Checkout API reference
Base URLhttps://pay.apiosk.com. Currency is USDC only, 6 decimals. Every
response carries Cache-Control: no-store.
Authentication
Two endpoints take your marketplace secret key, as either header:apk_pub_ key cannot authenticate here.
There is no shared platform key.
“No key”, “unknown key”, “revoked key” and “that was a publishable key” all
return the same
401 unauthorized. Distinguishing them would tell someone
probing with a guessed key which half of the guess was right.POST /v1/checkout
Creates a checkout and returns the URL to redirect the buyer to.amount is validated, not rounded. Scientific notation, padding, negatives and
more than 6 decimals are all rejected rather than coerced, because silently
rounding somebody’s price is worse than refusing it.
There is deliberately no field for a wallet address, a fee, a marketplace name or
a logo. See /pay/overview for why.
201 response
GET /v1/payments/
The authoritative status, scoped to your own marketplace.The payer-facing endpoints
You do not normally call these. The hosted page does, and they are documented so the flow is auditable.GET /v1/session/{id} returns what the checkout page renders: amounts, the
product line, the marketplace’s name and logo, the three split lines, and the
chain and token to pay in. It never returns a recipient address of any kind.
A non-UUID answers 404, not 500.
POST /v1/payments/{id}/prepare takes { payer_address, permit_signature?, permit_deadline? } and returns opaque calldata for the splitter. With an
EIP-2612 permit signature there is one transaction; wallets that cannot sign a
permit get an approve step first, so two.
POST /v1/payments/{id}/pay takes { tx_hash } and records it. This is a
claim, not a proof. It is a compare-and-swap: of many concurrent submits exactly
one wins, and a hash already used to pay another checkout is rejected.
GET /v1/payments/{id}/status is the poll that actually settles. It reads
the on-chain receipt and only marks the payment paid if the transaction carries a
split event for this checkout plus a matching transfer for every expected
leg, each consumed once. An RPC failure leaves the payment pending and is retried,
it never invents a result.
POST /v1/payments/{id}/cancel returns { ok: true, status: "cancelled" },
or 409 not_cancellable once the payment has left pending or failed.
Related links
- Quickstart: /pay/quickstart
- Statuses and timing: /pay/lifecycle
- Webhooks: /pay/webhooks
- Payment links: /pay/payment-links