Skip to content

Explore Zenq Pay

Sections of the home page, pricing and developer docs.

Sign in

Merchant dashboard

Express invoices

An Express invoice is created for one specific coin on one specific network, and its deposit address exists as soon as the invoice does. Use it when you show your own payment screen, top up a balance, or already know which token the customer will send.

Create one

curl -X POST https://<api-host>/v1/express/invoices \
  -H "Authorization: Bearer nxp_test_…" \
  -H "Idempotency-Key: topup-1001" \
  -H "Content-Type: application/json" \
  -d '{"asset_id":"<asset id>","amount":"25","merchant_order_id":"topup-1001"}'

Find asset_id with GET /v1/assets?environment=test (or environment=live), which lists the active USDT and USDC assets per network. Express accepts USDT and USDC tokens only.

FieldRequiredNotes
asset_idyesOne (symbol, network) asset from GET /v1/assets
amountnoIn token units, not USD. "0" or omitted means an open amount
merchant_order_idyes1–128 characters, unique per store for Express invoices
description, customer_reference, metadatanoAs for standard invoices
success_url, cancel_urlnoSame rules as hosted checkout

The response is the same invoice object as POST /v1/invoices, with mode: "express". The payment details are already filled in: payments[0] holds the address, asset_symbol, network_id and crypto_amount. The quote lasts until the invoice expires (one hour by default), so you can show the address straight away. The invoice also has a checkout_url if you would rather use the hosted page.

Fixed or open amount

amount_mode tells you which kind you created.

  • Fixed (amount greater than zero). The customer must send at least that many tokens. More decimal places than the token supports is refused with 422 invalid_precision; an amount below the asset's minimum with 422 below_minimum. Less than the amount confirmed makes the invoice partial; a further payment before expiry can still make it paid. More than the amount is paid.
  • Open (amount is "0" or omitted). The first confirmed transfer with a positive amount completes the invoice as paid, and the invoice's USD amount is set from what was received. Zero-value transfers are ignored. Use this for deposits and top-ups where the customer decides how much to send.

Money that arrives after the invoice is paid does not change it; you are notified so the extra funds can be reviewed. Money that arrives after expiry becomes late_review and is never credited automatically.

Idempotency-Key is mandatory

Every Express request must carry an Idempotency-Key header (1–128 characters). A request without one is rejected by request validation with 422 and a detail array, before anything is created.

You sendResult
A new key and a new merchant_order_id201 Created, a new invoice
The same key and the same body again200 OK, the original invoice (retries are safe)
The same key with a different body409 idempotency_conflict
A different key with a merchant_order_id that already has an Express invoice in this store409 order_conflict

So merchant_order_id protects you twice: a retried request returns the same invoice, and a bug that creates a second invoice for the same order is refused instead of handing the customer a second address.

Fulfilment

As with every invoice, fulfil from the signed invoice.paid webhook, deduplicated on the event id. See Webhooks.