The Invoices API allows you to create and manage cryptocurrency payment invoices for your customers. Each invoice generates a unique payment page where customers can select their preferred cryptocurrency and complete the payment. Invoices are ideal for e-commerce checkout flows and single-payment scenarios.
Overview
Section titled “Overview”An invoice is a payment request with a specific amount that customers can pay using various cryptocurrencies. When an invoice is created, customers receive a payment URL where they can choose their preferred cryptocurrency and complete the payment.
Invoice Lifecycle
Section titled “Invoice Lifecycle”Create Invoice
Generate a new invoice with a specified amount using the POST /v1/invoices endpoint.
Customer Payment
Customer visits the payment URL, selects direct crypto payment, or uses card checkout when the invoice allows cards and the remaining amount meets the minimum.
Payment Confirmation
Once payment is confirmed on the blockchain, the invoice status is updated to "paid". Partial payments are supported - if the customer pays less than the full amount, they can complete the payment with a second transaction for the remaining balance.
Webhook Notification
A webhook notification is sent to your server with payment details.
API Endpoints
Section titled “API Endpoints”Create Invoice
Section titled “Create Invoice”Creates a new invoice for direct cryptocurrency payment, with optional card checkout.
This endpoint creates a new invoice with the specified amount and options. The invoice will generate a unique payment page URL that you can redirect your customers to for completing the payment.
Request Headers
Section titled “Request Headers”| Header | Required | Description |
|---|---|---|
Content-Type | Yes | Must be application/json |
Merchant | Yes | Your merchant ID |
Sign | Yes | Request signature (see Authentication) |
Timestamp | No | Include only when using timestamped HMAC; X-Timestamp is accepted as an alias |
Build the canonical JSON body described in Authentication, sign it, and send that same string as the request body.
Request Parameters
Section titled “Request Parameters”| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
order_id | string | Yes | - | Your order identifier (must be unique per merchant) |
amount | string | Yes | - | Invoice amount in USD (minimum 3.00, e.g., “10.50”) |
is_customer_fee | boolean | No | false | If true, the customer pays the service fee (CoinsSend commission) |
is_customer_network_fee | boolean | No | false | If true, the customer pays the blockchain transaction fee; if false, the merchant covers it |
allow_card_payments | boolean | No | false | If true, card checkout may be shown when the invoice amount or remaining amount is at least $15.00 / 1500 cents |
allowed_coins | array | No | all supported coins | List of currently supported cryptocurrencies to allow for this invoice |
coin | string | No | - | Preselect a currently supported coin for the payment page |
network | string | No | - | Preselect a network that matches the selected coin |
success_url | string | No | - | URL to redirect the customer after successful payment |
cancel_url | string | No | - | URL to redirect the customer if they cancel payment |
Important:
coinandnetworkmust be a currently supported combination. Fetch the live catalog fromGET /v1/coins-and-fee. Requests containing an unsupported pair (for exampleethontron) or unsupportedallowed_coinsentries fail validation with HTTP422.
See Supported Coins & Networks for the coin/network tables and guidance on selecting invoice payment options.
Card checkout:
allow_card_paymentsdefaults tofalse. Card checkout is not shown or available unless you setallow_card_paymentstotruefor that invoice. Even when cards are allowed, the invoice amount or remaining amount must be at least$15.00/1500cents. Direct crypto payment remains available when cards are disabled or the remaining amount is below the card minimum.
Request Example
Section titled “Request Example”{ "order_id": "order_12345", "amount": "100.50", "is_customer_fee": true, "is_customer_network_fee": false, "allow_card_payments": true, "allowed_coins": ["usdt", "eth"], "coin": "usdt", "network": "tron", "success_url": "https://example.com/payment-success", "cancel_url": "https://example.com/payment-canceled"}Success Response
Section titled “Success Response”{ "status": "success", "data": { "id": "550e8400-e29b-41d4-a716-446655440000", "order_id": "order_12345", "url": "https://pay.coinssend.com/invoice_code", "code": "invoice_code", "amount": "100.50", "payer_amount": "100.50", "expired_at": "2024-01-02T12:00:00+00:00", "created_at": "2024-01-01T12:00:00+00:00" }}Response Field Descriptions
Section titled “Response Field Descriptions”| Field | Type | Description |
|---|---|---|
id | string | Unique invoice ID (UUID) |
order_id | string | Unique order ID in your system |
url | string | Payment URL for the invoice |
code | string | Unique invoice code |
amount | string | Invoice amount |
payer_amount | string | Total amount the payer needs to pay including fees |
expired_at | string | ISO 8601 timestamp when the invoice expires (24 hours after creation) |
created_at | string | ISO 8601 timestamp when the invoice was created |
allow_card_payments and provider_card are not returned by POST /v1/invoices. They can appear in invoice lookup and payment-page invoice payloads, where provider_card explains whether card checkout is currently available and why it may be disabled.
Card Payment Availability
Section titled “Card Payment Availability”Direct crypto payment is always available on the payment page. Card checkout is optional per invoice and requires both of these conditions:
allow_card_paymentsistrueon the invoice.- The invoice amount, or remaining amount after a partial payment, is at least
$15.00/1500cents.
If either condition is not met, the payment page does not show card checkout and customers can still pay directly with crypto. In invoice lookup and payment-page invoice payloads, the provider_card object explains the current card state with enabled, disabled_reason, minimum_amount_cents, and remaining_amount_cents.
Provider redirects, KYC success, provider webhooks, and provider status polling are not final payment confirmation. Chain confirmation remains the source of truth for moving an invoice to paid.
Create Provider-Card Order
Section titled “Create Provider-Card Order”Creates a card checkout order for an existing invoice when allow_card_payments is enabled and the remaining invoice amount is at least $15.00 / 1500 cents.
Request Parameters
Section titled “Request Parameters”| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
email | string | No | - | Optional customer email to store on the invoice. |
Do not send provider, coin, or network fields for card checkout. CoinsSend
selects these values. If a client includes them, they are ignored and cannot
override the selected checkout route.
Request Example
Section titled “Request Example”{ "email": "customer@example.com"}Success Response
Section titled “Success Response”{ "status": "success", "data": { "provider_card_order": { "id": "550e8400-e29b-41d4-a716-446655440000", "provider": "simpleswap", "local_status": "redirect_pending", "expires_at": "2026-05-11T12:30:00+00:00", "redirect_url": "https://provider.example/checkout/session" }, "reused": false }}Repeating this operation while the same active order is usable returns that
order with reused: true. This narrow active-order reuse is not a general
Idempotency-Key contract.
Retrieve Invoice
Section titled “Retrieve Invoice”Returns the current public checkout state for an invoice.
GET /v1/invoices/{invoiceCode}No merchant signature is required. The response uses the standard success
envelope with data.invoice and current data.network_fees. The invoice
object includes amounts, payment selection, status, allowed payment options,
transaction hashes, QR URL, and provider_card capability. See the exact
machine-readable schema in OpenAPI.
Treat the invoice code as a public checkout identifier. Do not use it as authorization for merchant balances, fees, wallet creation, or withdrawals.
AI assistant prompt: Build a server-side invoice creation and buyer redirect flow. Create
POST /v1/invoices, store the invoice ID, code, status, and URL, then send the buyer todata.url. Treat success/cancel redirect URLs as UX signals only, not payment confirmation. Confirm payment through Webhooks, handlepartialas unpaid progress, and handleexpiredas a terminal failure state. For the full checkout prompt, see AI Integration Prompts.
Error Responses
Section titled “Error Responses”| HTTP status | Response shape | Description |
|---|---|---|
400 | {"error":"Missing headers"} | Merchant or Sign header is missing |
401 | {"error":"Invalid merchant"} or {"error":"Invalid sign"} | Authentication failed |
403 | authentication or endpoint error | Merchant status blocks invoice creation |
409 | {"status":"error","message":"Order id already exists"} | The merchant order ID already exists; the original response is not replayed |
422 | validation error with errors, status, and message | Request parameters are invalid |
Invoice Fees
Section titled “Invoice Fees”When an invoice is paid, the amount your customer must send is shown in the
payer_amount field. This value includes the blockchain network fee and may also
include the service fee depending on the is_customer_fee setting.
- Service Fee (CoinsSend commission) – Calculated as
amount × service_fee_percent. It is added topayer_amountonly whenis_customer_feeistrue. Otherwise this fee is deducted from the merchant balance. - Network/Transaction Fee – Specified in the same coin as the invoice payment.
Network fee values can be obtained from the
network_feeslist in the Merchant API. It is added topayer_amountonly whenis_customer_network_feeistrue. When the merchant covers it (false), the customer sees no network surcharge and the fee is deducted from the merchant proceeds.
The final crypto amount to pay is calculated as:
amount_coin = (amount + (service_fee if is_customer_fee else 0)) / ratetotal_coin = amount_coin + (network_fee if is_customer_network_fee else 0)Fee Calculation Examples
Section titled “Fee Calculation Examples”Customer Pays Service Fee
Invoice amount: 100 USDNetwork fee: 1 USDService fee percent: 0.45%
Service fee: 100 × 0.45% = 0.45 USDTotal amount to pay: 100 + 1 + 0.45 = 101.45 USDMerchant Pays Service Fee
Invoice amount: 100 USDNetwork fee: 1 USDService fee percent: 0.45%
Service fee: 100 × 0.45% = 0.45 USDTotal amount to pay: 100 + 1 = 101 USDService fee deducted from merchant balance: 0.45 USDMerchant Pays Network Fee
Invoice amount: 100 USDNetwork fee: 1 USDService fee percent: 0.45%
Network fee covered by merchant ➜ payer sends: 100.45 USD if customer pays service feeor 100 USD if merchant also covers service fee.ETH USDC Example
Using the ETH network with USDC, the exchange rate on 2025‑07‑09 is
1 USDC = 1.0000363274333 USD.
Invoice amount: 100 USDNetwork fee: 1 USDCService fee percent: 0.45%
Service fee: 100 × 0.45% = 0.45 USDAmount before network fee: 100 + 0.45 = 100.45 USDAmount in USDC: 100.45 ÷ 1.000036327 ≈ 100.4463293 USDCTotal to send: 100.4463293 + 1 ≈ 101.4463293 USDCThe service fee is rounded down to 8 decimal places when converting to cryptocurrency because invoice amounts are stored in cents. The formula is:
fee_coin = floor(amount_coin × service_fee_percent × 100000000) / 100000000Where amount_coin is the invoice amount in the selected coin before the network fee is added.
Code Examples
Section titled “Code Examples”<?php// API credentials$merchantId = 'your_merchant_id';$apiKey = 'your_api_key';
// Invoice data$invoiceData = [ 'order_id' => 'order_' . time(), 'amount' => '100.50', 'is_customer_fee' => true, 'allow_card_payments' => true, 'success_url' => 'https://example.com/payment-success', 'cancel_url' => 'https://example.com/payment-canceled'];
// Generate signature$jsonData = json_encode($invoiceData);$base64Data = base64_encode($jsonData);$signature = md5($base64Data . $apiKey);
// Set up request$ch = curl_init('https://api.coinssend.com/v1/invoices');curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);curl_setopt($ch, CURLOPT_POST, true);curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonData);curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Content-Type: application/json', 'Merchant: ' . $merchantId, 'Sign: ' . $signature]);
// Execute request$response = curl_exec($ch);$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);curl_close($ch);
// Process responseif ($httpCode >= 200 && $httpCode < 300) { $responseData = json_decode($response, true);
if ($responseData['status'] === 'success') { echo "Invoice created successfully!\n"; echo "Payment URL: " . $responseData['data']['url'] . "\n"; echo "Invoice Code: " . $responseData['data']['code'] . "\n"; }} else { echo "Error: " . $response . "\n";}// API credentialsconst merchantId = 'your_merchant_id';const apiKey = 'your_api_key';
// Invoice dataconst invoiceData = { order_id: 'order_' + Date.now(), amount: '100.50', is_customer_fee: true, allow_card_payments: true, success_url: 'https://example.com/payment-success', cancel_url: 'https://example.com/payment-canceled'};
// Generate signatureconst jsonData = JSON.stringify(invoiceData) .replace(/\//g, '\\/') .replace(/[\u0080-\uFFFF]/g, character => `\\u${character.charCodeAt(0).toString(16).padStart(4, '0')}` );const base64Data = Buffer.from(jsonData, 'utf8').toString('base64');const crypto = require('node:crypto');const signature = crypto.createHash('md5').update(base64Data + apiKey).digest('hex');
// Make the API requestfetch('https://api.coinssend.com/v1/invoices', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Merchant': merchantId, 'Sign': signature }, body: jsonData}).then(response => response.json()).then(data => { if (data.status === 'success') { console.log("Invoice created successfully!"); console.log("Payment URL:", data.data.url); console.log("Invoice Code:", data.data.code); } else { console.error("Error:", data); }}).catch(error => console.error("Request failed:", error));import requestsimport jsonimport base64import hashlibimport time
# API credentialsmerchant_id = 'your_merchant_id'api_key = 'your_api_key'
# Invoice datainvoice_data = { 'order_id': f'order_{int(time.time())}', 'amount': '100.50', 'is_customer_fee': True, 'allow_card_payments': True, 'success_url': 'https://example.com/payment-success', 'cancel_url': 'https://example.com/payment-canceled'}
def canonical_json(payload): encoded = json.dumps( payload, ensure_ascii=False, separators=(',', ':'), allow_nan=False ) escaped = [] for character in encoded: codepoint = ord(character) if character == '/': escaped.append(r'\/') elif codepoint < 0x80: escaped.append(character) elif codepoint <= 0xFFFF: escaped.append(f'\\u{codepoint:04x}') else: codepoint -= 0x10000 escaped.append(f'\\u{0xD800 + (codepoint >> 10):04x}') escaped.append(f'\\u{0xDC00 + (codepoint & 0x3FF):04x}') return ''.join(escaped)
# Generate signature from the exact body that will be sentjson_data = canonical_json(invoice_data)base64_data = base64.b64encode(json_data.encode()).decode()signature = hashlib.md5((base64_data + api_key).encode()).hexdigest()
# Set up headersheaders = { 'Content-Type': 'application/json', 'Merchant': merchant_id, 'Sign': signature}
# Make the API requestresponse = requests.post( 'https://api.coinssend.com/v1/invoices', headers=headers, data=json_data)
# Process responseif response.status_code >= 200 and response.status_code < 300: data = response.json()
if data['status'] == 'success': print("Invoice created successfully!") print(f"Payment URL: {data['data']['url']}") print(f"Invoice Code: {data['data']['code']}") else: print(f"Error: {data}")else: print(f"HTTP Error: {response.status_code}") print(f"Response: {response.text}")Invoice Statuses
Section titled “Invoice Statuses”Invoices transition through the following states:
| Status | Description |
|---|---|
new | Invoice created; no payment method selected. |
waiting | Payment method locked in; awaiting blockchain payment. |
partial | Partial payment detected; remaining balance still due. |
paid | Full payment confirmed. |
expired | Invoice expired (24 hours after creation) before full payment. |
aml_rejected | Payment was rejected by AML processing. |
invoice.paid, invoice.expired, and AML rejection. Do not assume every intermediate status has an event. See the Webhooks documentation for details.
Best Practices
Section titled “Best Practices”- Store Invoice Data: Always store the invoice code and status in your database for tracking and reconciliation.
- Handle Webhooks: Implement webhook handling to receive real-time notifications of payment status changes.
- Support Partial Payments: Implement UI and business logic to handle partially paid invoices, allowing customers to complete payments in multiple transactions.
- Track Payment Progress: Use
payed_usd,payed_crypto, and payer amount fields from invoice lookup to show payment progress. - Use Card Checkout Deliberately: Set
allow_card_paymentsonly when you want card checkout available. Keep direct crypto payment available for invoices that do not allow cards or fall below the$15.00card minimum after partial payment. - Verify Webhooks: Always verify webhook signatures to ensure they come from CoinsSend.
- Check Expiration: Invoices expire after 24 hours. Consider this when implementing payment flows.
Related Resources
Section titled “Related Resources”- Webhooks - Receive real-time notifications for invoice status changes
- Authentication - Learn about API authentication and signatures
- Error Handling - Understand error responses and how to handle them
Code Examples
Section titled “Code Examples”For complete code examples in various languages, see: