API reference
A REST API over HTTPS with predictable, resource-oriented URLs and JSON request and response bodies. The base URL is https://apa.app/v1.
Conventions
Idempotency
Safely retry POST requests by sending an Idempotency-Key header (any unique string, e.g. a UUID). Apa stores the first response for 24 hours and replays it for repeats of the same key — so a dropped connection never creates two checkout sessions. Reusing a key with a different body returns 409 idempotency_conflict.
curl https://apa.app/v1/checkout/sessions \
-H "Authorization: Bearer sk_live_…" \
-H "Idempotency-Key: 5f3a1c9e-…" \
-H "Content-Type: application/json" \
-d '{"payout_wallet_id":"pp_123","amount":"100.00","currency":"USD"}'Pagination
List endpoints return a data array alongside a pagination object. Use limit (default 25, max 100) and pass the previous page's pagination.cursor as cursor to fetch the next page. pagination.has_more tells you when to stop.
GET /v1/payments?limit=25&cursor=cur_8fK2mQ
200 OK
{
"data": [ /* … */ ],
"pagination": { "cursor": "cur_9aF2k9", "has_more": true, "total": 42 }
}Rate limits
Live keys are limited to 100 requests/second. Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset. Exceeding the limit returns 429 — back off exponentially and retry.
Versioning
The API is versioned in the path (/v1). Additive changes (new fields, new endpoints) ship without a version bump; backwards-incompatible changes ship under a new version. Treat unknown fields as forwards-compatible and ignore them.
The Checkout Session object
The Payment Link object
The Payment object
Authentication
Send a one-time email code. Email accounts are best for stores and sellers that need multiple payout wallets.
POST /v1/auth/email/start
{ "email": "[email protected]" }
200 OK
{ "expires_in": 600, "sent": true }Exchange the email code for a dashboard session. Email-auth merchants can create and manage multiple payout wallets.
POST /v1/auth/email/verify
{ "email": "[email protected]", "code": "123456" }
200 OK
{ "session_token": "ses_…" }Get a nonce to sign with MetaMask/EVM or Phantom/Solana. Wallet login is scoped to the signed wallet.
POST /v1/auth/nonce
{ "address": "8dK3…p91A", "network": "solana" }
200 OK
{ "nonce": "Sign in to Apa\nWallet: 8dK3…p91A\nNetwork: solana\nNonce: 7f3a1c9e", "expires_in": 300 }Exchange a signed wallet nonce for a session. The connected wallet becomes the account's only payout wallet.
POST /v1/auth/verify
{ "address": "8dK3…p91A", "network": "solana", "signature": "base64-signature" }
200 OK
{ "session_token": "ses_…", "payout_wallet_id": "pp_123" }Payout wallets
Create a payout wallet — the asset, network and wallet you settle to.
POST /v1/payout-wallets
{ "asset": "USDC", "network": "solana", "address": "8dK3…p91A" }
201 Created
{
"data": {
"id": "pp_123",
"label": "USDC · solana",
"asset": "USDC",
"network": "solana",
"address": "8dK3…p91A",
"is_default": true
},
"request_id": "req_3aF2k9Lm"
}List your payout wallets.
GET /v1/payout-wallets
200 OK
{
"data": [ { "id": "pp_123", "asset": "USDC", "network": "solana" } ],
"pagination": { "cursor": null, "has_more": false, "total": 1 }
}Retrieve a single payout wallet.
GET /v1/payout-wallets/pp_123
200 OK
{
"data": {
"id": "pp_123",
"label": "USDC · solana",
"asset": "USDC",
"network": "solana",
"address": "8dK3…p91A",
"is_default": true
},
"request_id": "req_3aF2k9Lm"
}Checkout sessions
Create a single-order checkout session and get a hosted checkout URL.
POST /v1/checkout/sessions
{
"payout_wallet_id": "pp_123",
"amount": "100.00",
"currency": "USD",
"order_id": "ord_1042",
"description": "Order #9921",
"metadata": {
"product_id": "prod_123",
"cart_id": "cart_456",
"customer_id": "cus_789"
},
"accepted_assets": ["USDC_SOLANA", "SOL_SOLANA", "ETH_ETHEREUM"],
"expires_in": 1800,
"success_url": "https://store.example/thanks?order=9921"
}
201 Created
{
"data": {
"id": "cs_123",
"object": "checkout_session",
"status": "created",
"amount": "100.00",
"currency": "USD",
"payout_wallet_id": "pp_123",
"payment_link_id": null,
"order_id": "ord_1042",
"description": "Order #9921",
"metadata": { "product_id": "prod_123", "cart_id": "cart_456", "customer_id": "cus_789" },
"accepted_assets": ["USDC_SOLANA", "SOL_SOLANA", "ETH_ETHEREUM"],
"reference": "apa_3aF2k9Lm7Qp1",
"deposit_addresses": [
{
"asset": "USDC",
"network": "solana",
"address": "8dK3xQ2vT7mN4pR9wLcF5sZ1aB6hJ8uY0eP91A",
"kind": "direct",
"reference": "apa_3aF2k9Lm7Qp1"
},
{
"asset": "ETH",
"network": "ethereum",
"address": "0x9a2f4c1e8b7d6a5039f2c1b4e7a8d9c0f1e2b3a4",
"kind": "direct",
"reference": null
}
],
"checkout_url": "https://apa.app/checkout/cs_123",
"payment": null,
"success_url": "https://store.example/thanks?order=9921",
"cancel_url": null,
"created_at": "2026-06-27T10:00:00Z",
"expires_at": "2026-06-27T10:30:00Z"
},
"request_id": "req_3aF2k9Lm"
}Retrieve a session, including its current status and the resulting payment.
GET /v1/checkout/sessions/cs_123
200 OK
{
"data": {
"id": "cs_123",
"object": "checkout_session",
"status": "paid",
"amount": "100.00",
"currency": "USD",
"payout_wallet_id": "pp_123",
"payment_link_id": null,
"order_id": "ord_1042",
"description": "Order #9921",
"metadata": { "product_id": "prod_123", "cart_id": "cart_456", "customer_id": "cus_789" },
"checkout_url": "https://apa.app/checkout/cs_123",
"payment": "pay_8fK2mQ",
"created_at": "2026-06-27T10:00:00Z",
"expires_at": "2026-06-27T10:30:00Z"
},
"request_id": "req_8fK2mQ4h"
}Payment links
Create a reusable hosted payment link.
POST /v1/payment-links
{
"payout_wallet_id": "pp_123",
"amount": "25.00",
"currency": "USD",
"description": "Donation",
"order_id": "invoice-2048",
"metadata": { "customer_id": "cus_789" }
}
201 Created
{
"data": {
"id": "pl_123",
"object": "payment_link",
"status": "active",
"payout_wallet_id": "pp_123",
"receive_asset": "USDC",
"receive_network": "solana",
"description": "Donation",
"amount": "25.00",
"currency": "USD",
"order_id": "invoice-2048",
"metadata": { "customer_id": "cus_789" },
"url": "https://apa.app/pay/pl_123",
"payments": 0,
"success_url": null,
"cancel_url": null,
"created_at": "2026-06-27T10:00:00Z"
},
"request_id": "req_5xR9pL2b"
}List your payment links.
GET /v1/payment-links
200 OK
{
"data": [ { "id": "pl_123", "object": "payment_link", "status": "active", "amount": "25.00", "payments": 0 } ],
"pagination": { "cursor": null, "has_more": false, "total": 1 }
}Retrieve a payment link.
GET /v1/payment-links/pl_123
200 OK
{
"data": {
"id": "pl_123",
"object": "payment_link",
"status": "active",
"payout_wallet_id": "pp_123",
"receive_asset": "USDC",
"receive_network": "solana",
"description": "Donation",
"amount": "25.00",
"currency": "USD",
"order_id": "invoice-2048",
"metadata": { "customer_id": "cus_789" },
"url": "https://apa.app/pay/pl_123",
"payments": 0,
"success_url": null,
"cancel_url": null,
"created_at": "2026-06-27T10:00:00Z"
},
"request_id": "req_5xR9pL2b"
}Disable a payment link so it stops accepting new payments.
POST /v1/payment-links/pl_123/disable
200 OK
{
"data": { "id": "pl_123", "object": "payment_link", "status": "disabled" },
"request_id": "req_5xR9pL2b"
}Routes
Preview the route, expected output and fee for paying a given asset into a checkout session. The amount and payout asset come from the session.
GET /v1/routes/quote?session=cs_123&pay_asset=ETH&pay_network=ethereum
200 OK
{
"data": {
"id": "qt_8fK2mQ",
"provider": "chainflip",
"pay_asset": "ETH",
"pay_network": "ethereum",
"expected_output": "98.50 USDC",
"apa_fee": "1.50",
"expires_at": "2026-06-27T10:01:30Z",
"expires_in": 90
},
"request_id": "req_8fK2mQ4h"
}Payments
List payments, filterable by status, route and date.
GET /v1/payments?status=paid&limit=25
200 OK
{
"data": [ { "id": "pay_8fK2mQ", "status": "paid", "amount": "240.00" } ],
"pagination": { "cursor": null, "has_more": false, "total": 1 }
}Retrieve a payment with its route, outputs, fee and tx hashes.
GET /v1/payments/pay_8fK2mQ
200 OK
{
"data": {
"id": "pay_8fK2mQ",
"object": "payment",
"status": "paid",
"route": "routed",
"amount": "240.00",
"pay_asset": "ETH",
"pay_network": "ethereum",
"order_id": "ord_1042",
"metadata": { "customer_id": "cus_789" },
"payout_wallet_id": "pp_123",
"payment_link_id": null,
"receive_asset": "USDC",
"receive_network": "solana",
"receive_address": "8dK3…p91A",
"session": "cs_123",
"reference": "apa_3aF2k9Lm7Qp1",
"expected_output": "236.40 USDC",
"actual_output": "236.40 USDC",
"net_settlement": "236.40",
"apa_fee": "3.60",
"tx_hashes": ["0x9a2f…f70"],
"failure_reason": null,
"created_at": "2026-06-27T10:05:00Z"
},
"request_id": "req_9mC3tW4h"
}Record a refund you sent the customer. Apa is non-custodial: you send the crypto from your own wallet; this records it, transitions the payment to refunded, and emits payment.refunded. Optional amount (partial), address (override) and reason.
POST /v1/payments/pay_8fK2mQ/refund
{
"amount": "60.00",
"address": "8dK3…p91A",
"reason": "Order cancelled"
}
200 OK
{
"data": {
"id": "pay_8fK2mQ",
"object": "payment",
"status": "refunded",
"amount": "240.00"
},
"request_id": "req_9mC3tW4h"
}Webhooks
Register a URL to receive events. Returns a signing secret — store it to verify the Apa-Signature.
POST /v1/webhook-endpoints
{
"url": "https://store.example/api/apa/webhook",
"events": ["payment.paid", "payment.failed", "payment.refund_required"]
}
201 Created
{
"data": {
"id": "we_123",
"url": "https://store.example/api/apa/webhook",
"events": ["payment.paid", "payment.failed", "payment.refund_required"],
"secret": "whsec_9aF2k3Lm…",
"status": "active"
},
"request_id": "req_2bN7vK9m"
}List your registered endpoints and their delivery status.
GET /v1/webhook-endpoints
200 OK
{
"data": [ { "id": "we_123", "url": "https://store.example/api/apa/webhook", "status": "active" } ],
"pagination": { "cursor": null, "has_more": false, "total": 1 }
}Delete an endpoint. Events stop being delivered to it immediately.
DELETE /v1/webhook-endpoints/we_123
200 OK
{ "data": { "id": "we_123", "deleted": true }, "request_id": "req_4hG8rD7q" }Send a sample event to one of your endpoints to verify delivery.
POST /v1/webhooks/test
{ "endpoint_id": "we_123", "event": "payment.paid" }
200 OK
{ "data": { "delivered": true, "response_code": 200 }, "request_id": "req_7qP1zM5x" }