CXPay API documentation quickstart
This quickstart covers the essentials for integrating https://api.cxpay.cash/api/v1. For policy and fee context, read pricing and how-it-works pages.
Authentication
Send your API key in the Authorization header as documented by your SDK or HTTP client. Use cxpay_test_ keys in staging and cxpay_live_ in production. Keys are scoped—create separate keys for WooCommerce, billing, and reporting when possible.
CXPay is non-custodial: when a payer completes checkout, funds settle directly to the payout wallet address you provide at sign-up. CXPay does not operate merchant hot wallets, sweeps, or pooled balances for your sales. You remain in control of the wallet that receives each payment.
CXPay charges 1% on standard checkout, 0.5% when the payer selects the CXCASH rail (private, gas-free payments on Aztec via cxcash.app), and a $0.30 minimum fee per payment. There is no setup fee, monthly fee, or application fee in the product. Ethereum and Bitcoin network fees are shown to the payer at cost on those rails.
Create a payment intent
Example curl (replace KEY and adjust amountUsdCents):
Hosted checkout flow
Creating a payment intent returns data your app uses to redirect payers to CXPay hosted checkout. The payer selects asset/network, receives an exact quote, and broadcasts payment before quote expiry.
Verify webhooks in Node
Webhooks send cxpay-signature: t=<unix>,v1=<hex>. Compute HMAC-SHA256 of "<t>.<raw body>" with your endpoint secret and compare to v1 within a five-minute tolerance.
Idempotency
Include Idempotency-Key on POST /payment-intents so retries after network failures do not create duplicate intents.
Payment statuses
Webhook events map to payer outcomes: confirming, paid, succeeded, underpaid, overpaid, expired, failed, cancelled. Use dashboard delivery logs when debugging retries and dead-letter behavior.
Core endpoints
POST/GET /payment-intents, GET /payment-intents/:id, POST /payment-intents/:id/cancel, POST /payment-links, POST/GET /invoices(/:id), POST /refunds, GET /refunds/:id, GET /reports/payments, GET /exports/payments.csv, plus webhook endpoint management.
Configure webhook endpoints to receive signed POST requests when payment state changes. Parse the cxpay-signature header, reject stale timestamps outside the five-minute tolerance, and return quickly while processing asynchronously. Failed deliveries retry and may dead-letter; use dashboard delivery logs to diagnose URL typos, TLS issues, or application errors on your side.
The merchant dashboard and GET /reports/payments help you filter by status and time range. Download GET /exports/payments.csv when finance needs a spreadsheet-friendly view. Pair exports with webhook-driven order updates so internal systems stay aligned with on-chain settlement. Because CXPay does not hold balances, your wallet history and CXPay reports together form the reconciliation trail.
Hosted checkout in production
Server integrations should create payment intents with Idempotency-Key headers, persist the returned intent ID on your order row, and only mark paid after payment.succeeded verifies on your webhook handler. Test keys let you exercise the full lifecycle without touching live balances. WooCommerce merchants request the official plugin through the contact form and configure API base URL plus webhook secrets before going live.
Merchants who educate payers about exact amounts and quote expiry see fewer support tickets. Publish your accepted assets and networks on your store policy page and link to CXPay asset guides. When customers pay with ETH or BTC, remind them that network fees appear separately from the CXPay merchant fee. For audiences comfortable with Aztec, highlight CXCASH as a gas-free alternative through cxcash.app.
Checkout amounts are priced in USD and quoted to the payer as an exact crypto amount, rounded to a precision their wallet or exchange can actually type: two decimals for USD stablecoins and TRX, four for SOL, six for ETH and on-chain Bitcoin, and whole satoshis for Lightning. The payer must send that exact amount before the quote expires; quotes can be refreshed if they lapse. Underpaid, overpaid, and expired payments are surfaced as distinct statuses in the dashboard and via webhooks.
Payable amount precision
Payable precision is set per asset and network so the quoted amount fits the send form payers actually use. USDC, USDT, DAI, and CXCASH are quoted to two decimals on every supported network, because retail exchange apps commonly limit stablecoin withdrawals to cents. TRX also uses two decimals, SOL uses four, ETH and on-chain BTC use six, and Lightning invoices are exact to the satoshi.
Checkout and the API return the engine amount as a string. Render it as received instead of reformatting it to a fixed number of decimals, otherwise payers see a padded amount such as 1.010000 that some wallets refuse to accept.
A quote can land a few cents above the cart total. Because payments settle straight to the merchant wallet rather than to a per-invoice deposit address, the amount is what tells two payments on the same address apart: each open payment is offset by one payable unit, for example $1.00, $1.01, and $1.02 on a $1.00 item. That offset is capped at five cents on small invoices and at 0.5% of the order up to $0.25 on larger ones, and it is already included in the amount shown at checkout.
Payments that land within 0.25% of the quote count as paid. Anything further below is reported as underpaid, and the payer can top up the shortfall to the same address before the quote expires; receipts to that address are added together and the status is re-evaluated. Payments more than 0.25% above the quote are flagged as overpaid so the merchant can refund the difference.
On EVM networks, Tron, and Bitcoin on-chain the transferred amount is the only identifier available, which is why the amount must match. Solana payments also carry a Solana Pay reference key that identifies the transfer directly, with the amount as a fallback, and Lightning payments are matched by invoice payment hash, so both of those rails are exact by design. CXCASH payments carry a payment reference from the wallet.
Payment URIs (Tron, Solana, Lightning)
After select-asset, hosted checkout shows the exact engine amount string and, on supported rails, a paymentUri suitable for QR codes and wallet deep links.
Solana responses include solana: URIs with amount and reference. Tron responses include tron: URIs for TronLink. Lightning responses include lightning: BOLT11 plus invoice and railReference fields for wallet apps.
EVM and on-chain BTC continue to use deposit addresses; ETH and BTC on-chain may include a payer network-fee line at cost.
Create payment intent (curl)
curl -sS -X POST https://api.cxpay.cash/api/v1/payment-intents \
-H "Authorization: Bearer cxpay_test_YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-1001-create" \
-d '{"amountUsdCents":2500,"rail":"standard","metadata":{"orderId":"1001"}}'Verify webhooks (Node)
import crypto from 'node:crypto';
export function verifyCxpaySignature(rawBody, header, secret, toleranceSec = 300) {
const parts = Object.fromEntries(
header.split(',').map((p) => p.trim().split('=')),
);
const t = Number(parts.t);
const v1 = parts.v1;
if (!t || !v1) return false;
if (Math.abs(Date.now() / 1000 - t) > toleranceSec) return false;
const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
return crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected));
}Payable decimals by asset
| Asset | Network | Payable decimals | Example amount |
|---|---|---|---|
| USDC, USDT, DAI, CXCASH | All supported networks | 2 | 25.01 |
| TRX | Tron | 2 | 81.25 |
| SOL | Solana | 4 | 0.1057 |
| ETH | Ethereum and L2s | 6 | 0.004213 |
| BTC | Bitcoin on-chain | 6 | 0.000241 |
| BTC | Lightning | whole satoshis | 0.00024100 |
Webhook events and meanings
| Event | Meaning |
|---|---|
| payment.confirming | Payment seen on network, awaiting confirmations |
| payment.paid | Paid amount received; may still confirm |
| payment.succeeded | Successful settlement to merchant wallet |
| payment.underpaid | Less than quoted amount received |
| payment.overpaid | More than quoted amount received |
| payment.expired | Quote expired before satisfactory payment |
| payment.failed | Payment failed |
| payment.cancelled | Intent cancelled via API or dashboard |
Test vs live keys
Prefix cxpay_test_ keys for staging and webhook experiments. Use cxpay_live_ only in production. Rotate keys from the merchant dashboard if exposed.
Read API integration and how hosted checkout works for payer-facing flows.
Explore CXPay
Start accepting crypto payments
Create a merchant account with email, business name, and your payout wallet. No ID documents required.
Sign up freeQuestions about this page
What base URL should I use?
https://api.cxpay.cash/api/v1 for production integrations.
Which header signs webhooks?
cxpay-signature with timestamp and v1 HMAC.
Can I test without mainnet deploys?
Use cxpay_test_ keys and test webhooks; CXPay marketing makes no mainnet contract deploy claims.
Where is OpenAPI?
This page is a quickstart; explore endpoints via the listed paths and your HTTP client.
How many decimals does the quoted amount have?
Two for USD stablecoins and TRX, four for SOL, six for ETH and on-chain BTC, and whole satoshis for Lightning. Display the amount string exactly as the API returns it.