Optional analytics on public pages. No session recording. Support works either way. Privacy details
API reference
Create a payment request with a unique on-chain address.
/invoicesCreate a payment request with a unique on-chain address, quoted amount, and expiry.
| Field | In | Type | Required | Description |
|---|---|---|---|---|
| Idempotency-Key | header | string | No | Stable key per order attempt, max 255 characters. A retry with the same key and body returns the same invoice; a different body returns 409 idempotency_conflict. |
| BOSPay-Version | header | string | No | API version. Defaults to your organization's pinned version. Send it explicitly. |
| fiatAmount | body | number | Yes | Quoted fiat amount. 0.01–1,000,000,000. Respect the decimals returned by GET /currencies: whole numbers for JPY, two for ZAR, three for KWD. |
| fiatCurrency | body | string | No · ZAR | Supported ISO 4217 code from GET /currencies. Defaults to ZAR. Unsupported currencies return 400 before creating an invoice. |
| tokenSymbol | body | string | Yes | Accepted token for the selected chain: native asset, USDC, USDT, or DAI. |
| chain | body | string | No · ethereum | Network ID. Sandbox keys require sepolia. Live keys reject sepolia. Send this explicitly. |
| expiresAt | body | string | No | ISO 8601 timestamp. Defaults to 24 hours from creation. |
| merchantAddress | body | string | No | Optional. Must be one of your registered wallets for this network; any other address returns 400. Omit it to use the registered wallet for the asset. (In responses, read settlementRecipient for the payout wallet: merchantAddress there is a deprecated alias of paymentAddress.) |
| metadata | body | object | No | Up to 50 string key-value pairs (keys ≤40 chars, values ≤500). Returned on the invoice and in every event. Filter lists with metadata[key]=value. |
| description | body | string | No | Internal note, up to 1,000 characters. Not shown to the customer. |
const response = await fetch(`${process.env.BOSPAY_API_BASE}/invoices`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"BOSPay-Version": "2026-09-23",
"X-API-Key": process.env.BOSPAY_API_KEY,
"Idempotency-Key": "order-1048-attempt-1",
},
body: JSON.stringify({
"fiatAmount": 150,
"fiatCurrency": "ZAR",
"tokenSymbol": "USDC",
"chain": "sepolia",
"metadata": {
"orderId": "1048"
}
})
});
if (!response.ok) {
throw new Error(`BOSPay request failed: ${response.status}`);
}
const data = await response.json();Success
{
"id": "inv_1048",
"object": "invoice",
"invoiceId": "inv_1048",
"status": "pending",
"environment": "sandbox",
"livemode": false,
"fiatAmount": 150,
"fiatCurrency": "ZAR",
"cryptoAmount": "8.42",
"tokenSymbol": "USDC",
"chain": "sepolia",
"paymentAddress": "0xinvoicePaymentAddress",
"paymentLink": "https://checkout.bospay.co/checkout/inv_1048",
"metadata": {
"orderId": "1048"
},
"expiresAt": "2026-09-23T18:42:00.000Z",
"createdAt": "2026-09-23T10:42:00.000Z"
}Validation error
{
"error": {
"type": "invalid_request_error",
"code": "validation_error",
"message": "A valid fiatAmount is required.",
"field": "fiatAmount",
"requestId": "req_3f0c9a1b2c4d5e6f7a8b9c0d"
}
}Events: invoice.payment_detected, invoice.paid, invoice.expired. Event catalogue