Docs / Developer API
Coins paired with SAPLING
A coin can be planted paired with SAPLING instead of ZEC. It is a normal pump.fun coin whose quote is the $SAPLING pump.fun coin. Nobody holds $SAPLING because of a trade: every buy goes in as ZEC (or SOL, swapped to ZEC first) and every sale comes out as ZEC (or SOL, swapped after), through one PumpSwap instruction, multi_hop_swap, that crosses the $SAPLING/ZEC pool inside the trade. Amounts in requests and answers stay ZEC, SOL and coin base units, as for any coin.
The pins
| $SAPLING mint (Token-2022, 6 decimals) | BZFYNPeQAEW3HWQ4DNsTVahC1n4ZjTgn6jB2nnBbB96W |
| $SAPLING/ZEC pool (PumpSwap, canonical) | 6ejg4aYJM3Mk1t2zBKjbJ43df3s7rBMpC9mgo526K51G |
| its $SAPLING vault | 2JD5d35hkH9TXrssqNXFJczERMavMgP82WbzbeM3k2wW |
| its ZEC vault | DNzwnsYpT3hFTVALyzDGtsZqVdqBQ2bQ9btxVCRMw2Qz |
They are also in GET /v1/params, in pairs.sapling: the mint, its decimals and token program, the pool and its two vaults, the instruction, the route's protocol fee and the pool's LP fee. Read them there when your code runs.
Reads
A coin paired with SAPLING carries pair on every coin answer (GET /v1/coins, /v1/coins/search, /v1/coins/{mint}, /v1/graduations). No pair means the coin is paired with ZEC: a ZEC coin's answer has no new field.
"pair": { "key": "sapling", "symbol": "$SAPLING", "mint": "BZFYNPeQAEW3HWQ4DNsTVahC1n4ZjTgn6jB2nnBbB96W", "pool": "6ejg4aYJM3Mk1t2zBKjbJ43df3s7rBMpC9mgo526K51G" }GET /v1/coins/{mint} of a paired coin adds route: the route every trade of the coin takes. A buy runs the hops in order, a sale backwards. The coin's hop is its curve, or its canonical $SAPLING pool once it migrated. The addresses are derived from the mint.
"route": {
"instruction": "multi_hop_swap",
"program": "pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA",
"hops": [
{ "venue": "pool", "address": "6ejg4aYJM3Mk1t2zBKjbJ43df3s7rBMpC9mgo526K51G", "base": "BZFYNPeQAEW3HWQ4DNsTVahC1n4ZjTgn6jB2nnBbB96W", "quote": "A7bdiYdS5GjqGFtxf17ppRHtDKPkkRqbKtR27dxvQXaS" },
{ "venue": "curve", "address": "<the coin's bonding curve>", "base": "<mint>", "quote": "BZFYNPeQAEW3HWQ4DNsTVahC1n4ZjTgn6jB2nnBbB96W" }
]
}Units
- Every amount named
…Zecis ZEC: a paired coin's price, market cap, volume and creator fees are its $SAPLING amounts at the $SAPLING/ZEC pool's price. - Its
reserves(curve and pool) are the venues' raw reserves, so their quote side is $SAPLING base units (6 decimals). - Its
graduationraise (raiseAtCompletionZec,raisedSoFarZec) is the curve's $SAPLING at $SAPLING's price now. - Coins paired with hSOL stay out of v1, as before.
Trades and totals
A route moves two pools: the $SAPLING/ZEC pool, then the coin. It is one trade, and it is listed and counted once, as the paired coin's trade. Its zec is what the trader paid or received in all, from the same transaction; its creatorFeeZec is the coin's 2% at that rate.
GET /v1/tradesandGET /v1/coins/{mint}/trades?user=list the paired coin's trade only.GET /v1/coins/{mint}/tradesfor $SAPLING itself, withoutuser, also lists the $SAPLING/ZEC pool side of each route, marked"routed": true, so its list matches its chart. That row is never counted in a total.- Volumes, buy and sell counts, a wallet's volume and PnL, and
/v1/statsnever count the routed side. /v1/statsand/v1/stats/dailycount ZEC-paired coins only: a paired coin's creator fee arrives in $SAPLING and is split in kind.
Fees
A paired coin's 2.00% creator fee arrives in $SAPLING and is split in kind: the rootstock share (0.50% of each trade) is burned at once; the liquidity share (0.50%) goes to the LP pot's $SAPLING account and is added to the $SAPLING/ZEC pool with ZEC from the pot; the deployer's share (0.80%) and Sapling's (0.20%) are converted to ZEC on chain, never below the program's floor from its own record of the $SAPLING/ZEC price, and paid in ZEC. Holder rewards and payouts stay in ZEC.
GET /v1/coins/{mint}/fees of a paired coin keeps its fields in ZEC: what moved in $SAPLING at its ZEC value when it moved, and the deployer's share exactly as the conversions paid it. It adds sapling, the same fees as they moved, in $SAPLING base units:
"sapling": { "claimed": "…", "burned": "…", "toLp": "…", "converted": "…", "convertedZec": "…" }Every split, burn, conversion and draw is on /rings, with its signature.
Quotes
GET /v1/coins/{mint}/quote takes the same request. On a paired coin the answer is quoted on the route and adds:
pair:"sapling".route.costBps: everything the trader gives up against both venues' spot prices, fees and price impact together.route.feeBps: the fees alone. pump.fun's protocol fee once (0.05%), the creator fee (2.00%), and a graduated coin's LP fee (0.20%).route.saplingAmount: the $SAPLING passed between the two hops. The trader never holds it.priceImpactBps:costBpslessfeeBps.minTokensOut: on a buy, the fewest tokens accepted afterslippageBps.
A buy spends exactly amountIn ZEC (the route is exact in), so limit equals it. A sale's limit and minOutZec are the least ZEC out after slippage. Show the price impact to the trader before they confirm: there is no minimum pool depth.
Builds
POST /v1/plant/build
A new optional field, pair: "zec" (the default) or "sapling". With "sapling" the planting is still one transaction: create_v2 quoted in $SAPLING, the planting fee, the payee declaration, and with firstBuy one route from the wallet's ZEC into the new coin. The first buy spends exactly firstBuy.zec; its minimum is the quote on the new curve less firstBuy.slippageBps. expected carries tokensOut, minTokensOut, maxZecIn (equal to firstBuy.zec), priceImpactBps, costBps and feeBps.
400 invalid_paramfor any otherpair.422 too_largewhen the planting with its first buy does not fit one transaction: plant without the first buy, then buy.422 simulation_failedwhen pump.fun refuses, for instance when it has switched off new coins paired with another pump.fun coin. Coins already paired keep trading.
POST /v1/trade/build
No new field: the API reads the coin's pair from its curve on chain. A paired coin's buy or sale is one route.
- Buy in ZEC: the route from the wallet's ZEC account into its coin account (opened in the same transaction if needed), spending exactly
amount, for at least the quote lessslippageBps. - Buy in SOL: a Jupiter swap to ZEC, then the route spending exactly the ZEC the swap guarantees, in one transaction when it fits; otherwise the swap first and
thenthe buy in ZEC, as for any coin. - Sale: the route from the coin account into the wallet's ZEC account (opened if needed), for at least the quote less . closes the emptied coin account. is the sale, then a ZEC to SOL swap ().
What is accepted
The API checks every transaction before it answers, the relay checks it again before sending, and the SDK's verify() checks it on your machine. For a paired coin exactly this passes:
- The compute budget (one limit, one price, a bounded priority fee), the wallet's own coin or ZEC account opened idempotently, at most a close of its own emptied coin account after a full sale, and a Jupiter leg only where one was asked for.
- Exactly one
multi_hop_swap, account for account the route for this wallet and this coin: the wallet as user and signer, its own ZEC and coin accounts, pump.fun's fixed accounts, hop 1 the pinned $SAPLING/ZEC pool and its two vaults, hop 2 the coin's own curve (or canonical $SAPLING pool). Only the buyback fee account may vary, and it must be the ZEC account of one of pump.fun's buyback fee recipients. - The amounts: a buy spends exactly what was asked for at least the minimum; a sale sells exactly the tokens asked for at least the minimum.
Refused: any other pool or vault, another coin, another wallet's account, a direct curve or pool trade of a paired coin, a route for a coin paired with ZEC, a $SAPLING account, a transfer, any other program. A planting must be quoted in exactly the pair asked for.
Build the route yourself
Program pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA. Data: the discriminator [43, 100, 73, 19, 233, 246, 111, 148], then amount_in (u64, little endian), then min_amount_out (u64, little endian). Accounts:
0 user (signer, writable)
1 user's input account (buy: ZEC ATA; sale: coin ATA, Token-2022)
2 user's output account (buy: coin ATA; sale: ZEC ATA)
3 PumpSwap global config ["global_config"]
4 PumpSwap fee config (pump fees program, ["fee_config", PumpSwap])
5 user volume accumulator ["user_volume_accumulator", user] (PumpSwap)
6 ZEC ATA of a pump.fun buyback fee recipient (Global.buyback_fee_recipients)
7..9 SPL Token, Token-2022, System
10, 11 PumpSwap event authority, PumpSwap
12..15 pump.fun, its Global, its fee config, its event authority
16..20 hop 1: base mint, quote mint, venue, venue's base account, venue's quote account
21..25 hop 2: the sameA buy's hops are [$SAPLING, ZEC, the $SAPLING/ZEC pool, its two vaults] then [the coin, $SAPLING, the coin's curve or pool, its coin account, its $SAPLING account]. A sale's are the same two in reverse order. A venue's accounts are the venue's own associated token accounts (it is off the curve). @sapling/core builds it as routeBuyInstruction and routeSellInstruction; the SDK's verify() holds a route you built to the same rules.
SDK
SDK 0.4.0 adds the types: Coin.pair, CoinDetail.route, Holding.pair, Quote.pair, Quote.minTokensOut, Quote.route, Params.pairs, PlantBuildRequest.pair, Build.expected.costBps and feeBps, Trade.routed and CoinFees.sapling; and plant({ pair: "sapling" }). Its pinned set gains saplingMint and saplingPool. verify() recognises a paired coin from its curve on chain and accepts exactly its route (trade tags routeBuy and routeSell), quoting both venues itself; a $SAPLING planting only when the request asked for pair: "sapling". Nothing changes for ZEC coins.