X402 TypeScript SDK Integration Guide

TypeScript is one of the most recommended ways to integrate with Ace Data Cloud X402. The official SDK handles regular API calls, task polling, error handling, and automatic retries; @acedatacloud/x402-client is responsible for checking out the X-Payment request header when encountering 402 Payment Required.

Source code and package addresses:

Install Dependencies

npm install @acedatacloud/sdk @acedatacloud/x402-client

If using Base or SKALE, EVM signing capability is required:

npm install ethers

If using Solana, a Solana wallet adapter or @solana/web3.js is needed:

npm install @solana/web3.js

Clean npm project installation and import check output:

imports_ok true true true true true
@acedatacloud/sdk@2026.504.2
@acedatacloud/x402-client@2026.531.3
ethers@6.16.0
@solana/web3.js@1.98.4

Result explanation:

  • Both @acedatacloud/sdk and @acedatacloud/x402-client can be installed from npm and imported by Node.js.
  • ethers is used for EVM typed data signing, and @solana/web3.js is used for Solana transaction construction.

Base or SKALE Example

In the browser, window.ethereum can be used directly. In Node.js, ethers.Wallet can wrap an EIP-1193 style provider.

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

const wallet = new Wallet(process.env.EVM_PRIVATE_KEY!);

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 client = new AceDataCloud({
  paymentHandler: createX402PaymentHandler({
    network: 'base',
    evmProvider,
    evmAddress: wallet.address
  })
});

const result = await client.openai.chat.completions.create({
  model: 'gpt-4o-mini',
  messages: [{ role: 'user', content: 'Say hi in 3 words' }],
  max_tokens: 10
});

console.log(result.choices[0].message.content);

SKALE paid call program execution result:

payer 0xd0479FA9FD8C678303d477433d24C15e3723CC1C
elapsed_ms 6782
content ADC_TS_SDK_X402_OK
id chatcmpl-DlcVLO4PQWvmjPDQpy9yQw2QdLGAT

Result explanation:

  • The program first triggers an unauthenticated 402, then the handler checks out X-Payment, and finally retries with the same request body.
  • content ADC_TS_SDK_X402_OK is a fixed string returned by the model, indicating that the retried request entered the upstream API.
  • id chatcmpl-DlcVLO4PQWvmjPDQpy9yQw2QdLGAT is the response ID for this chat completion, which can be used to cross-reference with platform usage records.
  • On-chain settlement results can be found in the SKALE exact records in E2E Verification and Troubleshooting.

Change network to skale to use SKALE. The advantage of SKALE is the low gas cost for on-chain transactions; the advantage of Base is the more mature USDC liquidity and wallet support.

Browser Wallet Example

When using MetaMask, Coinbase Wallet, or WalletConnect in a frontend application, the EIP-1193 provider is usually passed directly:

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

const [address] = await window.ethereum.request({ method: 'eth_requestAccounts' });

const client = new AceDataCloud({
  paymentHandler: createX402PaymentHandler({
    network: 'base',
    evmProvider: window.ethereum,
    evmAddress: address
  })
});

const image = await client.images.generate({
  provider: 'nano-banana',
  prompt: 'a yellow banana on a white background'
});

The browser wallet will pop up a signature confirmation. The user is not signing any arbitrary message, but the payment request returned by the API: the receiving address, USDC contract, amount, validity period, and nonce are all included in the signature.

Solana Example

Solana uses SPL USDC TransferChecked. The incoming wallet adapter needs to expose publicKey and signAndSendTransaction.

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

const client = new AceDataCloud({
  paymentHandler: createX402PaymentHandler({
    network: 'solana',
    solanaWallet: phantomWallet
  })
});

const result = await client.openai.chat.completions.create({
  model: 'gpt-4o-mini',
  messages: [{ role: 'user', content: 'Say hi in 3 words' }],
  max_tokens: 10
});

The Solana path currently only supports exact and does not support upto. If the API returns multiple accepts, the handler will choose the one with network = 'solana'.

The Solana path has been verified on the same public API that paid retry can return HTTP 200 and ADC_SOLANA_E2E_OK. Public RPC queries may be rate-limited, so this article does not write the Solana tx hash; for on-chain reconciliation, please use your own Solana RPC or console logs for confirmation.

Choosing exact or upto

The current TypeScript handler will select the first matching payment requirement returned by the server for the network. The Ace Data Cloud API typically places the exact for the same network before upto, so if you explicitly want to use post-measurement, you need to pass in preferScheme: 'upto'.

Example:

const client = new AceDataCloud({
  paymentHandler: createX402PaymentHandler({
    network: 'base',
    evmProvider,
    evmAddress: wallet.address,
    preferScheme: 'upto'
  })
});

If the server does not return the upto requirement for that network, the handler will automatically fall back to the first available requirement for that network, which is usually exact.

upto requires a one-time authorization Permit2. The TypeScript helper supports Base and SKALE:

# Base
npx tsx scripts/approve-permit2.ts --network base

# SKALE Base
SKALE_BASE_PRIVATE_KEY=0x... npx tsx scripts/approve-permit2.ts --network skale

SKALE upto has completed public API verification: HTTP 402 -> HTTP 200, with the post-settlement tx being 0x51831a97fb97802951bee5dfb36735f4a0b589f153e6a23976fad5495c3925bc. Full output can be found in the billing scheme description.

What the SDK Does

The transport of @acedatacloud/sdk will execute a payment handler upon receiving a 402:

type PaymentHandler = (ctx: {
  url: string;
  method: string;
  body?: unknown;
  accepts: PaymentRequirement[];
}) => Promise<{ headers: Record<string, string> }>;

The handler returned by @acedatacloud/x402-client will:

  1. Select the payment requirement for the target network from ctx.accepts.
  2. Construct an EVM EIP-712 signature or Solana transfer transaction according to the network.
  3. Serialize the envelope to Base64.
  4. Return { headers: { 'X-Payment': '<base64>' } }.
  5. The SDK will automatically retry with the original request body.

This means that business code only needs to be written like a normal SDK call, without the need to manually handle 402 retries.