Skip to main content

Settle Payment

This is the V1 API. For new integrations we recommend Settle Payment (V2), which is conformant with the x402 v2 specification.

POST /papi/v1/b402/settle

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:

FieldTypeMandatoryRemarks
x402VersionintegerYesx402 protocol version (currently 1)
paymentPayloadobjectYesSame structure as /verify request. See Verify Payment for full field descriptions.
paymentRequirementsobjectYesSame structure as /verify request. See Verify Payment for full field descriptions.
settleAmountstringOnly for permit2-uptoThe 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

{
"x402Version": 1,
"paymentPayload": {
"x402Version": 1,
"scheme": "exact",
"network": "eip155:56",
"payload": {
"signature": "0xf3746613c2d920b5fdabc0856f2aeb2d4f88ee6037b8cc5d04a71a4462f134801234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1b",
"authorization": {
"from": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
"to": "0x8B3a350e2f3E6B9cC6FB10Fd106bA08f08bec5D2",
"value": "1000000",
"validAfter": "0",
"validBefore": "1710000600",
"nonce": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
}
}
},
"paymentRequirements": {
"scheme": "exact",
"network": "eip155:56",
"amount": "1000000",
"resource": "https://api.example.com/premium/data",
"description": "Premium API access",
"payTo": "0x8B3a350e2f3E6B9cC6FB10Fd106bA08f08bec5D2",
"asset": "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d",
"maxTimeoutSeconds": 300,
"extra": {
"name": "USD Coin",
"version": "2",
"assetTransferMethod": "eip3009",
"facilitatorAddress": "0x1111111111111111111111111111111111111111"
}
}
}

Example — Permit2 Upto Settle (with settleAmount)

{
"x402Version": 1,
"paymentPayload": {
"x402Version": 1,
"scheme": "exact",
"network": "eip155:56",
"payload": {
"signature": "0x112233...65bytes...4455",
"permit2Authorization": {
"permitted": {
"token": "0x55d398326f99059ff775485246999027b3197955",
"amount": "100000000"
},
"from": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
"spender": "0x3333333333333333333333333333333333333333",
"nonce": "5",
"deadline": "1710086400",
"witness": {
"to": "0x8B3a350e2f3E6B9cC6FB10Fd106bA08f08bec5D2",
"facilitator": "0x1111111111111111111111111111111111111111",
"validAfter": "0"
}
}
}
},
"paymentRequirements": {
"scheme": "exact",
"network": "eip155:56",
"amount": "100000000",
"resource": "https://ai.example.com/api/v1/chat",
"description": "AI Agent API - per-request billing",
"payTo": "0x8B3a350e2f3E6B9cC6FB10Fd106bA08f08bec5D2",
"asset": "0x55d398326f99059ff775485246999027b3197955",
"maxTimeoutSeconds": 300,
"extra": {
"name": "Tether USD",
"version": "1",
"assetTransferMethod": "permit2-upto",
"facilitatorAddress": "0x3333333333333333333333333333333333333333"
}
},
"settleAmount": "3000000"
}

In this example, the buyer authorized up to 100 USDT ("100000000") but the merchant only charges 3 USDT ("3000000") for this request.

Response Body

FieldTypePresenceRemarks
successbooleanAlwaysWhether the settlement succeeded
transactionstringWhen TX submittedOn-chain transaction hash. 0x-prefixed, 32-byte hex string. Present on both success and on-chain failure.
payerstringAlwaysPayer wallet address
networkstringWhen success=trueSettlement network in CAIP-2 format (e.g. "eip155:56")
amountstringWhen success=trueActual settled amount in token's smallest unit. For permit2-upto, equals the requested settleAmount; for other methods, equals the full signed amount.
confirmationsintegerWhen success=trueNumber of block confirmations waited
errorReasonstringOnly when success=falseMachine-readable failure reason
errorMessagestringWith errorReasonHuman-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:

