A Practical Guide to Pay-Per-Call AI APIs with the Ace Data Cloud SDK and X402

A Practical Guide to Pay-Per-Call AI APIs with the Ace Data Cloud SDK and X402

If you are building a CLI, backend worker, or agent that calls AI APIs on behalf of different users, API keys are often the awkward part: who owns the balance, who rotates the token, and how do you charge only for one call? The paymentHandler hook in the Ace Data Cloud SDK gives you another path: let the first request receive 402 Payment Required, sign an X402 payment envelope locally, then retry the same API call with a PAYMENT-SIGNATURE header.

What you can do

The documented flow is useful when you want business code to stay close to a normal SDK call while payment happens per request. In practice, you can:

  • Call client.openai.chat.completions.create(...) without passing an apiToken.
  • Inject a TypeScript or Python paymentHandler that signs the payment challenge after a 402.
  • Use EVM networks such as base or skale, or use solana where the Solana signer path is supported.
  • Choose preferScheme: 'upto' / prefer_scheme="upto" for metered chat-style usage, where actual settlement depends on usage rather than a fixed amount.

How it works

The SDK request path is intentionally simple. The first request goes to /openai/v1/chat/completions without an Authorization header. The server responds with 402 Payment Required and an accepts array describing acceptable schemes, networks, and required amounts. The SDK then calls your local paymentHandler({ url, method, body, accepts }). Your handler returns headers, usually including PAYMENT-SIGNATURE. The SDK resends the original request with that header and receives the normal business response.

The X402 envelope itself is JSON, base64-encoded into the PAYMENT-SIGNATURE header. At the top level it includes x402Version: 2 and an accepted object with the chosen scheme and network, for example scheme: "upto" and network: "eip155:8453" for Base.

Choosing between exact and upto

The documentation distinguishes two schemes. exact is for fixed-price work, such as a one-off generation or search call where the required amount is known before execution. upto is for metered billing, especially chat completions or token-based APIs. With upto, the signer authorizes an upper limit, and settlement is based on actual usage.

For chat completions, the practical rule is straightforward: prefer upto. In TypeScript that means preferScheme: 'upto'; in Python it is prefer_scheme="upto". If the server exposes only exact, the preference is ignored or falls back to a matching item. Solana currently exposes only exact, so preferScheme does not affect that path.

TypeScript browser wallet setup

For a browser app, the TypeScript package accepts an EIP-1193 provider. That means MetaMask or WalletConnect-style providers can be used directly. The complete documented option shape is:

export interface X402PaymentHandlerOptions {
  network: 'solana' | 'base' | 'skale';
  solanaWallet?: SolanaWalletAdapter;
  evmProvider?: EVMProvider;
  evmAddress?: string;
  preferScheme?: 'exact' | 'upto';
}

A minimal browser flow looks like this:

import { AceDataCloud } from '@acedatacloud/sdk';
import { createX402PaymentHandler } from '@acedatacloud/x402-client';

const accounts: string[] = await (window as any).ethereum.request({
  method: 'eth_requestAccounts'
});
const userAddress = accounts[0];

await (window as any).ethereum.request({
  method: 'wallet_switchEthereumChain',
  params: [{ chainId: '0x2105' }] // 8453 = Base
});

const client = new AceDataCloud({
  paymentHandler: createX402PaymentHandler({
    network: 'base',
    evmProvider: (window as any).ethereum,
    evmAddress: userAddress,
    preferScheme: 'upto'
  })
});

const res: any = await client.openai.chat.completions.create({
  model: 'gpt-4o-mini',
  messages: [{ role: 'user', content: 'hi' }],
  max_tokens: 20
});
console.log(res.choices[0].message.content);

The first EVM call can involve two approvals: a one-time USDC Permit2 approval and an EIP-712 signature for the X402 envelope. Later calls generally require only the envelope signature. That distinction matters for UX: explain the first-time approval separately from the per-call signature.

Python private-key mode for workers

For backend workers or task runners, the Python package signs directly from a private key. The documented installation is:

pip install acedatacloud acedatacloud-x402

The EVM path uses EVMAccountSigner.from_private_key and injects payment_handler into AceDataCloud:

import os
from acedatacloud import AceDataCloud
from acedatacloud_x402 import create_x402_payment_handler, EVMAccountSigner

signer = EVMAccountSigner.from_private_key(os.environ["EVM_PRIVATE_KEY"])

client = AceDataCloud(
    payment_handler=create_x402_payment_handler(
        network="base",
        evm_signer=signer,
        prefer_scheme="upto",
    )
)

res = client.openai.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "hi"}],
    max_tokens=20,
)
print(res["choices"][0]["message"]["content"])

On EVM Base, Permit2 approval can be handled once with approve_permit2 and a BASE_RPC_URL. Solana does not use Permit2; the documented Solana path uses SolanaKeypairSigner.from_secret_key_base58 and can optionally pass rpc_url="https://api.mainnet-beta.solana.com".

Common mistakes to avoid

  • Do not pass both token authentication and X402 assumptions into the same mental model. For X402 mode, construct the client without apiToken and provide paymentHandler.
  • Do not use raw private keys with the TypeScript createX402PaymentHandler. The documented TypeScript EVM path expects an EIP-1193 provider; for Node, wrap the key with a viem WalletClient.
  • Use preferScheme: 'upto' for chat-style metered usage. Using exact for chat can authorize the maximum required amount instead of usage-based settlement.
  • Separate payment errors from API errors. A 402 leads into the handler; after retry, normal business errors such as 401, 422, or 5xx are still ordinary SDK exceptions.

Where this fits

X402 is not a replacement for every API key. For your own backend, a token can still be the simplest path. But for agentic calls, third-party developers, CLIs, and per-user payment flows, the SDK hook keeps the API call readable while moving payment authorization to the wallet that owns the spend.

Read the full source documentation here: SDK + X402 Payment Hook.

Comments

Popular posts from this blog

Artistic QR Code API Integration Guidance

How to Configure Claude Code with CC Switch and Ace Data Cloud

How to Build a Server-Side Image Editing Workflow with GPT-Image-2