X402 Order Payment Tutorial
In addition to directly paying via API requests, Ace Data Cloud also supports paying for orders through the X402 payment console. The core protocol for order payment and API calls is the same: the first request returns 402, the client checks out X-Payment, and then retries the same request.
The difference is that order payment belongs to the platform API and requires an account token; whereas directly calling the x402.acedata.cloud AI API can be done using only X402, without needing an API Token.
¶ Prepare the Order
Go to the Ace Data Cloud Console, select the order you need to pay for, and record the order ID.
If you do not have an order yet, you can create a pending payment order on the package page. The order price is based on what is displayed on the page, and the maxAmountRequired in the X402 402 response is the final basis for signing.
¶ Create Account Token
The order payment request requires an account token. Open the Platform Token Page and create a token in the platform-v1-... format.
Subsequent requests will use:
Authorization: Bearer {platform_token}
The account token is different from a regular API Token. A regular API Token is used to consume API quotas; the account token is used to operate platform resources on behalf of your account, such as order payments.
¶ Trigger 402
First, send a request without X-Payment:
POST https://platform.acedata.cloud/api/v1/orders/{order_id}/pay/
Authorization: Bearer {platform_token}
Content-Type: application/json
{
"pay_way": "X402"
}
The returned status is 402, and the response includes accepts:
{
"x402Version": 1,
"error": "Payment required for this order.",
"accepts": [
{
"scheme": "exact",
"network": "base",
"maxAmountRequired": "1200000",
"resource": "http://platform.acedata.cloud/api/v1/orders/.../pay/",
"payTo": "0x...",
"asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"extra": {
"name": "USD Coin",
"version": "2",
"chainId": 8453,
"verifyingContract": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
}
}
]
}
The program output after creating a 10 Credits order and triggering 402:
created order 78481793-304e-47f7-bc0c-8231aec9cc1e
created state Pending
created price 1.26
http_status=402
x402Version 1
error Payment required for this order.
accepts [
('base', 'exact', '1200000', '0x4F0E2D3477a1B94CF33d16E442CEe4733dadCeE7'),
('solana', 'exact', '1200000', '5iVXFrYaYWX2GUTbkQj8mDBoBhAX8bneYigS2LJTia43')
]
description Ace Data Cloud Credits x 10.0
Result explanation:
- After the order is successfully created, the status is
Pending, and no on-chain payment has been made yet. - The first
pay/request did not carryX-Payment, so it returned HTTP 402. acceptsprovides both Baseexactand Solanaexact, with this tutorial subsequently choosing Base.- The price at order creation is
1.26, and upon entering the X402 payment process, the X402 payment discount is applied, resulting in a signed and settled amount of1.2USDC, corresponding to1200000atomic USDC.
Note that the resource here is a field returned by the server and involved in the signing; the client should not modify the protocol, path, or order ID within it.
¶ Sign and Retry
Order payment can reuse the low-level signing functions from @acedatacloud/x402-client or acedatacloud-x402. Below is a TypeScript example:
import { Wallet } from 'ethers';
import { signEVMPayment } from '@acedatacloud/x402-client';
const platformToken = process.env.ACE_PLATFORM_TOKEN!;
const orderId = process.env.ACE_ORDER_ID!;
const wallet = new Wallet(process.env.EVM_PRIVATE_KEY!);
const url = `https://platform.acedata.cloud/api/v1/orders/${orderId}/pay/`;
const body = { pay_way: 'X402' };
const first = await fetch(url, {
method: 'POST',
headers: {
Authorization: `Bearer ${platformToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(body)
});
if (first.status !== 402) {
throw new Error(`expected 402, got ${first.status}`);
}
const paymentRequired = await first.json();
const requirement = paymentRequired.accepts.find(
(item: any) => item.network === 'base' && item.scheme === 'exact'
);
const evmProvider = {
async request({ method, params }: { method: string; params?: unknown[] }) {
if (method !== 'eth_signTypedData_v4') throw new Error(`unsupported method: ${method}`);
const [, typedDataJson] = params as [string, string];
const typedData = JSON.parse(typedDataJson);
return wallet.signTypedData(typedData.domain, typedData.types, typedData.message);
}
};
const envelope = await signEVMPayment(requirement, evmProvider, wallet.address);
const xPayment = Buffer.from(JSON.stringify(envelope), 'utf8').toString('base64');
const paid = await fetch(url, {
method: 'POST',
headers: {
Authorization: `Bearer ${platformToken}`,
'Content-Type': 'application/json',
'X-Payment': xPayment
},
body: JSON.stringify(body)
});
if (!paid.ok) {
throw new Error(`payment failed: ${paid.status} ${await paid.text()}`);
}
console.log(await paid.json());
The program output after signing and retrying the same order with Base exact:
status 200
payer 0x5d4f08D5c2bb60703284bc06671Eb680fA41B105
has_x_payment_response True
settle_header {'success': True, 'network': 'base', 'transaction': '0xfec08cc00a159ea1ec692b32faa9bf3d17595a986301169e689d94f58bc44151', 'errorReason': None}
order {'id': '78481793-304e-47f7-bc0c-8231aec9cc1e', 'state': 'Finished', 'pay_way': 'X402', 'price': 1.2, 'pay_id': '0xfec08cc00a159ea1ec692b32faa9bf3d17595a986301169e689d94f58bc44151'}
On-chain confirmation result:
tx 0xfec08cc00a159ea1ec692b32faa9bf3d17595a986301169e689d94f58bc44151
status 1
block 46726704
explorer https://basescan.org/tx/0xfec08cc00a159ea1ec692b32faa9bf3d17595a986301169e689d94f58bc44151
transfer {"from":"0x5d4f08D5c2bb60703284bc06671Eb680fA41B105","to":"0x4F0E2D3477a1B94CF33d16E442CEe4733dadCeE7","value":"1200000"}
Result explanation:
status 200indicates that the platform's order payment interface has accepted thisX-Payment.has_x_payment_response Trueindicates that the response header contains a Base64 encodedX-PAYMENT-RESPONSEreceipt.settle_header.success=Trueandnetwork=baseindicate that the Facilitator has completed the Base settlement.- The final status of the order is
Finished,pay_wayisX402, andpay_idis written into the on-chain transaction hash. - The
Transferevent on BaseScan shows that the payment address transferred1200000atomic USDC to the platform's receiving address, which is1.2USDC.
¶ Successful Response and Receipt
After the order payment is successful, the response body contains the order information. The platform will also carry a Base64 encoded settlement response in the response header X-PAYMENT-RESPONSE, and common fields after decoding include:
| Field | Description |
|---|---|
success |
Whether the Facilitator settlement was successful. |
transaction |
On-chain settlement transaction hash. |
network |
Payment network. |
payer |
Payer wallet address. |
amount |
Actual settlement amount, using atomic units. |
If you need to reconcile, it is recommended to save the order ID, payer wallet address, transaction, and the final status of the order at the same time.
¶ Notes
- Order payment requires a platform account token and cannot be completed solely with the X402 wallet signature.
maxAmountRequireduses USDC atomic units, where1200000represents1.2USDC.- Do not construct the receiving address or asset address on your own; refer to the
acceptsin the 402 response. - If the same
X-Paymentis submitted multiple times, the Facilitator will implement replay protection based on nonce.
