Skip to main content

Hosted Checkout

The fastest way to get paid: create a charge and redirect the customer to a branded ZaroPay payment page. No payment UI to build.

Flow

Your backend Customer ZaroPay
──────────── ──────── ───────
POST /v1/deposit-addresses ─────► opens checkout_url ─────► shows QR + live status
(amount, orderRef, pays USDT on TRON detects + confirms on-chain
successUrl, cancelUrl) │
▲ ▼
└──────────── deposit.confirmed webhook (verify!) ◄──────────┘
customer redirected to successUrl

1. Create the charge

POST /v1/deposit-addresses with an amount (and optionally orderRef, successUrl, cancelUrl). The response includes a checkout_token and a ready-to-use checkout_url (https://checkout.zaropay.com/c/<token>). See Deposit Addresses.

2. Redirect the customer

Send them to data.checkout_url. The page is driven by the public, unauthenticated endpoint GET /v1/checkout/:token — the unguessable token is the capability (no API key needed in the browser). It returns a safe, whitelisted projection:

{
"state": "awaiting|confirming|paid|underpaid|overpaid|expired|error",
"merchant": { "name": "…", "logoUrl": "…", "accentColor": "#…" },
"order": { "ref": "INV-1042", "amount": "100", "payAmount": "100", "currency": "USDT",
"feeMode": "merchant", "successUrl": "…", "cancelUrl": "…",
"fiatCurrency": null, "fiatAmount": null, "quoteRate": null, "quoteExpiresAt": null },
"payment": { "address": "TXyz…", "chain": "tron", "expiresAt": "…" },
"status": { "depositStatus": "CONFIRMING", "confirmations": 5, "requiredConfirmations": 19,
"amountReceived": "100", "paymentState": "exact", "txHash": "0x…", "confirmedAt": null }
}

payAmount is the exact figure the payer must send. The page updates live (websocket + polling fallback) as the payment is detected and confirmed.

USD-priced orders

If you created the charge with pricingCurrency: "USD", the projection's order block carries the fiat denomination — fiatCurrency ("USD"), fiatAmount (the dollar figure), quoteRate (the locked USDT-per-USD rate), and quoteExpiresAt (when the lock ends). amount / payAmount stay the USDT the customer pays. The hosted page shows the USD amount alongside the USDT total and a countdown to quoteExpiresAt; when the lock lapses it auto-refreshes the quote via POST /v1/checkout/:token/requote (same token, no auth — only while the order is still unpaid), so the displayed USDT amount always reflects a fresh rate.

3. Return redirect

On a terminal state the customer is redirected to your successUrl / cancelUrl with query params appended:

?ref=<orderRef>&status=<paid|cancelled|expired>
The redirect is not proof of payment

The browser redirect is for UX only and is customer-controllable. Confirm fulfilment from the signed deposit.confirmed webhook — never from the status query parameter.

Customizing the page

The checkout page shows your merchant name, logo, and accent color (merchant block above), configured in the Merchant Dashboard. The orderRef you pass is shown to the customer.