X402 payment protocol client for AceDataCloud APIs. Pay per request with USDC — no API key, no account, no session.
This is a monorepo with one package per language, each designed as a plugin for the official AceDataCloud SDK:
| Language | Package | Plugs into |
|---|---|---|
| TypeScript | @acedatacloud/x402-client — npm |
@acedatacloud/sdk |
| Python | acedatacloud-x402 — PyPI |
acedatacloud |
The SDK does all the API work (task polling, SSE streaming, retries, typed errors). This package only contributes one thing: signing an X-Payment header when the server returns 402 Payment Required.
- 🟦 Base — USDC (ERC-20) via EIP-3009
TransferWithAuthorization - 🟪 Solana — USDC (SPL) via signed
TransferChecked - 🟨 SKALE — USDC (bridged) via EIP-3009
All three settle through our production facilitator at https://facilitator.acedata.cloud (source).
SDK call (no Bearer token)
│
▼
api.acedata.cloud ── 402 Payment Required + accepts[] ──▶ SDK
│
payment handler │ (this package)
▼
sign X-Payment envelope
│
◀────────────── retry with X-Payment ──────────────────┘
200 OK (+ x402_tx hash in headers)
import { AceDataCloud } from '@acedatacloud/sdk';
import { createX402PaymentHandler } from '@acedatacloud/x402-client';
const client = new AceDataCloud({
paymentHandler: createX402PaymentHandler({
network: 'base',
evmProvider: window.ethereum,
evmAddress: '0x...',
}),
});
await client.openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [{ role: 'user', content: 'Hi' }],
});See typescript/README.md for the full guide.
from acedatacloud import AceDataCloud
from acedatacloud_x402 import create_x402_payment_handler, EVMAccountSigner
client = AceDataCloud(
payment_handler=create_x402_payment_handler(
network="base",
evm_signer=EVMAccountSigner.from_private_key("0x..."),
),
)
client.openai.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": "Hi"}],
)See python/README.md for the full guide.
.
├── typescript/ # @acedatacloud/x402-client — published to npm
│ ├── src/
│ ├── scripts/ # live on-chain e2e tests (Base, Solana, SKALE)
│ └── package.json
├── python/ # acedatacloud-x402 — published to PyPI
│ ├── src/acedatacloud_x402/
│ ├── tests/
│ └── pyproject.toml
└── .github/workflows/
├── ci.yml # lint+build both packages
├── publish.yml # npm (TS) on push to main (CalVer)
└── publish-pypi.yml # PyPI (Python) on push to main (CalVer)
# TypeScript
cd typescript && npm install && npm run build
# Python
cd python && pip install -e ".[dev]" && pytest && ruff check .MIT © AceDataCloud
X402 payment protocol client for AceDataCloud APIs. Pay per request with USDC — no API key, no account, no session.
Every AceDataCloud API that costs money (chat completions, image generation, video generation, music generation, web search, …) now speaks the x402 protocol. This package ships the only piece the SDK can't do by itself: signing an X-Payment header when the server returns 402 Payment Required. It plugs straight into @acedatacloud/sdk as a paymentHandler.
- 🟦 Base — USDC (ERC-20) via EIP-3009
transferWithAuthorization - 🟪 Solana — USDC (SPL) via signed transfer
- 🟨 SKALE — USDC (bridged) via EIP-3009
All three networks settle through our production facilitator at https://facilitator.acedata.cloud (source).
SDK call (no Bearer token)
│
▼
api.acedata.cloud ── 402 Payment Required + accepts[] ──▶ SDK
│
paymentHandler │ (this package)
▼
sign X-Payment envelope
│
◀────────────── retry with X-Payment ──────────────────┘
200 OK (+ x402_tx hash in headers)
The SDK keeps doing everything it already does — task polling, SSE streaming, retries, typed errors — and this package contributes exactly one thing: the per-chain signature.
npm install @acedatacloud/sdk @acedatacloud/x402-client
# extra peers depending on the chain(s) you use:
npm install ethers # Base / SKALE
npm install @solana/web3.js # SolanaIf the npm package is not yet published you can install from GitHub:
npm install @acedatacloud/sdk github:AceDataCloud/X402Clientimport { AceDataCloud } from '@acedatacloud/sdk';
import { createX402PaymentHandler } from '@acedatacloud/x402-client';
const client = new AceDataCloud({
// No apiToken — per-request on-chain payment.
paymentHandler: createX402PaymentHandler({
network: 'base', // or 'skale'
evmProvider: window.ethereum, // any EIP-1193 provider works
evmAddress: '0xYourAddress...',
}),
});
const res = await client.openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [{ role: 'user', content: 'Say hi in 3 words' }],
max_tokens: 10,
});
console.log(res.choices[0].message.content);import { AceDataCloud } from '@acedatacloud/sdk';
import { createX402PaymentHandler } from '@acedatacloud/x402-client';
const client = new AceDataCloud({
paymentHandler: createX402PaymentHandler({
network: 'solana',
solanaWallet: phantomWallet, // any wallet adapter with signTransaction()
}),
});
const task = await client.images.generate({
provider: 'nano-banana',
prompt: 'a yellow banana on a white background',
});
const result = await task.wait(); // task polling handled by the SDKEvery AceDataCloud endpoint the SDK exposes (openai.chat, images, audio, video, search, …) works the same way.
- Fund a wallet with USDC on the network you want to use:
- Base — USDC on Base
- Solana — USDC on Solana
- SKALE — bridged USDC on SKALE Europa
- A few cents of USDC is enough for most single requests (prices are listed at platform.acedata.cloud).
- Construct the handler with whatever wallet primitive you have: a browser provider, a Node
ethers.Wallet,@solana/web3.jskeypair, etc.
If you need to produce an X-Payment envelope outside the SDK — for example in a custom fetch wrapper, tests, or an agent framework — the raw signing primitives are exported directly:
import { signSolanaPayment, signEVMPayment } from '@acedatacloud/x402-client';
const envelope = await signSolanaPayment(paymentRequirement, wallet);
const header = btoa(JSON.stringify(envelope));The live e2e scripts under scripts/ use this low-level entry point to settle real USDC on chain. For application code, prefer the SDK path above.
This repo includes live, on-chain smoke tests. They require a funded wallet (a few cents of USDC is plenty).
git clone https://github.com/AceDataCloud/X402Client.git
cd X402Client
npm install
# Base — EVM private key
export BASE_TEST_PRIVATE_KEY=0x...
node --experimental-strip-types scripts/test-real-e2e.ts
# Solana — base58-encoded secret key
export SOLANA_TEST_PRIVATE_KEY=...
node --experimental-strip-types scripts/test-solana-e2e.ts
# SKALE — EVM private key with funded bridged USDC
export SKALE_BASE_PRIVATE_KEY=0x...
node --experimental-strip-types scripts/test-skale-e2e.tsEach script:
- Sends
POST /openai/chat/completionswith no auth. - Parses the returned
402. - Signs the payment envelope.
- Retries with
X-Payment. - Prints the trace ID, chain tx hash, and the final chat response.
scripts/test-api-billing-scenarios.ts runs multiple APIs with different payloads and verifies the advertised 402 amount exactly matches floor(credits × 0.095215 × 1e6), then asserts an ApiUsage record with the on-chain tx hash lands in our logging pipeline.
export X402B_BASE_PAYER_PRIVATE_KEY=0x... # Base wallet with a few cents of USDC
node --experimental-strip-types scripts/test-api-billing-scenarios.tsLatest successful live runs on 2026-04-19:
- Base — tx
0x11313652...5327ec - Solana — tx
3qB25xsy...eBVzr - SKALE — tx
0xc6c7affe...aae42e1
All three chains are live. All settlements flow through our own facilitator at https://facilitator.acedata.cloud.
The handler does not hardcode AceDataCloud prices. For any x402-enabled API, the server returns the real charge in the first 402 response:
{
"accepts": [
{
"network": "base",
"maxAmountRequired": "95215",
"payTo": "...",
"asset": "..."
}
]
}That means:
- price is determined server-side by the API path, model, and request body
- different APIs can return different
maxAmountRequired - the client signs exactly what the server asks for
If you want to preview the price for another API without paying yet, send the same request once without Bearer auth and without X-Payment, then inspect the returned accepts list.
At the time of writing, 121 of 122 public APIs have x402 pricing configured — the only exception is the free /fish/voices listing.
There is currently no Python x402 signer. The Python SDK (acedatacloud) already exposes the same payment_handler hook as the TypeScript SDK — any callable that returns {"headers": {"X-Payment": "<base64>"}} works. A Python port of the signing logic in this package is tracked as future work; contributions are welcome.
This repo publishes on every push to main:
.github/workflows/publish.ymlbuilds, computes today's version via CalVer (YYYY.M.D[.N]), patchespackage.json, runsnpm publish --provenance --access public, and creates a matching GitHub Release.- The
versionfield committed inpackage.jsonis a placeholder — the real number is stamped at publish time.
If you need a manual publish:
npm run version:date # stamps today's date
npm publish --access publicMIT © AceDataCloud