Accept payments

Invoices API

An invoice is a request to pay a fixed amount in USD. It knows the order, the customer, the network the customer picked, the deposit address and every transfer we saw on chain. Five endpoints cover the whole flow.

Basics

Base URLhttps://pay.axiomis.app/api/v1
AuthAuthorization: Bearer axp_live_… or axp_test_…. The key decides the mode: test keys see only test invoices and test networks.
FormatJSON in, JSON out, snake_case fields. Times are ISO 8601 in UTC.
MoneyUSD amounts are integer cents. On-chain amounts (*_units) are strings of base units: USDT on BSC has 18 decimals and does not fit in a JavaScript number.
IDsinv_ plus 24 random characters. The ID is unguessable: the checkout page uses it as the only secret.

Create an invoice

POST/v1/invoices
FieldTypeDescription
amount_usd_centsinteger, requiredFrom 100 to 10000000. 1 USDT is treated as 1 USD.
external_order_idstring, requiredYour order ID, 1 to 128 printable ASCII characters. Several invoices can share it (network change creates a new invoice for the same order).
customer_refstring, requiredYour customer ID, same format. A customer can have at most 3 open invoices by default (TOO_MANY_OPEN_INVOICES).
descriptionstringShown to the customer, up to 200 characters.
localeen | ruLanguage of the checkout page.
success_urlURLWhere the "Back to store" button leads after payment on the hosted page. HTTPS in live mode.
cancel_urlURLWhere the customer goes to start over (expired or cancelled invoice). HTTPS in live mode.
metadataobjectAnything you want back in webhooks, up to 4 KB of JSON. Not shown to the customer.

Idempotency

Send an Idempotency-Key header (up to 255 printable ASCII characters) to make retries safe. The same key within 30 minutes returns the same invoice with status 200 instead of 201. The same key with a different amount, order or customer returns 409 IDEMPOTENCY_KEY_REUSED. A good key is your order ID plus an attempt number.

curl https://pay.axiomis.app/api/v1/invoices \
  -H "Authorization: Bearer $AXIOMISPAY_KEY" \
  -H "Idempotency-Key: order-1042-1" \
  -H "Content-Type: application/json" \
  -d '{"amount_usd_cents":2900,"external_order_id":"1042","customer_ref":"user-77"}'

Lifetime

A new invoice has no network yet and does not hold a deposit address. The customer picks a network and accepts the terms on the checkout page; only then is an address assigned and the 60-minute timer restarts from that moment. An invoice nobody opened expires 60 minutes after creation.

The invoice object

JSON
{
  "id": "inv_7Qx2mK9aLp3RtV8sNc4WbY1z",
  "object": "invoice",
  "mode": "test",
  "status": "paid",
  "amount_usd_cents": 2900,
  "received_usd_cents": 2900,
  "external_order_id": "1042",
  "customer_ref": "user-77",
  "description": "Pro plan, 1 month",
  "locale": "en",
  "metadata": { "plan": "pro" },
  "network": "tron-nile",
  "asset": "tron-nile:usdt",
  "address": "TJ4fQm1x6cE8hB9zZy3rVpW2nK5sLtGd7A",
  "memo": null,
  "decimals": 6,
  "expected_units": "29000000",
  "received_units": "29000000",
  "quote": null,
  "hosted_url": "https://pay.axiomis.app/i/inv_7Qx2mK9aLp3RtV8sNc4WbY1z",
  "embed_url": "https://pay.axiomis.app/embed/i/inv_7Qx2mK9aLp3RtV8sNc4WbY1z",
  "created_at": "2026-10-12T09:14:03.000Z",
  "expires_at": "2026-10-12T10:16:40.000Z",
  "paid_at": "2026-10-12T09:19:52.000Z",
  "closed_at": null,
  "cancel_reason": null,
  "replaced_by": null,
  "replaces": null,
  "resolution": "auto",
  "transfers": [
    {
      "network": "tron-nile",
      "asset": "tron-nile:usdt",
      "tx_hash": "9f1c…e42a",
      "log_index": 0,
      "amount_units": "29000000",
      "status": "confirmed",
      "confirmations": 19,
      "confirmations_required": 19,
      "block_number": "61523874",
      "counted": true,
      "explorer_url": "https://nile.tronscan.org/#/transaction/9f1c…e42a"
    }
  ]
}
FieldDescription
statusOne of eight statuses, see Statuses.
amount_usd_centsThe amount you asked for.
received_usd_centsWhat actually arrived, by confirmed transfers. Use it for overpayments and partial payments.
network, assetnull until the customer picks. Asset IDs look like tron:usdt, bsc:usdt, base:usdc, ton:usdt, tron-nile:usdt.
addressThe deposit address from your pool, assigned for the lifetime of this invoice. On TON: your own TON wallet address.
memoTON only: the transfer comment (AX-…) that identifies this invoice. The customer must include it; null on other networks.
expected_units, received_unitsAmounts in base units of the asset; divide by 10^decimals.
quoteFor native coins (TRX, BNB, ETH, POL, TON): the USD rate and when it expires. null for USDT and USDC.
replaced_by, replacesNetwork change closes the invoice and creates a new one; these fields link them.
resolutionauto, or manual when our operator confirmed the payment by hand.
transfersEvery transfer to the address. counted: false means it is linked but not counted (for example a different token).

Retrieve an invoice

GET/v1/invoices/:id

Returns the invoice object. Use it to double-check a status before you ship something expensive, or to poll if webhooks are not set up yet (poll no more often than every 10 seconds).

List invoices of an order

GET/v1/invoices?external_order_id=1042

Returns { "data": [Invoice, …] }. An order has more than one invoice when the customer changed the network: the old one is cancelled with cancel_reason: "network_changed" and points to the new one in replaced_by.

Cancel an invoice

POST/v1/invoices/:id/cancel

Closes an open invoice (for example the customer changed the plan). Works only for pending invoices with no transfer seen yet; otherwise you get 409 PAYMENT_IN_PROGRESS or 409 INVOICE_NOT_CANCELLABLE. Returns the invoice with status: "cancelled" and sends invoice.cancelled.

List networks and assets

GET/v1/assets
Response
{
  "data": [
    { "id": "tron-nile:usdt", "network": "tron-nile", "code": "usdt", "kind": "token", "decimals": 6, "testnet": true },
    { "id": "bsc-testnet:usdt", "network": "bsc-testnet", "code": "usdt", "kind": "token", "decimals": 6, "testnet": true }
  ]
}

Networks enabled for your key's mode. The customer chooses among them on the checkout page; you do not pass a network when creating an invoice.

Errors

Errors return a non-2xx status and { "code": "…", "message": "…" }. Build your logic on code: it is stable. message is for logs and may change (during the pilot some messages are in Russian).

StatusCodeMeaning
400VALIDATIONA field is missing or out of range; the message names it.
401INVALID_API_KEYMissing, wrong or revoked key.
404NOT_FOUNDNo such invoice for this key (test keys do not see live invoices and vice versa).
409IDEMPOTENCY_KEY_REUSEDThe Idempotency-Key was used for a different request.
409TOO_MANY_OPEN_INVOICESThis customer already has 3 open invoices. Cancel the old ones or reuse one.
409INVOICE_NOT_CANCELLABLEThe invoice is not pending any more.
409PAYMENT_IN_PROGRESSA transfer to the address was already seen; wait for the final status.
429RATE_LIMITEDToo many requests. Back off and retry.
5xxOur side. Retry with the same Idempotency-Key.

Network timeouts happen. If a create request times out, retry it with the same Idempotency-Key: you will not get a duplicate invoice.

Invoices API · Axiomis Pay Docs