Documentation Index
Fetch the complete documentation index at: https://docs.minisend.xyz/llms.txt
Use this file to discover all available pages before exploring further.
A checkout session is a payment intent created from your backend. You get a hosted checkout URL, redirect the customer, and receive a webhook on settlement.
Use checkout sessions when you have a developer and want payments embedded in your existing app.
Flow
Backend creates the session
POST to /api/merchant/checkout with the USDC amount. Receive checkout_url + session_id.
Redirect the customer
Send them to checkout_url. The page shows your business name, the amount, and a deposit address.
Customer sends USDC or USDT
Any of 19 USDC chains or 14 USDT chains. Same address.
Minisend normalises and settles
USDC on non-Base → CCTP bridge. USDT → swap to USDC on Base (30–50s). Then conversion to local currency, then payout.
You receive the result
Webhook on completed, failed, or expired. Or poll the status endpoint at any time.
Create a session
POST https://merchant.minisend.xyz/api/merchant/checkout Auth: Authorization: Bearer ms_live_...
curl -X POST https://merchant.minisend.xyz/api/merchant/checkout \
-H "Authorization: Bearer ms_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"amount": 25.00,
"description": "Order #4821",
"external_id": "order-4821",
"customer_email": "customer@example.com"
}'
Request fields
| Field | Type | Required | Description |
|---|
amount | number | Yes | USDC amount (>0). Customer pays this as USDC or USDT-equivalent. |
description | string | No | Shown on the checkout page. |
external_id | string | No | Your reference (e.g., order ID). Echoed back in webhooks. |
customer_email | string | No | For receipt purposes. |
Response (201)
{
"session_id": "cs_7f8a9b2c-...",
"checkout_url": "https://merchant.minisend.xyz/checkout/cs_7f8a9b2c-...",
"deposit_address": "0x1234...5678",
"amount_usdc": 25.00,
"expires_at": "2026-04-13T14:30:00Z",
"status": "pending"
}
Sessions expire after 30 minutes. Create them at the moment of checkout, not earlier.
Using external_id
Pass your order ID as external_id when you create the session. Minisend echoes it back in every webhook so you can reconcile without maintaining a session-to-order mapping.
// Create
body: JSON.stringify({ amount: 49.99, external_id: 'order-8837' })
// Handle webhook
if (req.body.event === 'checkout.completed') {
markOrderPaid(req.body.external_id, {
receipt: req.body.receipt,
local_amount: req.body.amount_local,
});
}
Check session status
GET https://merchant.minisend.xyz/api/merchant/checkout/{session_id} — no auth.
curl https://merchant.minisend.xyz/api/merchant/checkout/cs_7f8a9b2c-...
{
"session_id": "cs_7f8a9b2c-...",
"status": "completed",
"amount_usdc": 25.00,
"description": "Order #4821",
"deposit_address": "0x1234...5678",
"expires_at": "2026-04-13T14:30:00Z",
"created_at": "2026-04-13T14:00:00Z",
"amount_local": 3225.00,
"exchange_rate": 129.00,
"settlement_receipt": "SHQ1234ABC",
"completed_at": "2026-04-13T14:08:22Z",
"merchant": {
"business_name": "My Store",
"logo_url": null
}
}
Status values
| Status | Meaning |
|---|
pending | Waiting for the customer to send |
deposit_received | Detected on-chain; settlement initiated |
settling | Conversion + payout in progress |
completed | Payout delivered |
failed | Failed post-deposit — contact support |
expired | No deposit within 30 minutes |
Full example
// 1. Create session
const res = await fetch('https://merchant.minisend.xyz/api/merchant/checkout', {
method: 'POST',
headers: {
'Authorization': 'Bearer ms_live_your_key_here',
'Content-Type': 'application/json',
},
body: JSON.stringify({
amount: 25.00,
description: 'Order #4821 – 2x T-shirts',
external_id: 'order-4821',
}),
});
const { checkout_url } = await res.json();
// 2. Redirect
res.redirect(checkout_url);
// 3. Handle webhook
app.post('/webhooks/minisend', (req, res) => {
const signature = req.headers['x-minisend-signature'];
if (!verifyWebhook(req.body, signature, WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
if (req.body.event === 'checkout.completed') {
markOrderPaid(req.body.external_id, {
receipt: req.body.receipt,
local_amount: req.body.amount_local,
currency: req.body.currency,
});
}
res.status(200).send('OK');
});
See Webhook verification for the signature check.