Skip to main content
A checkout session is one payment you ask for from your server. You get back a link to a payment page we host, send your customer there, and we tell your server with a webhook once you’ve been paid. Use it when you want payments inside your own app or website. If you just want a link to share, a payment link is simpler and needs no code.

How it works

1

Your server creates the session

Send a POST to /api/merchant/checkout with the amount in USDC. You get back a checkout_url and a session_id.
2

Send your customer to the payment page

Open checkout_url for them. The page shows your business name, the amount, and the address to pay to.
3

Your customer pays

In USDC or USDT, on any of six networks, to the same address either way. Or with M-Pesa.
4

We convert it and pay you

If the payment came in on another network, we move it to Base for you. USDT is converted to USDC first, which takes 30 to 50 seconds. Then we convert it to your currency and send your payout.
5

You hear back

We send a webhook when the payment is completed, failed, or expired. You can also check the status yourself at any time.

Pay with M-Pesa too

Every checkout session can offer M-Pesa, whatever currency you’re paid in. Your customer sees a Crypto / M-Pesa switch on the payment page and picks whichever is easier. That’s handy if you sell something like event tickets to a mixed crowd: people who hold crypto pay with it, and everyone else pays with M-Pesa. The M-Pesa option only appears when the amount is within M-Pesa’s limits, so a very small or very large amount hides it instead of offering a payment that would fail. When a customer picks it, they enter their phone number and approve the payment prompt that pops up on their phone. The money arrives as USDC in your wallet, just like a crypto payment, and is paid out the same way.

Create a session

Request fields

number
required
The amount in USDC, greater than 0. Your customer pays this in USDC, the same amount in USDT, or the KES equivalent with M-Pesa.
string
Shown on the payment page.
string
Your own reference, such as an order ID. We send it back to you in every webhook.
string
Used for the customer’s receipt.
string
fiat or usdc. Changes how this one payment is paid out, without touching your account setting. See Settlement mode.
string
BASE, ARB, AVAX, OP, ETH, or MATIC. Only used when settlement_mode is usdc.
string
Where to send your customer after they pay. A full https URL, up to 2048 characters. See Sending the customer back.

Response (201)

Sessions expire after 30 minutes. Create one when your customer is ready to pay, not before.

Sending the customer back to your site

Set redirect_url when you create the session and we’ll send your customer back to you once they’ve paid. Without it, they finish on our page. That’s fine for a link at a shop counter, but an online store usually wants to show its own confirmation page. Only sessions created through the API can do this. Payment links always finish on our page.

Where your customer lands

We add two parameters to your URL and leave everything else as it was: So https://yourstore.com/thanks?order=4821 becomes:
If your URL already has its own session_id or status, we keep yours and don’t add ours. Use different names if you want both.

When it happens

When the payment is completed, we send your customer back automatically a few seconds after the success screen appears. If they tap to see their receipt, we stay put, and a button to go back is always there. When it’s failed or expired, we show the link back but let your customer choose when to use it. They may want to try again or read what happened first. Because we only send customers back automatically when the payment is completed, which is also when we send you checkout.completed, the two always agree.
Treat status=completed in the URL as a hint, not proof. Anyone can type it into the address bar, so someone who never paid could still reach your thank-you page.Use it to show the page, but only hand over the goods after you get the webhook or check the status from your server.

Settlement mode

Each payment is paid out the way your account is set up in Settings, unless you change it for one session with settlement_mode:
  • fiat: we convert the payment to your local currency and send it to your account, as usual.
  • usdc: we skip the conversion and keep the payment in your wallet as USDC.
Once a session is created, its mode is fixed. Changing your account setting later won’t affect it. If you keep USDC, settlement_chain picks which network it ends up on. Base needs no extra step. For any other network, we move the money there automatically once the payment is confirmed. checkout.completed arrives before that move finishes, so wait for the checkout.forwarded webhook, or check the session’s forward field, before treating the money as arrived. If the move can’t be completed, we send settlement.forward_failed and your USDC stays safe on Base. Two more endpoints help here, and both work with the API key you already use for checkout:
  • GET /api/merchant/settlement shows your current mode, network, fee rate, and which networks you can switch to.
  • GET /api/merchant/balances shows your USDC balance on every network you’ve been paid on. A null balance means we couldn’t read it just now, not that it’s empty.

Using external_id

Pass your order ID as external_id when you create the session. We send it back in every webhook, so you can match each payment to your order without keeping your own list of session IDs.

Check session status

No API key needed.

Status values

Full example

See Webhook verification for the signature check.