Skip to Content
API ReferenceInvoices

Invoices

Base URL: https://txnod.com/api/v1. Every request must carry the three HMAC headers:

  • X-Project-Id — the caller’s project ULID.
  • X-Timestamp — current Unix timestamp (seconds). Requests outside the ±300-second window are rejected with timestamp_out_of_window.
  • X-Signature — HMAC-SHA256 hex digest of ${timestamp}.${rawBody} using the project’s API secret.

The SDK (@txnod/sdk) handles signing transparently — prefer it over hand-rolled cURL except for smoke tests.

Create an invoice

POST https://txnod.com/api/v1/invoices — creates a new invoice. Idempotent on (project_id, external_id): a replayed request returns the existing invoice with HTTP 200 instead of 201.

Request

Request body (application/json)

FieldTypeRequiredConstraints
external_idstringyesmin length: 1; max length: 128
amount_usdnumbernoexclusive min: 0
amount_cryptostringnopattern: ^\d+(\.\d+)?$
coin"btc" | "eth" | "usdt_erc20" | "usdc_erc20" | "trx" | "usdt_trc20" | "ada" | "pol" | "usdt_polygon" | "usdc_polygon" | "bnb" | "usdt_bep20" | "usdc_bep20" | "ton" | "usdt_ton"yes
callback_urlstring (URI)no
metadataobjectno

Response

200 — Idempotent replay — existing invoice returned unchanged

FieldTypeRequiredConstraints
idstring (ULID)yes
project_idstring (ULID)yes
external_idstringyes
coin"btc" | "eth" | "usdt_erc20" | "usdc_erc20" | "trx" | "usdt_trc20" | "ada" | "pol" | "usdt_polygon" | "usdc_polygon" | "bnb" | "usdt_bep20" | "usdc_bep20" | "ton" | "usdt_ton"yes
addressstringyes
amount_cryptostringyes
amount_crypto_unitsstringyes
amount_usdnumber | nullyes
rate_snapshotobject | nullyes
payment_tokenstring | nullyespattern: ^[0-9a-f]{8}$
payment_uristringyes
callback_urlstring | nullyes
metadataobject | nullyes
matching_mode"exact" | "at_least" | "any"yes
confirmation_thresholdintegeryesmin: 0
status"pending" | "detected" | "paid" | "overpaid" | "partial" | "expired" | "expired_paid_late" | "reverted" | "cancelled"yes
expires_atintegeryesmin: 0
expires_at_isostring (ISO 8601)yes
created_atintegeryesmin: 0
created_at_isostring (ISO 8601)yes
derivation_pathstringnopattern: ^m(\/\d+'?)+$
verification_standard"bip84" | "bip44" | "cip1852" | "bip44_ed25519"no
transactionsarray<object>no
confirmationsintegernomin: 0

201 — Invoice created

FieldTypeRequiredConstraints
idstring (ULID)yes
project_idstring (ULID)yes
external_idstringyes
coin"btc" | "eth" | "usdt_erc20" | "usdc_erc20" | "trx" | "usdt_trc20" | "ada" | "pol" | "usdt_polygon" | "usdc_polygon" | "bnb" | "usdt_bep20" | "usdc_bep20" | "ton" | "usdt_ton"yes
addressstringyes
amount_cryptostringyes
amount_crypto_unitsstringyes
amount_usdnumber | nullyes
rate_snapshotobject | nullyes
payment_tokenstring | nullyespattern: ^[0-9a-f]{8}$
payment_uristringyes
callback_urlstring | nullyes
metadataobject | nullyes
matching_mode"exact" | "at_least" | "any"yes
confirmation_thresholdintegeryesmin: 0
status"pending" | "detected" | "paid" | "overpaid" | "partial" | "expired" | "expired_paid_late" | "reverted" | "cancelled"yes
expires_atintegeryesmin: 0
expires_at_isostring (ISO 8601)yes
created_atintegeryesmin: 0
created_at_isostring (ISO 8601)yes
derivation_pathstringnopattern: ^m(\/\d+'?)+$
verification_standard"bip84" | "bip44" | "cip1852" | "bip44_ed25519"no
transactionsarray<object>no
confirmationsintegernomin: 0

Errors

StatusError code(s)Trigger
400validation_error, invalid_coin, invalid_xpub_format, invalid_webhook_urlRequest body or query failed validation
401auth_invalid, signature_invalid, timestamp_out_of_windowHMAC authentication failed
402subscription_expiredOperator’s TxNod subscription is not active; writes are blocked. Operator must renew via dashboard /billing
403key_revoked, key_suspended, project_suspended, permission_deniedAuth key or project disabled by operator action
409external_id_conflict, xpub_not_verifiedIdempotent replay or ownership challenge incomplete
422coin_not_enabled, amount_out_of_range, wallet_not_bound, tron_no_activated_addresses_availableCoin not enabled, amount out of range, no verified wallet bound for the requested chain on the project, or — TRON only — operator’s address pool has zero activated rows
429rate_limit_exceededPer-project invoice-create rate limit exceeded
500internal_errorInternal error (including cold-start rate unavailability)
503pool_exhaustedAddress pool at hard cap; retry after Retry-After

Examples

curl -X POST https://txnod.com/api/v1/invoices \ -H "X-Project-Id: $TXNOD_PROJECT_ID" \ -H "X-Timestamp: $(date +%s)" \ -H "X-Signature: <hex>" \ -H "Content-Type: application/json" \ -d '{"external_id":"order-123","amount_usd":10.0,"coin":"btc"}'
import { TxnodClient } from '@txnod/sdk'; const client = new TxnodClient({ projectId: process.env.TXNOD_PROJECT_ID!, apiSecret: process.env.TXNOD_API_SECRET!, }); const invoice = await client.createInvoice({ external_id: 'order-123', amount_usd: 10.0, coin: 'btc', });

Search invoices

GET https://txnod.com/api/v1/invoices — cursor-paginated search over the caller project’s invoices.

Request

Query parameters

ParamTypeRequiredConstraints
external_idstringno
addressstringno
tx_hashstringno
amountstringno
status"pending" | "detected" | "paid" | "overpaid" | "partial" | "expired" | "expired_paid_late" | "reverted" | "cancelled"no
date_fromstring (ISO 8601)no
date_tostring (ISO 8601)no
cursorstring (ULID)no
limitintegernomin: 1; max: 200; default: 50

Response

200 — Cursor-paginated invoice list

FieldTypeRequiredConstraints
itemsarray<object>yes
next_cursorstring (ULID)no

Errors

StatusError code(s)Trigger
400validation_errorQuery validation error
401auth_invalid, signature_invalid, timestamp_out_of_windowHMAC authentication failed

Examples

curl "https://txnod.com/api/v1/invoices?status=paid&limit=20" \ -H "X-Project-Id: $TXNOD_PROJECT_ID" \ -H "X-Timestamp: $(date +%s)" \ -H "X-Signature: <hex>"
import { TxnodClient } from '@txnod/sdk'; const client = new TxnodClient({ projectId: process.env.TXNOD_PROJECT_ID!, apiSecret: process.env.TXNOD_API_SECRET!, }); const page = await client.searchInvoices({ status: 'paid', limit: 20 }); for (const invoice of page.items) console.log(invoice.id);

Retrieve an invoice

GET https://txnod.com/api/v1/invoices/{id} — fetch a single invoice by ULID. Returns 404 on cross-project lookups (no enumeration).

Request

Path parameters

ParamTypeRequiredConstraints
idstring (ULID)yes

Response

200 — Invoice detail including transactions + confirmations

FieldTypeRequiredConstraints
idstring (ULID)yes
project_idstring (ULID)yes
external_idstringyes
coin"btc" | "eth" | "usdt_erc20" | "usdc_erc20" | "trx" | "usdt_trc20" | "ada" | "pol" | "usdt_polygon" | "usdc_polygon" | "bnb" | "usdt_bep20" | "usdc_bep20" | "ton" | "usdt_ton"yes
addressstringyes
amount_cryptostringyes
amount_crypto_unitsstringyes
amount_usdnumber | nullyes
rate_snapshotobject | nullyes
payment_tokenstring | nullyespattern: ^[0-9a-f]{8}$
payment_uristringyes
callback_urlstring | nullyes
metadataobject | nullyes
matching_mode"exact" | "at_least" | "any"yes
confirmation_thresholdintegeryesmin: 0
status"pending" | "detected" | "paid" | "overpaid" | "partial" | "expired" | "expired_paid_late" | "reverted" | "cancelled"yes
expires_atintegeryesmin: 0
expires_at_isostring (ISO 8601)yes
created_atintegeryesmin: 0
created_at_isostring (ISO 8601)yes
derivation_pathstringnopattern: ^m(\/\d+'?)+$
verification_standard"bip84" | "bip44" | "cip1852" | "bip44_ed25519"no
transactionsarray<object>no
confirmationsintegernomin: 0

Errors

StatusError code(s)Trigger
401auth_invalid, signature_invalid, timestamp_out_of_windowHMAC authentication failed
404invoice_not_foundInvoice not found or belongs to a different project

Examples

curl https://txnod.com/api/v1/invoices/01HK8MAR2QEXAMPLE000000000 \ -H "X-Project-Id: $TXNOD_PROJECT_ID" \ -H "X-Timestamp: $(date +%s)" \ -H "X-Signature: <hex>"
import { TxnodClient } from '@txnod/sdk'; const client = new TxnodClient({ projectId: process.env.TXNOD_PROJECT_ID!, apiSecret: process.env.TXNOD_API_SECRET!, }); const invoice = await client.getInvoice('01HK8MAR2QEXAMPLE000000000'); console.log(invoice.status);

Cancel an invoice

POST https://txnod.com/api/v1/invoices/{id}/cancel — cancels an invoice in pending or detected state and releases its pool address into cooldown. Terminal-status invoices return 409 invoice_not_cancellable.

Request

Path parameters

ParamTypeRequiredConstraints
idstring (ULID)yes

Response

200 — Invoice cancelled

FieldTypeRequiredConstraints
idstring (ULID)yes
project_idstring (ULID)yes
external_idstringyes
coin"btc" | "eth" | "usdt_erc20" | "usdc_erc20" | "trx" | "usdt_trc20" | "ada" | "pol" | "usdt_polygon" | "usdc_polygon" | "bnb" | "usdt_bep20" | "usdc_bep20" | "ton" | "usdt_ton"yes
addressstringyes
amount_cryptostringyes
amount_crypto_unitsstringyes
amount_usdnumber | nullyes
rate_snapshotobject | nullyes
payment_tokenstring | nullyespattern: ^[0-9a-f]{8}$
payment_uristringyes
callback_urlstring | nullyes
metadataobject | nullyes
matching_mode"exact" | "at_least" | "any"yes
confirmation_thresholdintegeryesmin: 0
status"pending" | "detected" | "paid" | "overpaid" | "partial" | "expired" | "expired_paid_late" | "reverted" | "cancelled"yes
expires_atintegeryesmin: 0
expires_at_isostring (ISO 8601)yes
created_atintegeryesmin: 0
created_at_isostring (ISO 8601)yes
derivation_pathstringnopattern: ^m(\/\d+'?)+$
verification_standard"bip84" | "bip44" | "cip1852" | "bip44_ed25519"no
transactionsarray<object>no
confirmationsintegernomin: 0

Errors

StatusError code(s)Trigger
401auth_invalid, signature_invalid, timestamp_out_of_windowHMAC authentication failed
404invoice_not_foundInvoice not found or belongs to a different project
409invoice_not_cancellable, invalid_state_transitionInvoice is not in a cancellable state

Examples

curl -X POST https://txnod.com/api/v1/invoices/01HK8MAR2QEXAMPLE000000000/cancel \ -H "X-Project-Id: $TXNOD_PROJECT_ID" \ -H "X-Timestamp: $(date +%s)" \ -H "X-Signature: <hex>"
import { TxnodClient } from '@txnod/sdk'; const client = new TxnodClient({ projectId: process.env.TXNOD_PROJECT_ID!, apiSecret: process.env.TXNOD_API_SECRET!, }); const cancelled = await client.cancelInvoice('01HK8MAR2QEXAMPLE000000000'); console.log(cancelled.status);