List payments
An invalid
from or to returns 400 BCK.ROUTER.0001 rather than silently ignoring the filter.
amount is in the asset’s smallest unit, and assetDecimals is the scale to divide it by. The figure charged against your Delegation cap is the cents equivalent, rounded up, which is why a long run of sub-cent calls costs more budget than the raw amounts suggest.
Reading the asset
Three fields describe what was paid in, because the raw one isn’t the same kind of value on every rail:assetSymbol and assetDecimals are resolved when you read the record rather than stored on it, so rows written before they existed carry them too.
The routing fee on a record
amount is the merchant leg only. If a routing fee applied, it was reserved against your cap on top of that amount, and the record breaks it out:
The routing fee is 5% (
feeBps: 500). Two cases legitimately read feeStatus: "None" with a zero fee: an MPP payment, since that rail cannot carry a fee at all, and a mode-A call made without a requestId — without one a retry cannot be deduplicated, so collecting would risk double-charging. Mode B always carries a requestId, so it always collects.
This is why merchant amounts and spent budget don’t reconcile on their own.
amount on this record is the merchant leg, so the combined cap charge isn’t derivable from the ledger alone. It’s recorded as amountCents on GET /api/v1/delegation/{id}/transactions, with the fee broken out in that row’s providerMetadata.If the fee is later Released, that row’s amountCents is reduced by the fee and providerMetadata.feeReleased: true is set — but the feeCents breakout stays. So when that flag is present, don’t add the breakout back on top: the total has already moved.Auditing the fee leg
feeTxHash and feeNonce are what make the fee movement auditable on its own, and each answers a different question.
feeTxHash is not txHash. txHash anchors the merchant leg; feeTxHash anchors the fee leg. They are independent movements that settle separately — one can land while the other hasn’t — so reconcile them separately rather than reading either as evidence of the other. Like txHash, it is recorded verbatim as the settling party reported it, so treat it as an anchor to verify rather than as proof, and don’t assume a 0x shape.
feeNonce is the key that ties an on-chain transfer back to this payment. EIP-3009 records every authorization under authorizationState(payer, nonce), so with the nonce you can ask the chain directly whether that specific fee movement was consumed — which is exactly how a Submitted fee is resolved. It is not spendable on its own: a nonce identifies an authorization, it isn’t one. The signed authorization itself is deliberately never stored.
A
Settled fee can carry feeTxHash: null, and that isn’t a bug. When the fee is confirmed by reading authorizationState rather than by observing the settlement, the chain answers with a boolean — consumed or not — and there is no transaction to record. On those rows feeNonce is the audit key; use it rather than the missing hash.Fee lifecycle
Released is the one that returns budget to you. It’s reached when the fee provably will not be collected — the facilitator adjudicated and refused, a mode-B hop never returned 2xx, or the fee movement couldn’t be signed — and the fee’s cents go back on your Delegation cap and on the ledgers that mirrored it (an org group budget is corrected separately, and can lag). A fee that applied atomically but added no cent still lands here, with nothing to credit back. It’s only ever reached from Accrued or an adjudicated Failed — never from Submitted or Settled, where money may have moved or definitely did, and handing back headroom for money that already left your wallet is the one direction this must never fail in.
Export
Aggregate summary
For dashboards and spend monitoring,GET /api/v1/router/payments/summary returns a total plus a time series instead of individual rows.
granularity is day (default), week, or month; an unrecognised value falls back to day rather than erroring. from and to work as above. Buckets are oldest first.
The summary counts payment requests, not amounts. Use the list endpoint when you need money rather than volume.
Record statuses
status describes the merchant leg. A routing fee has its own feeStatus, and the two move independently — see the routing fee on a record.
Closing a mode-A record
In mode A the Router only signs — it never sees the merchant’s response, so it can’t know whether you redeemed the credential. Report the settlement to close the record:PAYMENT-RESPONSE header. Two things to know:
- Only an
Issuedpayment can be settled. Re-reporting the same hash is a harmless no-op; a different hash, or a record that isn’tIssued, returns409 BCK.ROUTER.0005. - A payment id that isn’t yours returns
404 BCK.ROUTER.0004.
Reconciling against the chain
The settlement reference is reported by the merchant and stored unverified. The Router bounds its length and character set, but it does not confirm on-chain that the transaction exists, that it paid the expected recipient, or that it moved the expected amount. So for anything that matters — accounting, disputes, anomaly detection — treattxHash as an anchor to verify, not as proof. Check it against the chain named in the record’s network field.
Note also that a non-0x reference is legitimate: settlement identifiers are protocol-specific, and non-blockchain rails return processor references rather than transaction hashes. Don’t assume the field is always a hash.
Next
Guardrails
Every error code, and what to do about each.
Overview
Back to the top.