Skip to main content

Deposit Addresses & Payment Links

One endpoint creates all three charge shapes:

You sendYou get
amount (+ optional successUrl/cancelUrl/orderRef)an order / payment link
reusable: truea standing "receive USDT" address (never expires)
nothing extraan open deposit address

Create POST /v1/deposit-addresses

Request body

All fields are optional at the schema level (unknown fields are ignored), but amount is required when the effective fee mode is client.

FieldTypeNotes
chainstringtron (default)
currencystringUSDT (default) or TRX
amountstringNon-negative decimal ("100", "49.50"). Presence makes this an order. Required in client fee mode (else 422 EXPECTED_AMOUNT_REQUIRED).
pricingCurrencystring | nullUSD to price the order in fiatamount is then a USD figure, converted to USDT at the live rate and locked for ~10 min (see Pricing in USD). Omit or USDT = amount is already USDT. With USD, a positive amount is required (422 USD_AMOUNT_REQUIRED).
orderRefstring | nullYour order reference, max 120; shown on the checkout page
labelstring | nullInternal label, max 120
successUrlstring | nullhttp/https, max 2048 — checkout redirect on success
cancelUrlstring | nullhttp/https, max 2048 — checkout redirect on cancel/expiry
settlementAccountIdstring (uuid)Route funds to a specific settlement wallet (404 SETTLEMENT_ACCOUNT_NOT_FOUND if not yours)
reusablebooleantrue → find-or-create a stable, non-expiring receive address
apiKeyIdstring (uuid)First-party attribution only; ignored when an X-Api-Key is presented

Response 201

FieldTypeNotes
idstring (uuid)
addressstringThe on-chain address to pay
chain / currencystring
statusstringACTIVE
expires_attimestamp | nullnull for reusable receive addresses
fee_modestringmerchant or client
expected_amountstring | nullThe order amount in USDT. For a USD-priced order this is the converted USDT (= fiat_amount × quote_rate)
pay_amountstring | nullGrossed-up amount the payer must send (client fee mode); else null
fiat_currencystring | nullUSD when the order was priced in fiat; else null
fiat_amountstring | nullThe original fiat amount you sent (e.g. "100"); null for USDT-priced orders
quote_ratestring | nullLocked exchange rate (USDT per 1 unit of fiat_currency); null otherwise
quote_sourcestring | nullRate source, e.g. coingecko; null otherwise
quote_expires_attimestamp | nullWhen the locked quote expires (created + ~10 min); null otherwise
order_refstring | null
success_url / cancel_urlstring | null
checkout_tokenstringUnguessable capability token
checkout_urlstring | nullCHECKOUT_BASE_URL + token, e.g. https://checkout.zaropay.com/c/<token>

Example

curl -X POST https://api.zaropay.com/v1/deposit-addresses \
-H "X-Api-Key: $ZAROPAY_API_KEY" -H "Content-Type: application/json" \
-d '{ "amount": "100", "orderRef": "INV-1042", "successUrl": "https://shop.example.com/thanks" }'

Pricing in USD (fiat)

Send pricingCurrency: "USD" to quote an order in dollars. ZaroPay converts to USDT at the live rate at creation and locks it for ~10 minutes, so the customer always pays a fixed USDT amount. Settlement and fees remain in USDT — the fiat figures are for display and reporting.

curl -X POST https://api.zaropay.com/v1/deposit-addresses \
-H "X-Api-Key: $ZAROPAY_API_KEY" -H "Content-Type: application/json" \
-d '{ "amount": "100", "pricingCurrency": "USD", "orderRef": "INV-1042" }'
// 201 — $100 converted to USDT at the locked rate
{
"expected_amount": "100.164", // USDT the customer pays (= fiat_amount × quote_rate)
"fiat_currency": "USD",
"fiat_amount": "100",
"quote_rate": "1.00164", // USDT per 1 USD, locked
"quote_source": "coingecko",
"quote_expires_at": "2026-06-29T12:34:56.000Z",
"checkout_url": "https://checkout.zaropay.com/c/<token>"
// …plus the usual id / address / status / checkout_token
}

The hosted checkout shows the USD amount, the USDT to pay, and a countdown; if the customer lingers past the lock it automatically re-quotes. If no fresh rate is available the request fails closed with 503 RATE_UNAVAILABLE (retry shortly) rather than quoting on a stale rate.

Note Because USDT tracks the US dollar, the conversion is typically within a fraction of a cent of 1:1. The lock simply guarantees the customer the exact USDT figure they were shown.

Errors

CodeStatusMeaning
EXPECTED_AMOUNT_REQUIRED422amount required in client fee mode
USD_AMOUNT_REQUIRED422pricingCurrency: "USD" sent without a positive amount
RATE_UNAVAILABLE503No fresh USD→USDT rate available — retry shortly
MAX_ACTIVE_ADDRESSES429Your active-address cap is reached
SETTLEMENT_ACCOUNT_NOT_FOUND404settlementAccountId isn't yours
NO_SETTLEMENT_ACCOUNT422reusable requested with no active settlement wallet

List GET /v1/deposit-addresses

Query params: status (ACTIVE/EXPIRED/ARCHIVED), chain (tron), kind (order = one-off links with expiry, receive = standing addresses), plus page / limit.

Returns an array of deposit-address rows (each with an injected checkout_url) and meta. When kind=order, each row also carries a derived payment_status (paid, confirming, detected, awaiting, expired).


Retrieve GET /v1/deposit-addresses/:id

:id is the address UUID, scoped to your merchant account (404 if it isn't yours). Returns a single deposit-address row including checkout_url. Use this to poll an order's status — though the webhook is the preferred, push-based signal.