OutcomesuccesserrorReasontransactionWhat to do
Settled (terminal)trueabsenttx hashDone — payment settled.
Pending (not terminal)falseabsent, or settle_exact_evm_transaction_confirmation_timed_outtx hash (present)Broadcast, awaiting confirmation. Re-call /settle with the same request after a short delay until it becomes Settled or Failed.
Failed (terminal)falsepresent and not the timeout code above (e.g. settle_exact_failed_onchain, a validation reason) — or the timeout code with no transactiontx hash (on-chain revert) or absentDone — payment failed; see errorReason.

How to classify a V1 response. A success: false is still Pending (keep polling) when it carries a transaction hash and its errorReason is either absent or settle_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 other success: false — a different errorReason (e.g. settle_exact_failed_onchain revert), or no transaction at all (never broadcast) — is terminal Failed.

⚠️ You must handle the Pending outcome — do not stop at the first success: false. A success: false that carries a transaction hash and has either no errorReason or errorReason: settle_exact_evm_transaction_confirmation_timed_out means the payment was broadcast and is awaiting confirmation — keep polling. Treat success: false as terminal only when errorReason is some other value, or when there is no transaction.

  • Poll /settle (it is idempotent — no double-charge, no re-broadcast) at ~3–5 s cadence until you receive success: true (settled) or a terminal success: false (per the rule above).
  • Poll for at least maxTimeoutSeconds, and preferably longer. maxTimeoutSeconds is 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 after maxTimeoutSeconds. Stopping exactly at maxTimeoutSeconds risks missing a late confirmation and booking a settled payment as failed.
  • errorReason: settle_exact_evm_transaction_confirmation_timed_out with a transaction hash is non-terminal (keep polling); the same code with no transaction means the tx was never broadcast and is terminal.
  • Never key settlement success on the HTTP status — it is always 200.

Example — Successful Settlement

{
"code": "000000",
"message": "success",
"data": {
"success": true,
"transaction": "0x89c91c789e57059b17285e7ba1716a1f5ff4c5dace0ea5a5135f26158d0421b9",
"payer": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
"network": "eip155:56",
"amount": "1000000",
"confirmations": 3
}
}

Example — Failed Settlement

{
"code": "000000",
"message": "success",
"data": {
"success": false,
"errorReason": "settle_exact_failed_onchain",
"errorMessage": "Transaction reverted: authorization is used",
"payer": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
"transaction": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
}
}

Example — Pending Settlement (broadcast, awaiting confirmation)

{
"code": "000000",
"message": "success",
"data": {
"success": false,
"payer": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
"transaction": "0x89c91c789e57059b17285e7ba1716a1f5ff4c5dace0ea5a5135f26158d0421b9"
}
}

The example above is a Pending response (success: false + a transaction hash + no errorReason). A Pending may also carry errorReason: settle_exact_evm_transaction_confirmation_timed_out alongside the transaction hash. Either way, keep re-calling /settle (idempotent) until success: true, or a success: false whose errorReason is some other (terminal) value — or that has no transaction at all. See Settlement outcomes and polling.

Notes:

  • An on-chain failure (e.g., nonce already used, token revert) still returns HTTP 200 with code: "000000". Check the success field in data for 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.
  • settleAmount behavior by mode:
    • eip3009 / permit2-exact — the settleAmount field is ignored; the full signed amount is always transferred.
    • permit2-uptosettleAmount is required and specifies the actual transfer amount. Must be ≤ permit2Authorization.permitted.amount.
  • Settlement is asynchronous. /settle waits only a short synchronous window (~20 s) for confirmation: a transaction that confirms within it returns success: true in a single call; otherwise it returns the Pending outcome and you poll /settle until 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:

ValueDescription
settle_exact_failed_onchainOn-chain transaction reverted
settle_exact_evm_transaction_confirmation_timed_outTransaction 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_failureBSC RPC node unavailable
settle_service_unavailableSettle service is temporarily unavailable
(any InvalidReason value)Payment validation failed during settle — see InvalidReason Values for the full list