Settle Payment
This is the V1 API. For new integrations we recommend Settle Payment (V2), which is conformant with the x402 v2 specification.
Code
Executes on-chain settlement — submits the payment transaction to BNB Smart Chain. This operation
is irreversible. Always call /verify first to validate the payment. Gas is sponsored; the
merchant does not need to hold BNB for gas fees.
Request Body
The request body has the same structure as /verify, with one additional field:
| Field | Type | Mandatory | Remarks |
|---|---|---|---|
| x402Version | integer | Yes | x402 protocol version (currently 1) |
| paymentPayload | object | Yes | Same structure as /verify request. See Verify Payment for full field descriptions. |
| paymentRequirements | object | Yes | Same structure as /verify request. See Verify Payment for full field descriptions. |
| settleAmount | string | Only for permit2-upto | The actual amount to settle, in the token's smallest unit. Must be ≤ the authorized amount in the signature. Ignored for eip3009 and permit2-exact modes. |
Example — EIP-3009 Settle
Code
Example — Permit2 Upto Settle (with settleAmount)
Code
In this example, the buyer authorized up to 100 USDT (
"100000000") but the merchant only charges 3 USDT ("3000000") for this request.
Response Body
| Field | Type | Presence | Remarks |
|---|---|---|---|
| success | boolean | Always | Whether the settlement succeeded |
| transaction | string | When TX submitted | On-chain transaction hash. 0x-prefixed, 32-byte hex string. Present on both success and on-chain failure. |
| payer | string | Always | Payer wallet address |
| network | string | When success=true | Settlement network in CAIP-2 format (e.g. "eip155:56") |
| amount | string | When success=true | Actual settled amount in token's smallest unit. For permit2-upto, equals the requested settleAmount; for other methods, equals the full signed amount. |
| confirmations | integer | When success=true | Number of block confirmations waited |
| errorReason | string | Only when success=false | Machine-readable failure reason |
| errorMessage | string | With errorReason | Human-readable failure description; accompanies errorReason whenever that is set — including on a broadcast-but-unconfirmed Pending whose errorReason is settle_exact_evm_transaction_confirmation_timed_out. |
Settlement outcomes and polling
Settlement is processed asynchronously. /settle broadcasts the transaction and returns as soon
as it either confirms within a short synchronous window or is left awaiting on-chain confirmation —
it does not block until final confirmation. Every response is HTTP 200; inspect data to
determine which of three outcomes you received:
| Outcome | success | errorReason | transaction | What to do |
|---|---|---|---|---|
| Settled (terminal) | true | absent | tx hash | Done — payment settled. |
| Pending (not terminal) | false | absent, or settle_exact_evm_transaction_confirmation_timed_out | tx hash (present) | Broadcast, awaiting confirmation. Re-call /settle with the same request after a short delay until it becomes Settled or Failed. |
| Failed (terminal) | false | present and not the timeout code above (e.g. settle_exact_failed_onchain, a validation reason) — or the timeout code with no transaction | tx hash (on-chain revert) or absent | Done — payment failed; see errorReason. |
How to classify a V1 response. A
success: falseis still Pending (keep polling) when it carries atransactionhash and itserrorReasonis either absent orsettle_exact_evm_transaction_confirmation_timed_out(broadcast succeeded but the RPC layer could not confirm in time — the tx may already be on-chain). Any othersuccess: false— a differenterrorReason(e.g.settle_exact_failed_onchainrevert), or notransactionat all (never broadcast) — is terminal Failed.
⚠️ You must handle the Pending outcome — do not stop at the first
success: false. Asuccess: falsethat carries atransactionhash and has either noerrorReasonorerrorReason: settle_exact_evm_transaction_confirmation_timed_outmeans the payment was broadcast and is awaiting confirmation — keep polling. Treatsuccess: falseas terminal only whenerrorReasonis some other value, or when there is notransaction.
- Poll
/settle(it is idempotent — no double-charge, no re-broadcast) at ~3–5 s cadence until you receivesuccess: true(settled) or a terminalsuccess: false(per the rule above).- Poll for at least
maxTimeoutSeconds, and preferably longer.maxTimeoutSecondsis the buyer's authorization validity budget (how long the signature stays valid), not a settlement SLA: the backend confirmation job keeps reconciling a broadcast-but-unconfirmed transaction for up to ~30 minutes, so a transaction can still finalize aftermaxTimeoutSeconds. Stopping exactly atmaxTimeoutSecondsrisks missing a late confirmation and booking a settled payment as failed.errorReason: settle_exact_evm_transaction_confirmation_timed_outwith atransactionhash is non-terminal (keep polling); the same code with notransactionmeans the tx was never broadcast and is terminal.- Never key settlement success on the HTTP status — it is always
200.
Example — Successful Settlement
Code
Example — Failed Settlement
Code
Example — Pending Settlement (broadcast, awaiting confirmation)
Code
The example above is a Pending response (
success: false+ atransactionhash + noerrorReason). A Pending may also carryerrorReason: settle_exact_evm_transaction_confirmation_timed_outalongside thetransactionhash. Either way, keep re-calling/settle(idempotent) untilsuccess: true, or asuccess: falsewhoseerrorReasonis some other (terminal) value — or that has notransactionat all. See Settlement outcomes and polling.
Notes:
- An on-chain failure (e.g., nonce already used, token revert) still returns HTTP
200withcode: "000000". Check thesuccessfield indatafor the settlement outcome.- Irreversible operation. Once a settlement transaction is broadcast and confirmed on-chain, it cannot be reversed.
- Idempotent. A given
(nonce, network, payer)tuple can only be settled once. Duplicate calls return the cached result without re-broadcasting.settleAmountbehavior by mode:
eip3009/permit2-exact— thesettleAmountfield is ignored; the full signed amount is always transferred.permit2-upto—settleAmountis required and specifies the actual transfer amount. Must be ≤permit2Authorization.permitted.amount.- Settlement is asynchronous.
/settlewaits only a short synchronous window (~20 s) for confirmation: a transaction that confirms within it returnssuccess: truein a single call; otherwise it returns the Pending outcome and you poll/settleuntil it resolves (see Settlement outcomes and polling). Most small payments confirm within the window; larger payments or network congestion more often return Pending first.- Rate limit: 20 requests per second per merchant (
X-Tesla-ClientId).- All token transfers occur strictly peer-to-peer on the public blockchain from the buyer's wallet directly to the merchant's wallet. The Facilitator contract validates signatures and forwards the transfer on-chain but never holds tokens in custody.
ErrorReason Values
Machine-readable reasons returned in the errorReason field when success is false:
| Value | Description |
|---|---|
settle_exact_failed_onchain | On-chain transaction reverted |
settle_exact_evm_transaction_confirmation_timed_out | Transaction confirmation timed out. Non-terminal when returned with a transaction hash — the tx was broadcast and may still confirm, so keep polling /settle (see Settlement outcomes and polling). The same code with no transaction means the tx was never broadcast and is terminal. |
settle_exact_node_failure | BSC RPC node unavailable |
settle_service_unavailable | Settle service is temporarily unavailable |
| (any InvalidReason value) | Payment validation failed during settle — see InvalidReason Values for the full list |