x402 Payment
Pay for an x402 HTTP resource by previewing payment options, then signing one.
x402-payment preview
Preview payment options from a Merchant's PaymentRequired response.
Syntax
baw x402-payment preview --paymentRequirements <base64-or-raw-json> --json
Parameters
| Parameter |
Required |
Description |
--paymentRequirements |
Yes |
The PaymentRequired payload — either the base64 PAYMENT-REQUIRED header value or its raw JSON. |
Example
baw x402-payment preview --paymentRequirements '{
"x402Version": 2,
"resource": {"url": "https://merchant/api"},
"accepts": [
{
"scheme": "exact",
"network": "eip155:8453",
"asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"amount": "10000000",
"payTo": "0x1111111111111111111111111111111111111111",
"extra": {"name": "USD Coin", "version": "2"}
},
{
"scheme": "exact",
"network": "eip155:56",
"asset": "0x55d398326f99059fF775485246999027B3197955",
"amount": "10000000000000000000",
"payTo": "0x1111111111111111111111111111111111111111",
"extra": {"name": "Tether USD", "version": "1"}
},
{
"scheme": "exact",
"network": "eip155:42161",
"asset": "0xcaca...1231",
"amount": "10000000",
"payTo": "0x1111111111111111111111111111111111111111",
"extra": {"name": "USD Coin", "version": "2"}
}
]
}' --json
Response
{
"success": true,
"data": {
"paymentId": "550e8400-e29b-41d4-a716-446655440000",
"options": [
{
"index": 1,
"status": "READY_TO_SIGN",
"reasons": [],
"scheme": "exact",
"assetTransferMethod": "eip3009",
"binanceChainId": "8453",
"tokenAddress": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"tokenSymbol": "USDC",
"amount": "10",
"amountUsd": "10.00",
"payTo": "0x1111111111111111111111111111111111111111",
"userWalletAddress": "0x2222222222222222222222222222222222222222",
"currentBalance": "100",
"currentBalanceUsd": "100.00",
"needApproveFirst": false,
"originalAccept": {
"scheme": "exact",
"network": "eip155:8453",
"asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"amount": "10000000",
"payTo": "0x1111111111111111111111111111111111111111",
"extra": {
"name": "USD Coin",
"version": "2"
}
}
},
{
"index": 2,
"status": "ACTION_REQUIRED",
"reasons": [
"INSUFFICIENT_BALANCE"
],
"scheme": "exact",
"assetTransferMethod": "eip3009",
"binanceChainId": "56",
"tokenAddress": "0x55d398326f99059fF775485246999027B3197955",
"tokenSymbol": "USDT",
"amount": "10",
"amountUsd": "10.01",
"payTo": "0x1111111111111111111111111111111111111111",
"userWalletAddress": "0x2222222222222222222222222222222222222222",
"currentBalance": "1.5",
"currentBalanceUsd": "1.50",
"needApproveFirst": false,
"originalAccept": {
"scheme": "exact",
"network": "eip155:56",
"asset": "0x55d398326f99059fF775485246999027B3197955",
"amount": "10000000000000000000",
"payTo": "0x1111111111111111111111111111111111111111",
"extra": {
"name": "Tether USD",
"version": "1"
}
}
},
{
"index": 3,
"status": "NOT_SIGNABLE",
"reasons": [
"UNSUPPORTED_NETWORK"
],
"scheme": "exact",
"originalAccept": {
"scheme": "exact",
"network": "eip155:42161",
"asset": "0xcaca...1231"
}
}
]
}
}
| Field |
Description |
paymentId |
UUID identifying this payment. |
options[].index |
1-based selector (first option is 1, not 0) to pass to sign --selectedIndex. |
options[].status |
The option's status, which drives the next step. See table below. |
options[].reasons |
Reasons the option isn't ready to sign. See table below. |
options[].scheme |
x402 scheme, such as exact. |
options[].assetTransferMethod |
Asset transfer method, such as eip3009, permit2, spl-transfer, etc. |
options[].binanceChainId |
Binance chain ID: 56 (BSC), CT_501 (Solana). |
options[].tokenAddress |
Token contract address. |
options[].tokenSymbol |
Token symbol, e.g. USDT. |
options[].amount |
Amount of tokens to pay, in human-readable units. |
options[].amountUsd |
Equivalent USD value at the current token price. |
options[].payTo |
Recipient (Merchant) address. |
options[].userWalletAddress |
User's own wallet address on this chain. |
options[].currentBalance |
User's current balance of tokenAddress, in human-readable units. |
options[].currentBalanceUsd |
Equivalent USD value of currentBalance at the current token price. |
options[].needApproveFirst |
Whether a Permit2 approve tx is required before this payment. If true, sign will dispatch the approve tx alongside the signature — on BSC the approve gas is sponsored. |
options[].originalAccept |
The Merchant's original accept entry. |
options[].status values:
| Value |
Meaning |
READY_TO_SIGN |
Can be signed directly. No user action required. |
ACTION_REQUIRED |
Can only be signed after the user takes some action. |
NOT_SIGNABLE |
Cannot be signed. Retrying won't help. |
options[].reasons values:
| Value |
Implied status |
Meaning |
INSUFFICIENT_BALANCE |
ACTION_REQUIRED |
The user's balance of tokenAddress on this chain is below amount. |
INVALID_ACCEPT_STRUCTURE |
NOT_SIGNABLE |
The Merchant's original accept structure is invalid. |
UNSUPPORTED_NETWORK |
NOT_SIGNABLE |
The accept's network is outside our supported set. |
UNSUPPORTED_SCHEME |
NOT_SIGNABLE |
The accept's scheme is outside our supported set. |
UNSUPPORTED_METHOD |
NOT_SIGNABLE |
The accept's assetTransferMethod is outside our supported set: eip3009, permit2, spl-transfer. |
NO_WALLET_ON_CHAIN |
NOT_SIGNABLE |
The user's agentic wallet has no address on this chain. |
BLOCKED_BY_SECURITY_CHECK |
NOT_SIGNABLE |
Security check flagged the payment as risky. |
BLOCKED_DAILY_LIMIT_REACHED |
NOT_SIGNABLE |
The user's daily x402 spending limit has been reached. |
Acting on preview result
- The returned options are pre-sorted; options earlier in the list are recommended over later ones.
- Only options with
status = READY_TO_SIGN can be signed directly. ACTION_REQUIRED options can be signed after the user takes a remediation action; NOT_SIGNABLE options cannot be signed.
x402-payment sign
Sign a payment option from preview and return the replay x402 header.
Syntax
baw x402-payment sign --paymentId <payment-id> --selectedIndex <index> --json
Parameters
| Parameter |
Required |
Description |
--paymentId |
Yes |
The paymentId returned by preview. |
--selectedIndex |
Yes |
The selected option index returned by preview. Must not be NOT_SIGNABLE. |
Example
baw x402-payment sign --paymentId 550e8400-e29b-41d4-a716-446655440000 --selectedIndex 1 --json
Response
{
"success": true,
"data": {
"paymentHeaderName": "PAYMENT-SIGNATURE",
"paymentHeaderValue": "eyJ4NDAyVmVyc2lvbiI6Mi...",
"approveTxHash": null,
"binanceChainId": null,
"signatureExpiresAt": 1747900800
}
}
| Field |
Description |
paymentHeaderName |
HTTP header name to use when replaying. For x402 v2 this is always PAYMENT-SIGNATURE. |
paymentHeaderValue |
HTTP header value to use when replaying. Set this as the paymentHeaderName header on the request to the Merchant. |
approveTxHash |
Non-null only when this sign also dispatched a Permit2 approve tx. See Replaying the Request. |
binanceChainId |
Binance chain ID where approveTxHash was dispatched. Null when no approve was dispatched. |
signatureExpiresAt |
Unix epoch seconds (UTC) after which the signature is no longer valid. See Replaying the Request. |
Replaying the Request
- Replay the original HTTP request with the
paymentHeaderName: paymentHeaderValue header from sign attached.
- Construct the replay request using the schema from the x402 payment requirements'
extensions field if available.
- If
approveTxHash is non-null (Permit2), wait for it to confirm (e.g. baw wallet tx-history --tx <hash>) before replaying.
- A signature can only be used once and is valid until
signatureExpiresAt. If exceeded, restart from preview.
- The
PAYMENT-RESPONSE response header (base64 JSON) carries settlement metadata, including the txHash.
- Infer the response body's schema before parsing it; don't parse blindly.
Guardrails
- Confirm before signing. Confirm with the user before calling
sign and only proceed once they've consented, unless the user explicitly asks to skip confirmation.
- Confirm before signing another payment option. Confirm with the user before switching to a different payment option, network, or token, and only proceed once they've consented, unless the user explicitly asks to skip confirmation.
- Confirm before changing to a new resource. Only pay for a different resource or service when the user has named it — never silently substitute; if the current one fails, report the error and let the user decide. When the user does name a new resource, confirm before paying, unless they explicitly ask to skip confirmation.
- Confirm before retrying more than once. If replaying the request fails due to a network or unknown error, retry at most once automatically. Before any further retries, confirm with the user, unless the user explicitly asks to skip confirmation.
Limitations
- Only x402 v2 is supported.
- Only BSC, Base, and Solana are supported. Ethereum is not supported.