Docs / Developer API
Transactions
Every transaction follows the same four steps: build (the API answers it unsigned), verify (you check it against your own request), sign (your user's wallet), send (your RPC, or the relay).
What a build answers
transactions: in order, each a v0 transaction in base64 with a recent blockhash and empty signature slots, who must sign it (signers, in slot order), the lookup tables it names (addresses only: read them from chain), its last valid block height and its size.simulation: every build is simulated before it is answered;solCostLamportsis what the wallet pays in SOL.expected: tokens or ZEC out, and the bound your slippage sets (minTokensOut,minZecOut,maxZecIn).intent: your request as the API read it. Verify against your own request, not this.expiresAt: about when the blockhash expires. Build again after it.
Plant
A planting is one transaction: it creates the coin on pump.fun, paired to ZEC; pays the launch fee to the treasury; makes the first buy if you ask for one; and declares where the deployer's 40% goes. It lands whole or not at all.
- Make the coin's mint key on your side (
Keypair.generate()). Only its public key is ever sent. POST /v1/plant/upload(multipart): name, symbol, description, links, image, the planter's wallet (payer), the mint's public key, andholders(1 when the share will pay holder rewards). The same rules as sapling.cash: name up to 32 bytes, ticker 2 to 10 of A–Z and 0–9, PNG, JPEG, WebP or GIF under 4 MB. It answers the metadata'suri.POST /v1/plant/buildwith the wallet, the mint, the same name, symbol and uri, the payee (me,wallet:<address>orholders), and an optionalfirstBuyin ZEC base units.- Verify, sign (wallet first, then the mint key), send.
- Poll
GET /v1/tx/{signature}untilregisteredis true; the coin is then atGET /v1/coins/{mint}and on sapling.cash.
POST https://api.sapling.cash/v1/plant/build
{
"wallet": "<wallet>",
"mint": "<mint>",
"name": "Night Owl",
"symbol": "OWL",
"uri": "ipfs://<cid>",
"payee": "holders",
"firstBuy": { "zec": "50000000", "slippageBps": 100 }
}Signing order
With a browser wallet the wallet signs first, then the mint key. Some wallets add a compute-budget instruction or a Lighthouse assertion of their own when they sign; check that the transaction they hand back changed in nothing else before the mint key signs it (the SDK does). With a bot's own keypair, both sign at once.
A first buy in SOL
Two transactions, two approvals, as on sapling.cash. First POST /v1/swap/build from SOL to ZEC. Once that swap is final, build the planting with firstBuy.zec set to the swap's minZecOut. If your user stops between the two, they keep the ZEC.
Buy and sell
POST https://api.sapling.cash/v1/trade/build
{ "wallet": "<wallet>", "mint": "<mint>", "side": "buy", "pay": "ZEC", "amount": "25000000", "slippageBps": 100 }
POST https://api.sapling.cash/v1/trade/build
{ "wallet": "<wallet>", "mint": "<mint>", "side": "sell", "amount": "all", "receive": "ZEC", "slippageBps": 100 }- The venue (curve or pool) is read from chain when the trade is built. Slippage is 100 bps on the curve and 200 on the pool by default, at most 2000.
pay: "SOL": the SOL is swapped to ZEC through Jupiter in the same transaction when it fits. When it does not, the answer has the swap only, andthensays what to call once it lands (the same build withpay: "ZEC"and the swap'sminZecOut).amount: "all"sells the whole balance and closes the emptied token account, which returns its rent to the wallet.receive: "SOL"adds a second transaction, a swap of the ZEC received, its minimum checked.
Swap
POST /v1/swap/build swaps SOL to ZEC or ZEC to SOL through Jupiter. The route is simulated and refused when it would cost more than the amount swapped plus a small margin, so a wallet is never asked for a swap that overpays.
Claim a payee's share
A coin's deployer share waits in its fee account until it is paid out. POST /v1/claim/build pays it, and it always pays the payee recorded on chain, whoever sends it: any wallet can send it for any coin, and the sender gets nothing from it. Sapling sends these itself whenever the payee has a ZEC account.
Holder rewards are different: Sapling pays them to holders on every run. There is nothing for a holder to claim or build.
Change the payee
POST https://api.sapling.cash/v1/payee/build
{ "wallet": "<current payee>", "mint": "<mint>", "payee": "wallet:<new payee>" }- Only the current payee can sign it. Nobody else can change a payee: not the planter after a handover, not Sapling.
- What waits in the fee account is paid to the current payee first, in the same transaction.
- Moving the share to another wallet hands it over: the new wallet controls it from then on.
"payee": "holders"turns the share into holder rewards. That is permanent: nobody can change it afterwards, the payee included. The answer sayspermanent: true, and the SDK builds it only withconfirmPermanent: true.
Send
Send the signed transactions through your own RPC, in order, each after the one before has landed. Or use the relay:
POST https://api.sapling.cash/v1/tx/send
{ "buildId": "b_<id>", "signed": ["<signed transaction, base64>"] }- The relay sends only what it built. Each transaction must be the build's byte for byte, apart from what a wallet may add (a compute budget, Lighthouse assertions). It runs the same check again with every signature verified, then sends and confirms. A transaction someone changed never leaves through it.
- A build is sent once. Its blockhash expires within about a minute and a half; after that, build again.
- For a planting, the relay tells Sapling's index at once, so the coin is listed sooner.
GET /v1/tx/{signature}says when it is registered.
When a build is refused
A build whose simulation fails is not answered: you get 422 refused with the reason in plain words, for example “Not enough SOL: you need about 0.034 SOL for the planting fee, rent and network fees.” Show the message to your user as it is. The other codes are on keys and limits.