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.
| Field | Required | Notes |
|---|---|---|
asset_id | yes | One (symbol, network) asset from GET /v1/assets |
amount | no | In token units, not USD. "0" or omitted means an open amount |
merchant_order_id | yes | 1–128 characters, unique per store for Express invoices |
description, customer_reference, metadata | no | As for standard invoices |
success_url, cancel_url | no | Same 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 (
amountgreater than zero). The customer must send at least that many tokens. More decimal places than the token supports is refused with422 invalid_precision; an amount below the asset's minimum with422 below_minimum. Less than the amount confirmed makes the invoicepartial; a further payment before expiry can still make itpaid. More than the amount ispaid. - Open (
amountis"0"or omitted). The first confirmed transfer with a positive amount completes the invoice aspaid, and the invoice's USDamountis 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 send | Result |
|---|---|
A new key and a new merchant_order_id | 201 Created, a new invoice |
| The same key and the same body again | 200 OK, the original invoice (retries are safe) |
| The same key with a different body | 409 idempotency_conflict |
A different key with a merchant_order_id that already has an Express invoice in this store | 409 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.