Skip to content

Create an invoice

POST/v1/invoices

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.

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.

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 ^[!-~]+$.
Field Type Description
price object A fiat-denominated invoice: the payer chooses an option and its amount is quoted then. USD only.
price.currency required string Always USD.
price.amount 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[].asset required string Asset symbol, e.g. USDT. At most 16 characters.
options[].network required string Network slug, e.g. bsc. At least 2 characters, at most 32 characters.
options[].amount 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.
Terminal window
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"
}'
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.currency string
price.amount string A decimal number written as a string, with up to 8 decimal places.
options array of objects
options[].id string
options[].network string
options[].asset string
options[].asset_id string
options[].contract optional string
options[].decimals integer
options[].amount_due 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[].display_decimals 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[].rate 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[].quote_expires_at optional string (date-time) Until when amount_due holds. Afterwards the payer takes a new quote; the invoice lives on.
options[].address optional string
options[].token_account optional string Solana tokens: the address’s associated token account, where the token is held.
options[].selected_at optional string (date-time)
options[].amount_paid string Sum of confirmed payments to this option. A whole number written as a string of digits.
options[].amount_detected 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.

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: