Orphan Payments
Base URL: https://txnod.com/api/v1. Same HMAC header requirements as the Invoices API: X-Project-Id, X-Timestamp, X-Signature.
An orphan payment is an on-chain receipt that could not be matched to any open invoice address at detection time. Common causes are manual sends to a reused address, invoice expiry before funds arrived, or partners that do not use callback_url. Orphans are surfaced so operators can resolve them by attributing to an external_id — the attribution API creates a synthetic invoice in paid state indistinguishable from the normal-payment path.
List orphan payments
GET https://txnod.com/api/v1/orphan-payments — cursor-paginated list for the authenticated project. Filters by attribution status, chain, tx hash, date range, and amount range.
Request
Query parameters
| Param | Type | Required | Constraints |
|---|---|---|---|
attributed | "true" | "false" | no | — |
chain | "btc" | "eth" | "tron" | "ada" | "polygon" | "bsc" | "ton" | no | — |
tx_hash | string | no | — |
date_from | string (ISO 8601) | no | — |
date_to | string (ISO 8601) | no | — |
amount_units_gte | string | no | pattern: ^\d+$ |
amount_units_lte | string | no | pattern: ^\d+$ |
cursor | string (ULID) | no | — |
limit | integer | no | min: 1; max: 200; default: 50 |
Response
200 — Cursor-paginated orphan-payment list
| Field | Type | Required | Constraints |
|---|---|---|---|
items | array<object> | yes | — |
next_cursor | string (ULID) | no | — |
Errors
| Status | Error code(s) | Trigger |
|---|---|---|
| 400 | validation_error | Query validation error |
| 401 | auth_invalid, signature_invalid, timestamp_out_of_window | HMAC authentication failed |
| 429 | rate_limit_exceeded | Per-project rate limit exceeded |
| 500 | internal_error | Internal error |
Examples
curl "https://txnod.com/api/v1/orphan-payments?chain=btc&attributed=false&limit=50" \
-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.listOrphanPayments({ chain: 'btc', limit: 50 });
for (const orphan of page.items) console.log(orphan.tx_hash);Resolve an orphan from the dashboard
If you don’t want to call the attribution endpoint directly, resolve orphans from the dashboard:
- Open Orphan Payments in the dashboard. Filter by
attributed=falseand the relevant chain. - Identify the orphan row by matching
tx_hash,to_address,amount_units, orreceived_atagainst your ledger to find the correspondingexternal_id. - Click Attribute on the row, enter the target
external_id, and optionally auser_id/metadatablob for the synthetic invoice. - The attribution creates a synthetic invoice in
paidstatus and enqueues aninvoice.paidwebhook event indistinguishable from the real-payment path. Your normal handler processes it without any special-case code.
If the external_id is already in use for a different invoice, the dashboard surfaces external_id_conflict. If the orphan was already attributed, it surfaces orphan_already_attributed. Both are idempotent — they identify the collision cleanly and cannot cause double-fulfillment.
Attribute an orphan payment
POST https://txnod.com/api/v1/orphan-payments/{tx_hash}/attribute — attributes a previously unmatched payment to the caller-supplied external_id. Creates a synthetic invoice in paid status and enqueues an invoice.paid webhook event indistinguishable from the real-payment path. Idempotent replay with the same external_id collides via external_id_conflict. Re-attribution of an already-attributed orphan returns orphan_already_attributed.
Request
Request body (application/json)
| Field | Type | Required | Constraints |
|---|---|---|---|
external_id | string | yes | min length: 1; max length: 128 |
user_id | string | no | min length: 1; max length: 256 |
metadata | object | no | — |
to_address | string | no | min length: 1 |
tx_output_index | integer | no | min: 0 |
Response
200 — Orphan attributed; synthetic invoice returned
| Field | Type | Required | Constraints |
|---|---|---|---|
id | string (ULID) | yes | — |
project_id | string (ULID) | yes | — |
external_id | string | yes | — |
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 | — |
address | string | yes | — |
amount_crypto | string | yes | — |
amount_crypto_units | string | yes | — |
amount_usd | number | null | yes | — |
rate_snapshot | object | null | yes | — |
payment_token | string | null | yes | pattern: ^[0-9a-f]{8}$ |
payment_uri | string | yes | — |
callback_url | string | null | yes | — |
metadata | object | null | yes | — |
matching_mode | "exact" | "at_least" | "any" | yes | — |
confirmation_threshold | integer | yes | min: 0 |
status | "pending" | "detected" | "paid" | "overpaid" | "partial" | "expired" | "expired_paid_late" | "reverted" | "cancelled" | yes | — |
expires_at | integer | yes | min: 0 |
expires_at_iso | string (ISO 8601) | yes | — |
created_at | integer | yes | min: 0 |
created_at_iso | string (ISO 8601) | yes | — |
derivation_path | string | no | pattern: ^m(\/\d+'?)+$ |
verification_standard | "bip84" | "bip44" | "cip1852" | "bip44_ed25519" | no | — |
transactions | array<object> | no | — |
confirmations | integer | no | min: 0 |
Errors
| Status | Error code(s) | Trigger |
|---|---|---|
| 400 | validation_error | Validation error (e.g. ambiguous tx_hash without disambiguators) |
| 401 | auth_invalid, signature_invalid, timestamp_out_of_window | HMAC authentication failed |
| 404 | orphan_not_found | Orphan not found or belongs to a different project |
| 409 | external_id_conflict, orphan_already_attributed | external_id_conflict (external_id already in use) or orphan_already_attributed (orphan already attributed) |
| 429 | rate_limit_exceeded | Per-project rate limit exceeded |
| 500 | internal_error | Internal error (e.g. rate quote unavailable) |
Examples
curl -X POST https://txnod.com/api/v1/orphan-payments/0xabc123/attribute \
-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-42"}'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.attributeOrphanPayment('0xabc123', {
external_id: 'order-42',
});
console.log(invoice.id, invoice.status);