This guide describes the recommended x402 V2 merchant flow. B402 calls must come from your trusted backend and use the Web3 API Key created for the same Developer Portal project that completed B402 onboarding.
Portal Onboarding and Runtime API
The Developer Portal and the B402 runtime API serve different purposes:
| Stage | Where it happens | What to use |
|---|---|---|
| Onboarding | Developer Portal | Select a project, complete the B402 Payments application, and configure the write-once payTo address. |
| Key setup | Developer Portal | Create an API Key in the same project with B402 Payments permission. If enabled, allow your backend's public egress IP. |
| Runtime | Merchant backend | Sign and call https://web3.binance.com/build/api/v2/b402/* with the API Key and Secret Key. |
Do not copy the Portal's onboarding request into your backend. Public runtime
calls must not send apiKey or projectCode query parameters, merchantId,
X-OC-Tenant-Id, or X-OC-User-Id. The Web3 gateway derives the project and
account identity from the authenticated API Key.
1. Create and Configure a B402-Enabled API Key
In the same Developer Portal project that completed B402 onboarding:
- Open API Key Management and select Add New Key.
- Enter a key name. On the API permissions step, select B402 Payments before creating the key. A key without this option cannot call any B402 endpoint.
- If you configure an IP whitelist, add the stable public egress IP of the backend that will call B402. Do not add a private, local, or end-user IP.
- When the success dialog appears, store both displayed values in your backend's secret manager. The Secret Key is shown only once; create or rotate the API Key if it is lost.
| Portal value | Suggested backend setting | How B402 uses it |
|---|---|---|
| API Key | OC_API_KEY | Send as the X-OC-APIKEY header. |
| Secret Key | OC_SECRET_KEY | Use as the HMAC-SHA256 signing key. Never include it in a URL, header, or body. |
| Project | No request setting | The Web3 gateway derives it from the API Key; do not send projectCode. |
payTo | Application configuration | Use the write-once onboarding address in HTTP 402 payment requirements. |
Keep these credentials in a trusted backend. Never put the Secret Key in browser or mobile code, commit it to source control, or paste it into a client-side request.
Authenticate Web3 Requests
Every B402 request uses the standard Binance Web3 HMAC authentication headers:
X-OC-APIKEYX-OC-TIMESTAMPX-OC-SIGN- Optional:
X-OC-RECV-WINDOWandX-OC-NONCE
Follow Authentication exactly. The signed request path includes /build, and the
signature must use the exact raw JSON string sent on the wire.
B402 uses an outer request envelope. Sign and send {"body": ...}, not only the inner x402
object. Re-serializing the JSON after signing changes the request bytes and invalidates the
signature.
The Web3 gateway resolves the B402 merchant from the authenticated project's tenant identity. Do not
send or trust a client-supplied merchantId for Portal traffic.
2. Test the API Key with Supported
The following Node.js 18+ example is ready to use after OC_API_KEY and OC_SECRET_KEY are
supplied through your local or deployment secret configuration. Do not change the host or remove
/build from requestPath:
Code
The helper accepts the object that belongs inside body and creates the outer {"body": ...}
envelope once. It also signs and sends the same rawBody string. Reuse it for the other operations:
Code
For permit2-upto, add settleAmount to the inner Settle object shown above.
Read and Cache Supported Configurations
Call POST /api/v2/b402/supported when your service starts, then refresh periodically. An empty
Supported request is:
Code
The response contains kinds[], extensions, and signers. Select a kind matching the asset and
transfer method you want to accept. Copy the entire matching kinds[].extra object into the
paymentRequirements.extra object returned to the buyer.
Use this first Supported call as a readiness check:
- A successful response has envelope code
000000000. 1160401means the same Developer Portal project has not completed B402 onboarding.- Gateway code
40104means an access policy rejected the call. Check the B402 Payments permission and API Key IP whitelist first; if both are correct, contact support to check the endpoint allowlist.
Do not hardcode signerAddress, spenderAddress, EIP-712 name, or
version. They can change when facilitator configuration or Permit2 proxy
contracts are upgraded.
3. Return HTTP 402 to the Buyer
When payment is required, return an x402 V2 response such as:
Code
Amounts are decimal strings in the token's smallest unit. payTo must be the receiving address
configured during B402 onboarding.
4. Receive the Signed Payment Payload
The buyer selects one requirement, signs its authorization, and retries the resource request with an
x402 payment payload. Keep the original payment requirements server-side; do not let the buyer
replace the amount, asset, network, payTo, timeout, or extra values.
Your backend must reject the buyer payload unless paymentPayload.accepted exactly matches the
server-held paymentRequirements. Then send both objects unchanged to B402. The transfer-specific
signed data is under paymentPayload.payload:
authorizationforeip3009.permit2Authorizationforpermit2-exactandpermit2-upto.
5. Verify Before Settlement
Send the buyer payload and your original requirements to POST /api/v2/b402/verify:
Code
Verify is off-chain and does not spend funds. Proceed only when data.isValid is true. A business
validation failure still uses HTTP 200; inspect data.isValid, data.invalidReason, and the
optional data.invalidMessage rather than relying only on the HTTP status.
6. Settle the Payment
Call POST /api/v2/b402/settle with the same body. For permit2-upto, also include
body.settleAmount, which must not exceed the authorized paymentRequirements.amount.
Settlement submits an on-chain transaction and is irreversible. Treat it as successful only when
data.success is true.
success: true: recordtransaction,payer,network, andamount, then deliver the resource.success: falsewith a non-emptytransaction: the transaction was broadcast; poll or reconcile before deciding whether to retry.success: falsewith an emptytransaction: terminal pre-broadcast failure; useerrorReason.
Settle is idempotent for the same signed authorization. Use bounded retries with backoff for transient failures, but never create a fresh buyer authorization automatically.
Operational Guidance
- Keep host clocks synchronized; stale timestamps are rejected.
- Persist settlement results using the signed authorization or transaction hash as an idempotency key.
- Log request IDs and transaction hashes, but never signatures, API secrets, or full authorization payloads.
- Build alerting around
invalidReason,errorReason, HTTP 429, and infrastructure errors. - Use Verify for every payment; do not deliver value based only on a buyer-provided signature.