> ## Documentation Index
> Fetch the complete documentation index at: https://docs.acedata.cloud/llms.txt
> Use this file to discover all available pages before exploring further.

# X402 TypeScript SDK Integration Guide

> Platform integration guide - Ace Data Cloud

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 signing the `PAYMENT-SIGNATURE` request header when encountering `402 Payment Required`.

Source code and package addresses:

* SDK repository: [https://github.com/AceDataCloud/SDK](https://github.com/AceDataCloud/SDK)
* X402 Client repository: [https://github.com/AceDataCloud/X402Client](https://github.com/AceDataCloud/X402Client)
* npm SDK: [https://www.npmjs.com/package/@acedatacloud/sdk](https://www.npmjs.com/package/@acedatacloud/sdk)
* npm X402 Client: [https://www.npmjs.com/package/@acedatacloud/x402-client](https://www.npmjs.com/package/@acedatacloud/x402-client)

## Install Dependencies

```bash theme={null}
npm install @acedatacloud/sdk @acedatacloud/x402-client
```

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

```bash theme={null}
npm install ethers
```

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

```bash theme={null}
npm install @solana/web3.js
```

Clean npm project installation and import check output:

```text theme={null}
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.

```ts theme={null}
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);
```

The output of this example program:

```text theme={null}
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 signs the `PAYMENT-SIGNATURE`, 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 target 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 [E2E Verification and Troubleshooting](https://platform.acedata.cloud/documents/x402-e2e-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, and only Base provides `upto` post-measurement.

Note: SKALE currently only supports `exact`. If `preferScheme: 'upto'` is passed under `network: 'skale'`, the handler will silently fall back to `exact` if it cannot find `upto`, without throwing an error—scenarios like chat completions that are measured by tokens will thus settle at a fixed price instead of actual usage. Please use Base for post-measurement.

## Browser Wallet Example

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

```ts theme={null}
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`.

```ts theme={null}
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 to return HTTP 200 and `ADC_SOLANA_E2E_OK` for paid retries on the same public API. 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 `exact` for the same network before `upto`, so if you explicitly want to use post-measurement, you need to pass in `preferScheme: 'upto'`.

Example:

```ts theme={null}
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 of Permit2. `upto` is currently only available on Base, so only one authorization for Base USDC is needed:

```bash theme={null}
npx tsx scripts/approve-permit2.ts --network base
```

Base `upto` has completed public API verification: HTTP 402 -> HTTP 200, the subsequent settlement tx is `0x4b0b836ce1cd1171cdbc37df1637150b024214ec28e7f6f2d09122f15cbfc036`. For complete output, see the billing plan description.

## What the SDK does

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

```ts theme={null}
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: { 'PAYMENT-SIGNATURE': '<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 needing to manually handle 402 retries.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.