Flow
1
Backend creates the session
POST to /api/merchant/checkout with the USDC amount. Receive checkout_url + session_id.2
Redirect the customer
Send them to
checkout_url. The page shows your business name, the amount, and a deposit address.3
Customer sends USDC or USDT
Any of six chains, USDC or USDT. Same address either way.
4
Minisend normalises and settles
USDC on another chain bridges to Base via CCTP. USDT swaps to USDC on Base first, taking 30 to 50 seconds. From there it converts to local currency and pays out.
5
You receive the result
Webhook on
completed, failed, or expired. Or poll the status endpoint at any time.Customers can pay with M-Pesa instead of crypto. The checkout page offers both, side by side.
Pay with M-Pesa too
Every checkout session can offer this, not just accounts that settle in KES. The customer sees a Crypto / M-Pesa switcher on the hosted checkout page and picks whichever is easier for them, which is worth leading with if you’re selling something like event tickets to a mixed audience: crypto-native buyers pay in USDC or USDT, everyone else pays with a number they already know. The M-Pesa tab only shows when the session’s KES-equivalent amount falls inside Pretium’s range, so a very small or very large amount hides it rather than offering a payment that would fail. If it’s shown and the customer picks it, they enter their phone number, confirm an STK push, and the KES lands as USDC in your wallet, exactly like a crypto deposit would. It settles the same way no matter your account’s payout currency or settlement mode.Create a session
POST https://merchant.minisend.xyz/api/merchant/checkout Auth: Authorization: Bearer ms_live_...
Request fields
Response (201)
Settlement mode
Every session settles the way your account is set up in Settings, unless you override it withsettlement_mode. Fiat converts to your payout currency and pays out as usual. USDC skips that and leaves the deposit in your wallet.
Once a session is created, its mode is locked in. Changing your account default later won’t touch it.
If you’re settling in USDC, settlement_chain picks where the payment lands. Base needs no bridging. Anything else forwards there automatically once the deposit confirms, and checkout.completed fires before that forward finishes, so check the session’s forward field (or listen for checkout.forwarded) before treating the money as landed on its destination chain. A failed forward stays quiet rather than sending a webhook, so poll forward.status if you need certainty.
Two more endpoints round this out. GET /api/merchant/settlement returns your current mode, chain, fee rate, and which chains you can switch to. GET /api/merchant/balances returns your USDC balance on every chain you’ve received on, with null meaning a chain’s balance couldn’t be read right now, not that it’s empty. Both use the same API key and checkout scope you already have.
Using external_id
Pass your order ID asexternal_id when you create the session. Minisend echoes it back in every webhook so you can reconcile without maintaining a session-to-order mapping.
Check session status
GET https://merchant.minisend.xyz/api/merchant/checkout/{session_id} — no auth.

