3. API Reference
The complete HTTP contract. All request/response bodies are JSON.
- Base URL:
https://api-processing.zuuppa.com(use your assigned base URL if different). - Authentication: every payments endpoint requires an API key — send
Authorization: Bearer sk_live_...(orsk_test_...). Create the key in the dashboard (API keys). Requests without a valid key get401. Keep the key server-side.GET /healthis open.
Conventions
- Amounts are integers in the asset's base units (lamports for SOL, token base units for a mint). See Concepts.
index=derivation_index, the integer identifying a payment intent.- Errors return a non-2xx status and a body of the form:
{ "error": "human-readable message" }
Error status codes
| Code | Meaning |
|---|---|
400 Bad Request | Invalid input (bad mint, non-positive amount, nothing to sweep). |
401 Unauthorized | Missing or invalid API key. |
404 Not Found | No intent for the given index/reference. |
500 Internal Server Error | Internal error. |
502 Bad Gateway | Upstream Solana RPC error. |
POST /intents
Auth: requires Authorization: Bearer sk_....
Create a payment intent. Derives a unique deposit address and returns it.
Request body (all fields optional):
| Field | Type | Default | Description |
|---|---|---|---|
expected_lamports | integer | null | Expected amount in base units. null = accept any amount ("open-ended"). Must be > 0 if provided. |
mint | string | null | SPL mint address to accept. Omit for native SOL. Must be a valid mint. |
reference | string | null | Your opaque id (order id, user id). Stored and returned; never interpreted. |
expires_in_secs | integer | null | Seconds until the payment window closes. null = never expires. |
Examples
Fixed-amount SOL invoice, 15-minute window:
{ "expected_lamports": 500000000, "reference": "order-1001", "expires_in_secs": 900 }
Accept 100 USDC (6-decimal mint):
{ "expected_lamports": 100000000, "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "reference": "order-1002" }
Open-ended donation address in SOL (any amount):
{ "reference": "donation-jar" }
Response 200 OK — the created intent (see the object reference):
{
"id": "d0714125-193a-4706-91d1-80854d829214",
"derivation_index": 42,
"address": "9xQe...pump",
"mint": null,
"mint_decimals": null,
"expected_lamports": 500000000,
"status": "pending",
"received_lamports": 0,
"reference": "order-1001",
"expires_at": "2026-07-26T13:15:00Z",
"created_at": "2026-07-26T13:00:00Z",
"updated_at": "2026-07-26T13:00:00Z",
"refund_sender": null
}
Save derivation_index — you'll poll status with it. Show address to the payer.
Errors
400expected_lamports must be > 0400invalid mint address/invalid mint: ...(mint not found on-chain)
Idempotency (recommended)
If you pass a reference, POST /intents is idempotent on it: retrying
the same reference (network retry, crash, double-tap) returns the same intent
(same derivation_index and address) instead of creating a second deposit
address. Always pass a stable unique reference (e.g. your order id).
GET /intents?reference={reference}
Auth: requires Authorization: Bearer sk_....
Recover an intent by its reference — e.g. if the POST /intents response was
lost, look it up instead of creating a new one.
Response 200 OK — the same PaymentIntent object as POST /intents.
Errors — 404 no intent for that reference.
curl -H 'Authorization: Bearer sk_live_...' \
"https://api-processing.zuuppa.com/intents?reference=order-1001"
GET /status?index={index}
Auth: requires Authorization: Bearer sk_....
The endpoint your app polls. Returns the intent's full state plus a human-readable message, the exact settled amounts (once swept), and any wrong-token refunds.
Query params
index(required) — thederivation_indexfromPOST /intents.
Response 200 OK:
{
"id": "d0714125-...",
"derivation_index": 42,
"address": "9xQe...pump",
"mint": null,
"mint_decimals": null,
"expected_lamports": 500000000,
"status": "swept",
"received_lamports": 500000000,
"reference": "order-1001",
"expires_at": "2026-07-26T13:15:00Z",
"created_at": "2026-07-26T13:00:00Z",
"updated_at": "2026-07-26T13:02:11Z",
"refund_sender": "Fx3X...gsy",
"action": "swept",
"message": "Payment received and settled.",
"settlement": {
"asset": "SOL", "decimals": 9,
"destination_amount": 499995000, "destination_ui": 0.499995,
"platform_fee_amount": 0, "platform_fee_ui": 0.0,
"signatures": ["4bd..."]
}
}
Response fields — the flattened PaymentIntent (see below) plus:
| Field | Type | Present | Description |
|---|---|---|---|
action | string | always | Machine-friendly state: waiting, underpaid, paid, overpaid, swept, refunding, refunded, expired, refund_failed. |
message | string | always | Human-readable status message, safe to show a payer. |
shortfall_lamports | integer | only when underpaid | How many more base units are needed to complete the payment. |
token_refunds | array | only if non-empty | Wrong-token refunds for this address: `[{ "mint": "...", "status": "pending |
settlement | object | only after first sweep | Exact settled amounts. See below. |
settlement object (source of truth for accounting):
| Field | Type | Description |
|---|---|---|
asset | string | "SOL" or the SPL mint address. |
decimals | integer | 9 for SOL, else mint decimals. |
destination_amount | integer | Base units delivered to your destination wallet (net of platform fee / refunded excess). |
destination_ui | number | destination_amount ÷ 10^decimals, for display. |
platform_fee_amount | integer | Base units sent to the platform wallet (0 if fees off). |
platform_fee_ui | number | Decimal-adjusted platform fee. |
signatures | string[] | On-chain sweep transaction signature(s). |
Errors
404no intent for that index
POST /sweep
Auth: requires Authorization: Bearer sk_....
Manually trigger a sweep of an intent's balance to your destination. Usually unnecessary — settlement is automatic. Use it only to force a retry.
⚠️ This moves funds. Treat it as a privileged backend-only operation.
Request body
{ "index": 42 }
Response 200 OK:
{
"signature": "4bd...",
"lamports_swept": 499995000,
"platform_fee_lamports": 0,
"from": "9xQe...pump",
"to": "BLTpUS6b..."
}
Errors
400nothing to sweep (balance ...)404no intent for that index502on RPC failure.
GET /health
Liveness probe. Returns 200 OK with body ok. No auth, no JSON.
PaymentIntent object
The core object returned by /intents and flattened into /status. Fields:
| Field | Type | Description |
|---|---|---|
id | string (UUID) | Internal unique id. |
derivation_index | integer | The index / stable id. Poll with this. |
address | string | Deposit address to show the payer. |
mint | string | null | Accepted asset: null = SOL, else SPL mint. |
mint_decimals | integer | null | Token decimals (null for SOL). |
expected_lamports | integer | null | Expected amount, base units. null = any. |
received_lamports | integer | Amount received so far, base units (gross). |
status | string | Lifecycle state (see Concepts). |
reference | string | null | Your opaque id. |
expires_at | string (ISO 8601) | null | Payment window close time. |
created_at | string (ISO 8601) | Creation time. |
updated_at | string (ISO 8601) | Last state change. |
refund_sender | string | null | Address we will/did refund to (the payer's address, once known). |
Next: Integration guide →