API quickstart
The send21 API has two building blocks. A payment request asks to get paid: the payer opens a link, picks a currency and pays from any wallet. A payment draft prepares a payment to someone else, which the sender signs in their own wallet. Base URL: https://send21.io/api/v1.
1. Create an API key
Sign in and open API keys. Pick only the scopes you need. Keys look like s21_... and are shown once. No key can move funds, because send21 never holds any.
| Scope | Allows |
|---|---|
drafts:read | Read drafts, payment requests, templates, status and rates |
drafts:write | Create, cancel and re-quote drafts and payment requests |
addressbook:read | Read saved addresses |
addressbook:write | Change saved addresses |
webhooks:manage | Register and delete webhook endpoints |
2. Ask to get paid: a payment request
Price it in any of 165 fiat currencies and list the currencies you accept, each with your own receiving address. The response contains payPath; share https://send21.io plus that path as a link or QR code. The rate locks when the payer picks a currency.
curl -X POST https://send21.io/api/v1/payment-requests \
-H "Authorization: Bearer s21_YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-1042" \
-d '{
"fiatCurrency": "EUR",
"fiatAmount": 49.00,
"orderId": "ORDER-1042",
"memo": "Invoice 1042",
"options": [
{ "currency": "Eurc", "network": "Base", "address": "0xYourAddress" },
{ "currency": "Usdc", "network": "Solana", "address": "YourSolanaAddress" },
{ "currency": "Btc", "network": "Mainnet", "address": "[email protected]", "method": "Lightning" }
]
}'3. Prepare a payment: a draft
A draft pays a receiver. With singleOutput: true it is one QR payment from any wallet, and the send21 fee is billed to your account. Without it, the fee is a separate output and the template suits PSBT and batching wallets. Fetch wallet-ready instructions from GET /drafts/{id}/tx-template.
curl -X POST https://send21.io/api/v1/drafts \
-H "Authorization: Bearer s21_YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: payout-77" \
-d '{
"receiverAddress": "0xReceiverAddress",
"network": "Arbitrum",
"currency": "Usdc",
"paymentMethod": "MultiOutput",
"singleOutput": true,
"fiatCurrency": "SEK",
"fiatAmount": 1500
}'4. Track the payment
- Poll
GET /drafts/{id}/statusforAwaitingPayment,Seen,Confirmed,ExpiredorCancelled. - Better: register a webhook and react to
draft.confirmed. - A transfer within 10% of the billed amount is flagged as
draft.amount_mismatchand can be accepted withPOST /drafts/{id}/accept-received.
Good to know
- Send an
Idempotency-Keyheader on create calls. A retry with the same key returns the original object. - Batch creation:
POST /drafts/batchtakes up to 25 drafts. - Rate limit: 300 requests per minute per key. A 429 means back off; prefer webhooks over tight polling.
- A 402 on a create call means accrued fees must be settled first; the body names
POST /fees/accrued/settle. - Full reference: /swagger and /openapi.json.
Related
This page is also available as Markdown: /docs/quickstart.md. Questions: [email protected].