Hosted checkout or your own? A decision you can make in an afternoon
The two CNIXPay integration modes differ by one field when creating an order. Who each one suits, what each one requires, and how to move from one to the other without touching your backend.
The first decision when integrating CNIXPay is who renders the payment page. At the API level the two options differ by a single field, but the difference in effort and control is real.
Two modes, one field
Mode A · your own checkout: pass paymentOptions when creating the order (POST /orders) to declare which network × token combinations you accept. The paymentOptions array in the response adds the deposit address and amount due for each — render them in your own page.
// Request
{
"merchantOrderNo": "ORDER_001",
"amount": "100.00",
"paymentOptions": [
{ "chain": "tron", "token": "USDT" },
{ "chain": "bsc", "token": "USDC" }
]
}
// Response (excerpt)
{
"paymentOptions": [
{ "chain": "tron", "token": "USDT", "address": "TR7NHq...", "amount": "100.00" },
{ "chain": "bsc", "token": "USDC", "address": "0x55d3...", "amount": "100.00" }
]
}
Mode B · hosted checkout: omit paymentOptions. No address is allocated up front (paymentOptions in the response is empty); the response includes a cashierUrl and you redirect the customer there. Network selection, address and QR code, countdown and the result page are all handled by the platform, which then sends the customer back to your returnUrl.
// Request
{
"merchantOrderNo": "ORDER_002",
"amount": "50.00",
"returnUrl": "https://shop.example.com/orders/ORDER_002"
}
// Response (excerpt)
{
"cashierUrl": "https://pay.example.com/pay/20261017...",
"paymentOptions": []
}
Callbacks, signatures, order statuses and the query endpoint are identical in both modes.
Who each mode suits
| Your own checkout | Hosted checkout | |
|---|---|---|
| Effort | Build a payment page: address, QR, countdown, status polling | None — just redirect |
| Brand and UX | Fully custom; customer never leaves your domain | Platform page, returns to your site afterwards |
| Network choice | You decide what the customer sees | Customer picks on the platform page |
| Best for | Products with an existing checkout, in-app payments, high UX bar | Fast launches, MVPs, campaign pages, no frontend capacity |
| Time to ship | One or two days | One afternoon |
An easily missed point: with your own checkout, the payment options the customer sees are fixed when you create the order. If they reach the payment page and say “I only have USDC on Polygon”, call the add payment options endpoint (POST /orders/{orderNo}/payment-options) to append it — no need to close and recreate the order.
What your own checkout must get right
If you choose Mode A, the payment page needs at least:
- One card per option: network, token, address, QR code, amount due. Amounts can differ per network (
paymentOptions[].amount) — use each one’s own value. - Full address plus one-tap copy. Addresses are case-sensitive on TRON and Solana; never “prettify” them.
- A countdown driven by
expireTime(Unix seconds), not local time plus a fixed duration. - Status polling: while the customer is on the page, hit your own backend every 5–10 seconds; the backend reads the callback-persisted state or gets the order. Never call CNIXPay from the browser.
- An “I have paid” button that triggers an immediate query for instant feedback.
The hosted checkout already does all of this — which is why it takes an afternoon.
Moving from hosted to your own
A common path: launch on the hosted checkout to validate the business, then build your own once the flow is proven. Switching is cheap because the backend does not change:
- Pass
paymentOptionswhen creating the order. - Render the page from
paymentOptionsin the response. - Leave the callback handler untouched.
You can even mix per order: some channels pass paymentOptions and use your page, others omit it and use the hosted checkout, all under the same app.
Recommendation
- Ship first, optimise later. Without specific UX requirements, start with the hosted checkout and use small real orders to prove callbacks, idempotency and reconciliation.
- Have an app or strict brand consistency? Build your own from the start. A day or two of work buys a fully controlled experience.
- Either way, the callback handler is the same. Verify, deduplicate, fulfil only on
paid, poll on timeout — see Callback verification and idempotency.
Field details are in the integration guide · Create an order.