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
amountstringDecimal string ("100", "49.50"). A positive value makes this an order; "0" or omitted = open address. A positive amount is required in client fee mode (else 422 EXPECTED_AMOUNT_REQUIRED).
pricingCurrencystring | nullUSD to price the order in fiat — amount 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 — see Fee modes
expected_amountstring | nullThe order amount in USDT. For a USD-priced order this is the converted USDT (= fiat_amount × quote_rate)
pay_amountstring | nullClient fee mode: the amount the payer must send — expected_amount plus the platform fee on it (no fee on the fee). A payer who sends it in full is charged exactly that fee, so you receive expected_amount; an under- or overpayment is fee'd on the amount that actually arrived (on an overpayment the fee is capped at the surplus above expected_amount, so you always receive at least the order). 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 | nullThe hosted checkout link for this environment: https://staging-checkout.zaropay.com/c/<token> on staging, https://checkout.zaropay.com/c/<token> on live

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" }'

Fee modes​

The ZaroPay platform fee is a percentage (or fixed amount) set on your account. fee_mode says who pays it:

fee_modeCustomer is asked to sendFeeYou receive (netAmount)
merchant (default)expected_amount (100)deducted from the payment: 199
clientpay_amount = expected_amount + fee (101)paid on top by the customer: 1100

The fee is always charged on the amount that actually arrives. A customer who sends exactly what was asked is charged exactly the quoted fee; anything else is fee'd on the amount paid. With a 100 USDT order at 1% in client mode:

Customer sendspaymentStateFeeYou receive
101 (as asked)exact1100
50underpaid0.549.5
200overpaid2198

payment_state is set for every order with an amount, in both modes; it is null only for an open address. ZaroPay never refunds automatically — see Underpaid and overpaid payments for how to handle each state from the webhook, where netAmount / feeAmount (and fiatNetAmount for USD orders) tell you exactly what you received.

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", // the order in USDT (= fiat_amount × quote_rate); in client fee mode the customer pays pay_amount = this + fee
"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.

Once a USD-priced deposit is credited, the deposit row carries fiat_net_amount and the webhook fiatNetAmount — what you received converted back to dollars at the locked rate — so a partial or over-payment can be booked in USD without converting yourself ($100 order paid with 50 USDT at 1.002 → net_amount "49.5", fiat_net_amount "49.4").

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, detected, confirming, stuck, reorg_pending, failed, 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.