HTTP API — One-time Payment
This page is the API reference for one-time payment, covering the full interface definitions for both exact and charge schemes. For usage guides and SDK integration examples, see One-time payment · Integration docs.
exact or charge?
exact — single recipient, supports both sync and async settlement.
charge — supports a single recipient too, plus splits, i.e. one payment to multiple addresses (≤10). Defaults to and only supports sync settlement.
| Dimension | exact | charge |
|---|
| Recipient | Single | Single / one-payment-to-multiple-addresses (≤10) |
| Settlement timing | Sync / async | Default and sync only |
| Integration guide | exact path | charge path |
- Base URL:
https://web3.okx.com
exact path prefix: /api/v6/pay/x402
charge path prefix: /api/v6/pay/mpp/charge
- Network: X Layer (chainId
196, CAIP-2 identifier eip155:196)
Authentication
All endpoints require API Key authentication. The following headers must be provided:
| Header | Required | Description |
|---|
OK-ACCESS-KEY | Yes | API Key |
OK-ACCESS-SIGN | Yes | Request signature |
OK-ACCESS-PASSPHRASE | Yes | API passphrase |
OK-ACCESS-TIMESTAMP | Yes | ISO 8601 timestamp |
Content-Type | Yes | application/json for POST requests |
All responses use a unified envelope:
On business errors, code is non-"0" and data is null. See the Error codes section at the end of this page.
exact Scheme
1. /api/v6/pay/x402/supported
GET
/api/v6/pay/x402/supported
Query the schemes, networks, and signers supported by the Broker. The Seller SDK calls this endpoint to construct the accepts array of the 402 response.
Request parameters
None.
Response parameters
| Parameter | Type | Description |
|---|
kinds | Array<SupportedKind> | Supported payment-type list |
kinds[].x402Version | Integer | Protocol version, e.g. 2 |
kinds[].scheme | String | Settlement scheme: exact / aggr_deferred |
kinds[].network | String | CAIP-2 network identifier, e.g. eip155:196 |
kinds[].extra | Object | Scheme-specific extension config |
extensions | Array<String> | Supported extension identifiers |
signers | Object | CAIP-2 wildcard → array of signer addresses |
Request example
Response example
2. /api/v6/pay/x402/verify
POST
/api/v6/pay/x402/verify
Validate the Buyer's signed payment authorization. No on-chain transaction is executed.
Request parameters
| Parameter | Type | Required | Description |
|---|
x402Version | Integer | Yes | Protocol version, e.g. 2 |
paymentPayload | Object | Yes | The payment payload the client sends with the protected request. See PaymentPayload |
paymentRequirements | Object | Yes | The Seller-defined payment requirements. See PaymentRequirements |
Constraint: paymentPayload.accepted.scheme and paymentRequirements.scheme must both be "exact".
Response parameters
| Parameter | Type | Description |
|---|
isValid | Boolean | true = passed, false = failed |
invalidReason | String | Machine-readable invalid reason (returned on failure) |
invalidMessage | String | Human-readable invalid message (returned on failure) |
payer | String | Payer wallet address |
Request example
Response example — verification passed
Response example — verification failed
3. /api/v6/pay/x402/settle
POST
/api/v6/pay/x402/settle
After verification passes, submit the on-chain settlement. In exact mode, each call initiates an independent on-chain transferWithAuthorization transaction.
Request parameters
| Parameter | Type | Required | Description |
|---|
x402Version | Integer | Yes | Protocol version, e.g. 2 |
paymentPayload | Object | Yes | Same as verify |
paymentRequirements | Object | Yes | Same as verify |
syncSettle | Boolean | No | OKX extension. true = wait for on-chain confirmation; false (default) = async broadcast |
Response parameters
| Parameter | Type | Description |
|---|
success | Boolean | Whether settlement succeeded |
errorReason | String | Machine-readable failure reason (returned on failure) |
errorMessage | String | Human-readable failure message (returned on failure) |
payer | String | Payer wallet address |
transaction | String | On-chain transaction hash |
network | String | CAIP-2 network identifier |
status | String | OKX extension. Settlement status — see table below |
status values:
syncSettle | Result | status | transaction |
|---|
false (default) | Broadcast | pending | txHash |
true | Confirmed on-chain | success | txHash |
true | Wait timeout | timeout | txHash |
| — | Verify / simulation / on-chain failure | "" | "" |
Request example
Response example — sync settle success (syncSettle=true)
Response example — async settle (syncSettle=false)
Response example — settle failure
4. /api/v6/pay/x402/settle/status
GET
/api/v6/pay/x402/settle/status
Query settlement status by on-chain transaction hash — used for polling in async settlement (syncSettle=false).
Request parameters
| Parameter | Location | Type | Required | Description |
|---|
txHash | query | String | Yes | On-chain transaction hash |
Response parameters
| Parameter | Type | Description |
|---|
success | Boolean | Whether the query succeeded (false if txHash not found) |
errorReason | String | Machine-readable failure reason |
errorMessage | String | Human-readable failure message |
payer | String | Payer wallet address |
transaction | String | On-chain transaction hash |
network | String | CAIP-2 network identifier |
status | String | Current settlement status: pending / success / failed |
Request example
Response example — query success
Response example — transaction not found
charge Scheme
charge provides one-time token transfer based on an HTTP 402 Challenge-Credential flow.
- Server-side payment (transaction mode): the Buyer signs an EIP-3009 authorization, and the Broker submits the on-chain transaction on their behalf
- Client-side payment (hash mode): the Buyer broadcasts the on-chain transaction themselves, and the Broker verifies its validity
5. /api/v6/pay/mpp/charge/settle
POST
/api/v6/pay/mpp/charge/settle
Server-side payment — submit the on-chain ERC-20 transfer on behalf of the user. Supports the EIP-3009 authorization scheme and splits (up to 10).
Request parameters
| Parameter | Type | Required | Description |
|---|
challenge | Object | Yes | The Challenge object issued by the server (echo back as-is). See Challenge |
payload | Object | Yes | EVM payment receipt |
payload.type | String | Yes | Always "transaction" |
payload.authorization | Object | Yes | EIP-3009 authorization object |
payload.authorization.type | String | Yes | Always "eip-3009" |
payload.authorization.from | String | Yes | Payer wallet address |
payload.authorization.to | String | Yes | Recipient wallet address |
payload.authorization.value | String | Yes | Payment amount (base units) |
payload.authorization.validAfter | String | Yes | Authorization start Unix timestamp |
payload.authorization.validBefore | String | Yes | Authorization expiry Unix timestamp |
payload.authorization.nonce | String | Yes | Random bytes32, unique per authorization |
payload.authorization.signature | String | Yes | 65-byte EIP-712 signature (r‖s‖v) |
payload.authorization.splits | Array | No | Splits list (max 10). See Split |
source | String | No | Payer DID (did:pkh:eip155:196:0x...) |
Response parameters
| Parameter | Type | Description |
|---|
method | String | Always "evm" |
reference | String | On-chain transaction hash (0x-prefixed) |
status | String | Always "success" |
timestamp | String | RFC 3339 settlement time |
chainId | Integer | Settlement chain ID, e.g. 196 |
challengeId | String | Challenge ID, for client correlation |
externalId | String | Echoed merchant order ID from the Challenge request |
Request example
Response example
Request example — with splits
6. /api/v6/pay/mpp/charge/verifyHash
POST
/api/v6/pay/mpp/charge/verifyHash
Client-side payment — verify that the on-chain transaction broadcast by the client matches the payment requirements in the Challenge.
Request parameters
| Parameter | Type | Required | Description |
|---|
challenge | Object | Yes | The Challenge object issued by the server (echo back as-is). See Challenge |
payload | Object | Yes | Payment receipt |
payload.type | String | Yes | Always "hash" |
payload.hash | String | Yes | The on-chain transaction hash already broadcast by the client |
source | String | Yes | Payer DID (did:pkh:eip155:196:0x...) |
Response parameters
| Parameter | Type | Description |
|---|
method | String | Always "evm" |
reference | String | On-chain transaction hash (0x-prefixed) |
status | String | Always "success" |
timestamp | String | RFC 3339 confirmation time |
chainId | Integer | Chain ID, e.g. 196 |
challengeId | String | Challenge ID, for client correlation |
externalId | String | Echoed merchant order ID from the Challenge request |
Request example
Response example
Common data structures
PaymentPayload
After signing, the Buyer passes this through the X-PAYMENT header (base64-encoded) to the Seller, who forwards it as-is to the Broker.
| Parameter | Type | Required | Description |
|---|
x402Version | Integer | Yes | Protocol version, e.g. 2 |
resource | Object | No | Protected-resource description |
resource.url | String | Yes | The URL of the protected resource |
resource.description | String | No | Resource description |
resource.mimeType | String | No | Expected response MIME type |
accepted | Object | Yes | The payment option chosen by the Buyer (selected from the accepts array). Same shape as PaymentRequirements |
payload | Object | Yes | Signed data |
payload.signature | String | Yes | EIP-712 signature (EOA signature) |
payload.authorization | Object | Yes | EIP-3009 authorization parameters. See Authorization |
PaymentRequirements
Used both as an entry of the 402 response accepts array and as paymentPayload.accepted.
| Parameter | Type | Required | Description |
|---|
scheme | String | Yes | Always "exact" |
network | String | Yes | CAIP-2 network identifier, e.g. eip155:196 |
amount | String | Yes | Payment amount (atomic-unit string) |
asset | String | Yes | Token contract address |
payTo | String | Yes | Recipient wallet address |
maxTimeoutSeconds | Integer | No | Max payment-completion timeout (seconds) |
extra | Object | No | Scheme-specific extension (e.g. name / version) |
Authorization
| Parameter | Type | Required | Description |
|---|
from | String | Yes | Payer wallet address (EOA) |
to | String | Yes | Recipient wallet address (must equal payTo) |
value | String | Yes | Payment amount (atomic units, must equal amount) |
validAfter | String | Yes | Authorization start Unix timestamp |
validBefore | String | Yes | Authorization expiry Unix timestamp |
nonce | String | Yes | 32-byte random nonce (0x hex, anti-replay) |
Challenge
The Challenge object issued by the server, echoed back by the client as-is.
| Parameter | Type | Required | Description |
|---|
id | String | Yes | Challenge ID |
realm | String | Yes | Protection space identifier |
method | String | Yes | Always "evm" |
intent | String | Yes | Payment intent: "charge" / "session" |
request | String | Yes | base64url-encoded request parameters |
expires | String | Yes | Expiry time (ISO 8601) |
Split
A single split entry in the Charge splits list — each requires its own signature.
| Parameter | Type | Required | Description |
|---|
from | String | Yes | Payer address (same as primary signature) |
to | String | Yes | Split recipient address |
value | String | Yes | Split amount (base units) |
validAfter | String | Yes | Authorization start Unix timestamp |
validBefore | String | Yes | Authorization expiry Unix timestamp |
nonce | String | Yes | Independent nonce (bytes32) |
signature | String | Yes | 65-byte EIP-712 signature |
Supported networks and tokens
| Network | Chain Index | Status |
|---|
| X Layer | 196 | Supported |
Stablecoins supported on X Layer:
| Token | Contract address |
|---|
| USDG | 0x4ae46a509f6b1d9056937ba4500cb143933d2dc8 |
| USD₮0 | 0x779ded0c9e1022225f8e0630b35a9b54be713736 |
Error codes
Error responses use the unified envelope {"code": "<code>", "msg": "<message>", "data": null}.
1. Authentication errors (HTTP 401)
| Code | Description |
|---|
| 50103 | Header OK-ACCESS-KEY cannot be empty |
| 50104 | Header OK-ACCESS-PASSPHRASE cannot be empty |
| 50105 | Header OK-ACCESS-PASSPHRASE is invalid |
| 50106 | Header OK-ACCESS-SIGN cannot be empty |
| 50107 | Header OK-ACCESS-TIMESTAMP cannot be empty |
| 50111 | Invalid OK-ACCESS-KEY |
| 50112 | Invalid OK-ACCESS-TIMESTAMP |
| 50113 | Invalid signature |
2. Request errors
| Code | HTTP status | Description |
|---|
| 50011 | 429 | User request rate exceeds the per-endpoint limit |
| 50014 | 400 | Required parameter {param} cannot be empty |
3. Business errors
| Code | HTTP status | Description |
|---|
| 50026 | 500 | System error, please retry later |
| 81001 | 200 | {param} parameter error |
| 81004 | 200 | Unsupported chain |
| 80007 | 200 | Risky address |
4. verify / settle business fields
For exact endpoints, failure reasons are returned in data.invalidReason (verify) or data.errorReason (settle / settle/status). Common values:
| Field value | Applies to | Description |
|---|
insufficient_funds | verify, settle | Payer balance insufficient |
nonce_already_used | verify, settle | Nonce already used |
expired_authorization | verify, settle | Authorization expired |
signature_invalid | verify, settle | Signature verification failed |
requirements_mismatch | verify, settle | accepted does not match paymentRequirements |
transaction_reverted | settle | On-chain transaction reverted |
chain_unavailable | settle | On-chain RPC unavailable |
not_found | settle/status | txHash not found in Broker records |
5. charge business errors
| Code | Name | Description |
|---|
| 8000 | SERVICE_ERROR | Internal API service error |
| 70000 | invalid_params | Missing required field or invalid format |
| 70001 | unsupported_chain | Chain not in supported list |
| 70002 | payer_blocked | Payer is blocklisted |
| 70003 | invalid_credential | source missing, or txHash already used |
| 70004 | invalid_signature | Signature verification failed |
| 70005 | split_sum_exceeds_total | Split total >= primary amount |
| 70006 | split_count_exceeded | Split count > 10 |
| 70007 | tx_not_confirmed | Transaction not confirmed on-chain |
| 70009 | challenge_invalid | Challenge does not exist or has expired |