API Reference
Checkout SDK
The client-facing endpoints your checkout page calls directly. They are authenticated by a per-intent client_secret (cs_...) rather than your sk_ API key, so they are safe to call from an untrusted browser. Base URL https://api.zuuppa.com.
Every endpoint here is authenticated by the client_secret returned from POST /intents. A cs_ secret is scoped to a single intent: it can quote, select a token, read status, attach buyer details, and cancel — but only for that one intent. It cannot create intents, sweep funds, list your account, or touch any other intent. That is exactly why it is safe to ship to the browser.
Never send your sk_ key to the client.
The whole point of thecs_ secret is that your sk_ key stays on your server. Create the intent server-side with sk_, forward only client_secret (and address) to the browser, and drive the rest of checkout with the endpoints below.The buyer flow, in order#
A typical hosted or custom checkout calls these in sequence:
1. GET /intents/quote → show live prices in each accepted token
2. POST /intents/select-token → buyer picks an asset; locks amount + returns payment_uri
3. (optional) POST /intents/details → attach buyer name / email / shipping
4. GET /intents/status → poll until paid & settled (render the QR from payment_uri)A buyer who abandons can hit POST /intents/cancel to release the intent early. Every request below carries the intent's client_secret; a wrong or unknown one is a 401.
Endpoints#
Live per-token pricing for the intent: the USD price converted to each accepted asset at the current spot rate, plus how long the checkout window has left. Call it to render the token picker before the buyer selects.
Pass client_secret as a query parameter.
{
"price_usd_cents": 5000,
"expires_in_seconds": 540,
"quotes": [
{ "symbol": "SOL", "decimals": 9, "expected_lamports": 500000000 },
{ "symbol": "USDC", "decimals": 6, "expected_lamports": 50000000 }
]
}expected_lamportsis the amount in that asset's base units — divide by10^decimalsfor the UI figure.- Quotes are a live snapshot; re-fetch before selection if the picker has been open a while.
expires_in_secondscounts down the fixed 10-minute window.
Errors: 401 unknown/invalid client_secret; 409 if the intent is no longer quotable (already paid, expired, cancelled); 502 on a pricing/RPC failure.
The buyer commits to a pay-in asset. Locks mint, mint_decimals, and expected_lamports at the current rate and returns the payment_uri to render as the QR code. Required before any payment can be detected.
Request body#
cs_ secret.null for native SOL, or the SPL mint address. Must be one of the intent's accepted_tokens; anything else is a 400.{ "client_secret": "cs_7pKf...9dQ2", "mint": null }{
"derivation_index": 42,
"address": "9xQe...pump",
"mint": null,
"mint_decimals": 9,
"expected_lamports": 500000000,
"status": "pending",
"payment_uri": "solana:9xQe...pump?amount=0.5&label=Acme%20Store"
}Re-selectable while pending.
The buyer can change their mind: callingselect-token again while the intent is still pending re-locks the amount to the new asset and returns a fresh payment_uri. Once a payment lands the selection is frozen — a further call returns 409. Each successful selection emits an intent.token_selected webhook.Errors: 400 token not in accepted_tokens; 401 bad client_secret; 409 a payment already arrived (selection locked); 502 on a pricing/RPC failure.
The client-side status poll. Returns the same body as the server-side GET /status — the flattened intent plus action, message, payment_uri, shortfall_lamports, settlement, and any token_refunds — but authenticated by client_secretinstead of your API key.
Pass client_secret as a query parameter. Poll it to drive the checkout UI: re-render the QR from payment_uri, show message, and switch to a success state when action becomes swept (read exact figures from settlement). See GET /status for the full field reference and the settlement object.
{
"derivation_index": 42,
"address": "9xQe...pump",
"status": "underpaid",
"action": "underpaid",
"message": "Received 0.30 of 0.50 SOL. Send the rest to complete payment.",
"expected_lamports": 500000000,
"received_lamports": 300000000,
"shortfall_lamports": 200000000,
"payment_uri": "solana:9xQe...pump?amount=0.2&label=Acme%20Store"
}underpaid intent the payment_uri's amount is the remaining shortfall — render it directly so the buyer tops up the exact difference.Errors: 401 unknown/invalid client_secret.
Attach or update buyer details (name, email, shipping address) on the intent from the client — for order confirmation, receipts, or shipping. All fields optional except the secret.
Request body#
cs_ secret.400.line1, line2, city, state, postal_code, country (ISO 3166-1 alpha-2 — a bad code is a 400).{
"client_secret": "cs_7pKf...9dQ2",
"first_name": "Ada",
"email": "ada@example.com",
"address": { "line1": "1 Market St", "city": "SF", "country": "US" }
}Merged by key.
Fields you send overwrite their previous values; fields you omit are left untouched. To clear a value, send it explicitly asnull rather than omitting it. Returns 200 with the updated customer_details.Errors: 400 invalid email or country code; 401 bad client_secret; 409 if the intent is in a terminal state that no longer accepts detail edits.
Let the buyer cancel from the client — the untrusted-client counterpart of POST /cancel, authenticated by client_secret instead of your sk_ key. Same behavior: only acts while pending/underpaid, idempotent, and race-safe against a confirming payment.
Request body#
{ "client_secret": "cs_7pKf...9dQ2" }Response 200 OK with the intent's current status (same shape as GET /intents/status), now cancelled (or refunding/refunded if a partial SOL balance is being returned). A webhook fires exactly as with the server-side cancel — see POST /cancel.
Errors#
| Code | Message |
|---|---|
400 | Malformed request body. |
401 | unknown / invalid client_secret |
409 | payment already received; cannot cancel |
Related#
POST /intents— create the intent (server-side) and get theclient_secretthese endpoints use.GET /statusandPOST /cancel— the server-side (sk_) equivalents of status polling and cancellation.- Custom checkout guide — these endpoints wired into an end-to-end flow.