Create an invoice
With price the invoice is fiat-denominated (USD): the payer picks an option on the checkout page and its amount is quoted at that moment. Without price it is crypto-denominated: each option carries its fixed amount. Send the payer to checkout_url.
Authorization
Section titled “Authorization”Send your API key as a bearer token in the Authorization header. Secret API key: Authorization: Bearer ctp_live_sk_…. A publishable key (ctp_…_pk_…) is accepted by these operations only, which serve reference data: getRate, listAssets, listNetworks (each marked x-publishable-key: true). Every other operation refuses it with 403 publishable_key_not_allowed, whatever Origin the request carries: that header binds browsers, not other clients, and nothing on this API relies on it.
Headers
Section titled “Headers”| Name | Type | Description |
|---|---|---|
Idempotency-Key |
string | Makes the request safe to retry: the same key with the same request replays the first response (Idempotent-Replayed: true) for 24 hours; the same key with a different request is 422 idempotency_key_reused; while the first request is still running, 409 idempotency_request_in_progress with Retry-After. Only POST honours it. At most 255 characters. Pattern ^[!-~]+$. |
Request body
Section titled “Request body”| Field | Type | Description |
|---|---|---|
price |
object | A fiat-denominated invoice: the payer chooses an option and its amount is quoted then. USD only. |
price. required |
string | Always USD. |
price. required |
string | Decimal string with up to 8 decimals, e.g. "49.99". A decimal number written as a string, with up to 8 decimal places. |
options |
array of objects | The ways the payer may pay. With price, default: every asset enabled in this environment. Without price (crypto-denominated) it is required and each option carries its amount. At least 1 item, at most 64 items. |
options[]. required |
string | Asset symbol, e.g. USDT. At most 16 characters. |
options[]. required |
string | Network slug, e.g. bsc. At least 2 characters, at most 32 characters. |
options[]. |
string | Crypto-denominated invoices only: the fixed amount due, in base units of the asset. A whole number written as a string of digits. |
order_id |
string | Your reference; not unique-checked. At most 128 characters. |
customer_email |
string | The email address of your customer, for your own records: returned on the invoice and in its events, never shown on the checkout page and never written to. Kept as given, apart from surrounding spaces. At least 3 characters, at most 320 characters. |
description |
string | At most 1024 characters. |
metadata |
map of string to string | Up to 20 keys of your own data, returned as given. |
success_url |
string | Where the checkout sends the payer after paying. At most 2048 characters. |
cancel_url |
string | At most 2048 characters. |
tolerance_bps |
integer | Underpayment tolerance in basis points. Default: the merchant setting. Minimum 0, maximum 200. |
expires_in |
integer | Seconds the payer has to choose an option (fiat) or to pay (crypto). Default: the merchant setting. Minimum 300, maximum 2592000. |
Example request
Section titled “Example request”curl -X POST "https://api.ctpeway.com/v1/invoices" \ -H "Authorization: Bearer $CTPEWAY_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: <a-unique-key>" \ -d '{ "price": { "currency": "USD", "amount": "49.99" }, "options": [ { "asset": "USDT", "network": "bsc" }, { "asset": "BNB", "network": "bsc" } ], "order_id": "order-1042", "customer_email": "customer@example.com", "description": "Order 1042", "success_url": "https://shop.example/orders/1042/thanks", "cancel_url": "https://shop.example/cart"}'import { CtpeWay } from '@ctpeway/sdk';
const ctpeway = new CtpeWay(process.env.CTPEWAY_API_KEY);
const result = await ctpeway.invoices.create({ price: { currency: 'USD', amount: '49.99', }, options: [ { asset: 'USDT', network: 'bsc', }, { asset: 'BNB', network: 'bsc', }, ], order_id: 'order-1042', customer_email: 'customer@example.com', description: 'Order 1042', success_url: 'https://shop.example/orders/1042/thanks', cancel_url: 'https://shop.example/cart',});Response
Section titled “Response”201 Created
Section titled “201 Created”| Field | Type | Description |
|---|---|---|
id |
string | |
number |
integer | |
status |
string | One of open, pending, underpaid, paid, expired, canceled, refunded. |
outcome_flags |
array of strings | Values: overpaid, late, underpaid_accepted, partially_refunded. |
kind |
string | One of fiat, crypto. |
price optional |
object | |
price. |
string | |
price. |
string | A decimal number written as a string, with up to 8 decimal places. |
options |
array of objects | |
options[]. |
string | |
options[]. |
string | |
options[]. |
string | |
options[]. |
string | |
options[]. optional |
string | |
options[]. |
integer | |
options[]. optional |
string | Set once the option is selected (fiat invoices). A quoted amount is rounded up to display_decimals, so the amount shown to the payer is exactly the amount that pays the invoice. A whole number written as a string of digits. |
options[]. optional |
integer | Present with amount_due: the decimals it is stated with. amount_due is a whole number of 10^(decimals − display_decimals) base units; equal to decimals when the amount is exact to the base unit (crypto invoices). |
options[]. optional |
string | Price of one unit of the asset in the invoice currency at lock time. A decimal number written as a string, with up to 8 decimal places. |
options[]. optional |
string (date-time) | Until when amount_due holds. Afterwards the payer takes a new quote; the invoice lives on. |
options[]. optional |
string | |
options[]. optional |
string | Solana tokens: the address’s associated token account, where the token is held. |
options[]. optional |
string (date-time) | |
options[]. |
string | Sum of confirmed payments to this option. A whole number written as a string of digits. |
options[]. |
string | Sum of detected, unconfirmed payments to this option. A whole number written as a string of digits. |
selected_option_id optional |
string | |
paid_option_id optional |
string | |
tolerance_bps |
integer | |
order_id optional |
string | |
customer_email optional |
string | The customer the merchant named when creating the invoice. |
description optional |
string | |
metadata optional |
map of string to string | |
expires_at |
string (date-time) | |
pre_selection_expires_at |
string (date-time) | |
created_at |
string (date-time) | |
paid_at optional |
string (date-time) | |
expired_at optional |
string (date-time) | |
canceled_at optional |
string (date-time) | |
refunded_at optional |
string (date-time) | When the invoice became refunded. |
livemode |
boolean | false for objects of the test environment. |
checkout_url |
string | The hosted checkout page of this invoice. Send the payer here. |
{ "id": "string", "number": 0, "status": "open", "outcome_flags": [ "overpaid" ], "kind": "fiat", "price": { "currency": "string", "amount": "10.00" }, "options": [ { "id": "string", "network": "string", "asset": "string", "asset_id": "string", "contract": "string", "decimals": 0, "amount_due": "1000000", "display_decimals": 0, "rate": "10.00", "quote_expires_at": "2026-01-01T00:00:00.000Z", "address": "string", "token_account": "string", "selected_at": "2026-01-01T00:00:00.000Z", "amount_paid": "1000000", "amount_detected": "1000000" } ], "selected_option_id": "string", "paid_option_id": "string", "tolerance_bps": 0, "order_id": "string", "customer_email": "string", "description": "string", "metadata": {}, "expires_at": "2026-01-01T00:00:00.000Z", "pre_selection_expires_at": "2026-01-01T00:00:00.000Z", "created_at": "2026-01-01T00:00:00.000Z", "paid_at": "2026-01-01T00:00:00.000Z", "expired_at": "2026-01-01T00:00:00.000Z", "canceled_at": "2026-01-01T00:00:00.000Z", "refunded_at": "2026-01-01T00:00:00.000Z", "livemode": true, "checkout_url": "string"}The values are placeholders generated from the schema. They show the shape, not real data.
Errors
Section titled “Errors”A failed request answers with the error format described under Errors.
Besides the codes any endpoint can return, this endpoint can answer with these code values:

