BazaarLinkBazaarLink
Sign in
DocsAPI ReferenceSDK ReferenceAgentic UsageAI Skills

Pay with OKX x402: register agents and top up

x402 lets a client pay for a request with stablecoins. BazaarLink accepts x402 payments, settled through OKX's x402 facilitator on X Layer, to register an agent account and to top up an existing balance. This page describes the two routes exactly as they behave.

The 402 flow

Both routes follow the same three steps: ask, sign, resend.

  1. Send the request without a payment. The server answers 402 Payment Required with a JSON body: x402Version, resource, and accepts (network, asset, amount, payTo, maxTimeoutSeconds).
  2. Sign a payment authorization for one entry in accepts with your own wallet key.
  3. Send the same request again with the base64-encoded payment payload in the X-PAYMENT header. The header name payment-signature is accepted as an alias.
Read the requirements from the response
Take network, asset and amount from the 402 response instead of hard-coding them. amount is in the asset's smallest unit (6 decimals for USDT0). Send the same JSON body in both requests.

Register an agent

POSThttps://bazaarlink.ai/api/v1/agents/register/x402

POST /api/v1/agents/register/x402 creates an agent account, an API key and an initial balance in one paid request. It needs no API key and no login.

Request body

namerequired
string
Agent name, 1 to 100 characters.
description
string
Optional description, up to 4000 characters.
amountUsdrequired
number
Amount to pay in US dollars, a positive number. It is clamped to the allowed range (currently $1 to $50) before the 402 is built, so read the amount from the response.

Unknown fields are rejected with 400 bad_request.

1. Ask without paying

The response is 402 with the payment requirements. Nothing is created yet.

curl -i -X POST https://bazaarlink.ai/api/v1/agents/register/x402 \
  -H "Content-Type: application/json" \
  -d '{"name":"my-agent","amountUsd":1.1}'
HTTP/1.1 402 Payment Required
Content-Type: application/json

{
  "x402Version": 2,
  "resource": {
    "url": "https://bazaarlink.ai/api/v1/agents/register/x402",
    "description": "BazaarLink paid agent registration",
    "mimeType": "application/json"
  },
  "accepts": [
    {
      "scheme": "exact",
      "network": "eip155:196",
      "payTo": "0xPAY_TO_ADDRESS",
      "asset": "0xASSET_CONTRACT",
      "amount": "1100000",
      "maxTimeoutSeconds": 300,
      "extra": { "name": "USD₮0", "version": "1" }
    }
  ]
}

2. Sign and resend

Sign with your own wallet, then send the same request with the X-PAYMENT header. The curl command shows the request; the TypeScript example below produces the header value.

curl -i -X POST https://bazaarlink.ai/api/v1/agents/register/x402 \
  -H "Content-Type: application/json" \
  -H "X-PAYMENT: <base64 payment payload>" \
  -d '{"name":"my-agent","amountUsd":1.1}'

TypeScript example

This example uses the @okxweb3/x402 client packages and viem; you can sign with the OKX Wallet or any wallet key. The private key stays on your machine; only the signed authorization is sent.

import { x402Client } from "@okxweb3/x402-core/client";
import type { Network } from "@okxweb3/x402-core/types";
import { toClientEvmSigner } from "@okxweb3/x402-evm";
import { ExactEvmScheme } from "@okxweb3/x402-evm/exact/client";
import { privateKeyToAccount } from "viem/accounts";

const URL = "https://bazaarlink.ai/api/v1/agents/register/x402";
const HEADERS = { "content-type": "application/json" };
const BODY = JSON.stringify({ name: "my-agent", amountUsd: 1.1 });

// 1. Ask without paying. The 402 body lists what the server accepts.
const challenge = await fetch(URL, { method: "POST", headers: HEADERS, body: BODY });
if (challenge.status !== 402) throw new Error("unexpected status " + challenge.status);
const paymentRequired = await challenge.json();

// 2. Sign the payment authorization with your own wallet key.
const privateKey = readSecret("payer-private-key") as `0x${string}`; // from your own secret store, never from source code
const signer = toClientEvmSigner(privateKeyToAccount(privateKey));
const client = new x402Client().register(
  paymentRequired.accepts[0].network as Network,
  new ExactEvmScheme(signer),
);
const payload = await client.createPaymentPayload(paymentRequired);
const xPayment = Buffer.from(JSON.stringify(payload), "utf8").toString("base64");

// 3. Send the same request again with the signed payment.
const res = await fetch(URL, { method: "POST", headers: { ...HEADERS, "x-payment": xPayment }, body: BODY });
const account = await res.json(); // 201: api_key, credits, claim_token, payment ...
console.log(res.status, account.credits_usd);

Keep the wallet private key in an environment variable or a secret store, never in source code.

Registration response

A successful registration returns 201 with these fields. The API key appears only here, so store it right away.

HTTP/1.1 201 Created
Content-Type: application/json

{
  "api_key": "sk-bl-...",
  "credits": 1,
  "credits_usd": "$1.0000",
  "claim_token": "...",
  "claim_expires": "2026-10-08T00:00:00.000Z",
  "upgrade_url": "https://bazaarlink.ai/claim?token=...",
  "referral_code": "...",
  "free_model": "auto:free",
  "message": "...",
  "referral_message": "...",
  "base_url": "https://bazaarlink.ai/api/v1",
  "docs": "https://bazaarlink.ai/llms.txt",
  "payment": {
    "txHash": "0xTX_HASH",
    "network": "eip155:196",
    "amountUsd": 1.1,
    "paidUsd": 1.1,
    "creditedUsd": 1,
    "serviceFeeUsd": 0.1
  }
}
api_key
string
The new API key.
credits
number
Balance added, in US dollars: the amount paid minus the platform top-up fee.
credits_usd
string
The same balance as a formatted string.
claim_token
string
Token a person can use to claim the account.
claim_expires
string
ISO 8601 deadline for claiming the account.
upgrade_url
string
Claim link for a person, ending in /claim?token=.
referral_code
string
Referral code of the new agent account.
free_model
string
Always auto:free, the model available without a balance.
message
string
Ready-made text an agent can show its owner.
referral_message
string
Text about the referral code.
base_url
string
API base URL to use with the new key.
docs
string
Machine-readable documentation entry point.
payment
object
Object with txHash, network and amountUsd of the settled payment, plus paidUsd, creditedUsd and serviceFeeUsd.

Top up an existing balance

POSThttps://bazaarlink.ai/api/x402/topup

POST /api/x402/topup credits the account that owns the API key or the signed-in session. The 402 flow is the same and the body only has amountUsd.

Authenticate with Authorization: Bearer plus your API key, or use a signed-in browser session.

curl -i -X POST https://bazaarlink.ai/api/x402/topup \
  -H "Authorization: Bearer $BAZAARLINK_API_KEY" \
  -H "Content-Type: application/json" \
  -H "X-PAYMENT: <base64 payment payload>" \
  -d '{"amountUsd":1.1}'

A successful top-up returns 200 with status credited, the new balance in US dollars, the txHash, and paidUsd, creditedUsd and serviceFeeUsd (what you paid, what was credited, and the platform top-up fee).

HTTP/1.1 200 OK
Content-Type: application/json

{
  "status": "credited",
  "balance": 12.5,
  "txHash": "0xTX_HASH",
  "paidUsd": 1.1,
  "creditedUsd": 1,
  "serviceFeeUsd": 0.1
}
// Same three steps against /api/x402/topup; only the URL, body and auth header change.
const URL = "https://bazaarlink.ai/api/x402/topup";
const HEADERS = {
  "content-type": "application/json",
  authorization: "Bearer " + process.env.BAZAARLINK_API_KEY,
};
const BODY = JSON.stringify({ amountUsd: 1.1 });
// ...reuse the challenge / sign / resend code from the registration example.
// 200 -> { "status": "credited", "balance": 12.5, "txHash": "0x...", "paidUsd": 1.1, "creditedUsd": 1, "serviceFeeUsd": 0.1 }

Read the current limits

GEThttps://bazaarlink.ai/api/x402/topup

GET /api/x402/topup returns minUsd, maxUsd and network without authentication.

curl https://bazaarlink.ai/api/x402/topup
{ "minUsd": 1, "maxUsd": 50, "network": "eip155:196" }

Duplicate and repeated payments

A signed authorization can be used once. The server recognizes a repeated payment before it contacts the payment network, so a retry never charges you twice.

Top-up: resending a payment that was already credited returns 200 with status already_credited.

Registration: for 15 minutes the same signed payment returns the same 201 response, API key included, so a network failure can be retried safely. After that the response is 200 with status already_registered and the payment txHash, and the API key is not shown again.

Error responses

The x402 routes return errors as { "error": { "message", "code" } }. Two responses differ: 410 uses { "error", "code" } and 429 uses { "error" } with a Retry-After header.

HTTP
Code
Meaning
400bad_request
The body is not valid: wrong type, missing name, or an unknown field.
400topup_unavailable
Top-up is not available for this account.
401unauthenticated
Top-up only: no valid API key or session.
402(payment requirements body)
No usable payment yet. The body holds the requirements, so sign and resend. It is also returned when the payment does not match the requirements or fails verification.
402payment_amount_too_low
The settled amount is lower than the amount requested.
403geo_blocked
x402 is not available from your region.
410agent_register_discontinued
Agent registration is switched off.
429(Retry-After header)
Too many registrations from the same network source. Wait for the seconds given in Retry-After.
502facilitator_error
The payment could not be verified or settled. Try again later.
502settlement_error
The payment was received but could not be credited. Resend the same payment instead of signing a new one.
502registration_error
The payment was received but the account could not be created. Resend the same payment instead of signing a new one.
503disabled / runtime_disabled
x402 is switched off or not configured right now.
503asset_unavailable / dedup_unavailable
A dependency (asset configuration, duplicate check or top-up check) is unavailable. Try again later.
503signup_disabled / agent_register_unavailable
Registration is temporarily disabled or unavailable.

Hand the account to a person

Send upgrade_url from the response to the account owner. After they sign in and claim it, the API key and balance move to their account. Claim before claim_expires.

https://bazaarlink.ai/claim?token=<claim_token>

Network and asset

Today this is USDT0 on X Layer, settled through OKX's x402 facilitator. A platform top-up fee applies, so the balance you receive is lower than the amount you pay (see pricing). Payments settle on-chain and cannot be reversed, so check the amount and network before you sign.

See the x402 agent payments page for an overview.

Support
Support
Hi! How can we help you?
Send a message and we'll get back to you soon.