Docs/API reference/API reference

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

Base URL
https://apa.app/v1
Auth
Bearer token — Authorization: Bearer sk_live_…
Content type
application/json
Errors
Conventional HTTP codes; a JSON body with error.code and error.message. See Errors.
Saved payout wallets only
Sessions and payment links settle to a saved payout_wallet_id. A request can't pass a raw wallet, so a leaked key can never redirect a payout.

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

idstring
Unique identifier, prefixed cs_.
objectstring
Always "checkout_session".
statusstring
Lifecycle status — see Payment statuses.
amountstring
Display amount, e.g. "100.00".
currencystring
USD, EUR or AED.
payout_wallet_idstring
Payout wallet the payment settles to.
payment_link_idstring | null
Payment link that created this session, if it came from a hosted link.
order_idstring | null
Your order reference, echoed in webhooks.
descriptionstring | null
Customer-facing description, if you sent one.
metadataobject
The key/value pairs you sent, echoed back ({} if none).
accepted_assetsarray
Assets this checkout accepts — your full Safe List or the custom subset you set.
referencestring
Unique on-chain reference for this session — attached as a memo / Solana-Pay reference where the chain supports it.
deposit_addressesarray
Direct payment targets for this session, each with asset, network, address, kind and optional reference. Routed payment targets are created on demand when a customer chooses that route.
checkout_urlstring
Hosted checkout URL to redirect the customer to.
paymentstring | null
Id of the resulting payment once one is created.
success_urlstring | null
Where the customer is sent after a successful payment, if you set one.
cancel_urlstring | null
Where the customer is sent if they abandon checkout, if you set one.
created_atstring
ISO-8601 timestamp when the session was created.
expires_atstring | null
ISO-8601 timestamp when the checkout expires; create a new session after this.

The Payment object

idstring
Unique identifier, prefixed pay_.
objectstring
Always "payment".
statusstring
Lifecycle status — see Payment statuses.
routestring
"direct" — paid as the exact payout asset on your payout network, 0% fee — or "routed" — asset/network conversion via a route provider, 1.5% fee.
amountstring
Display amount charged.
pay_assetstring
Asset the customer paid, e.g. ETH.
pay_networkstring
Network the customer paid on, e.g. ethereum.
order_idstring | null
Your order reference, echoed from the session or payment link.
metadataobject
The key/value pairs you set on the session or link, echoed back ({} if none).
payout_wallet_idstring
Payout wallet the funds settled to.
payment_link_idstring | null
Source payment link, if the payment came from a hosted link.
receive_assetstring
Asset delivered to the merchant payout wallet.
receive_networkstring
Network of the merchant payout wallet.
receive_addressstring
Merchant payout wallet address.
sessionstring | null
Id of the checkout session this payment came from, if any.
referencestring | null
Unique on-chain reference for the originating session — the memo / Solana-Pay reference that ties the transfer to this payment.
expected_outputstring | null
Estimated settled amount in the payout asset.
actual_outputstring | null
Final settled amount once confirmed.
net_settlementstring
Display-currency amount after Apa fee, for reconciliation.
apa_feestring
The Apa fee — "0.00" for direct, 1.5% of the amount for routed. No other Apa charges; customer wallet gas may still apply.
tx_hashesarray
Settlement transaction hashes ([] until settled).
failure_reasonstring | null
Reason for failed or refund-required states.
created_atstring
ISO-8601 timestamp when the payment was created.

Authentication

POST/v1/auth/email/start

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 }
POST/v1/auth/email/verify

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_…" }
POST/v1/auth/nonce

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 }
POST/v1/auth/verify

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

POST/v1/payout-wallets

Create a payout wallet — the asset, network and wallet you settle to.

assetstringrequired
Payout asset, e.g. USDC, ETH, SOL.
networkstringrequired
Settlement network, e.g. solana, base, ethereum.
addressstringrequired
The wallet that receives settled funds. Validated for the network.
labelstringoptional
A name shown in the dashboard.
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"
}
GET/v1/payout-wallets

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 }
}
GET/v1/payout-wallets/:id

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

POST/v1/checkout/sessions

Create a single-order checkout session and get a hosted checkout URL.

amountstringrequired
Amount in the display currency, e.g. "100.00".
currencystringoptional
Display currency: USD, EUR or AED. Defaults to USD.
payout_wallet_idstringoptional
The saved payout wallet to settle to. Omit to use your default payout wallet. A request can only reference a saved wallet, never a raw one.
order_idstringoptional
Your reference for the order; echoed back on the payment and in webhooks.
descriptionstringoptional
Shown to the customer at checkout, e.g. "Order #9921" → "Paying Example Store · Order #9921".
metadataobjectoptional
Up to 50 string key/value pairs, echoed on the session, the payment and every webhook. Use it to map back to your product_id, cart_id, customer_id, etc.
accepted_assetsarrayoptional
Restrict the assets this checkout accepts, e.g. ["USDC_SOLANA", "SOL_SOLANA", "ETH_ETHEREUM"] (ASSET_NETWORK). Omit to accept your full Safe List.
expires_inintegeroptional
Seconds until the checkout expires (minimum 60), e.g. 1800 — useful for carts and inventory holds.
success_urlstringoptional
Where to send the customer after a successful payment.
cancel_urlstringoptional
Where to send the customer if they abandon checkout.
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"
}
Mapping payments back to your system
metadata and order_id are echoed on the resulting payment and on every webhook, so you can map an on-chain payment back to your cart_id, customer_id or order without storing anything extra.
GET/v1/checkout/sessions/:id

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"
}

Routes

GET/v1/routes/quote

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

GET/v1/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 }
}
GET/v1/payments/:id

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"
}
POST/v1/payments/:id/refund

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.

amountstringoptional
Amount you refunded, e.g. "60.00". Omit to record a full refund.
addressstringoptional
Override the address the refund was sent to, if it differs from the customer's source wallet.
reasonstringoptional
Optional note, up to 280 characters, stored with the payment.
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

POST/v1/webhook-endpoints

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"
}
Save the secret
The secret is shown once. Use it to verify the Apa-Signature header on every delivery — see Webhooks.
GET/v1/webhook-endpoints

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/v1/webhook-endpoints/:id

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" }
POST/v1/webhooks/test

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" }