AI Models
Multi-model AI inference with per-token rolling settlement.
Overview
ZAN AI Service provides access to multiple AI models through the x402 Gateway. The SDK's client.chat() method offers a unified interface regardless of the underlying model protocol (OpenAI, Anthropic, Gemini). The gateway handles protocol adaptation internally.
Key features:
- Per-token billing (input + output tokens priced separately)
- Rolling settlement: first call is free, subsequent calls settle the previous call's cost
- Model catalog dynamically fetched from upstream — always up to date
- SDK handles payment automatically with
autoPayment: true
Quick start
import { createX402Client } from '@zan_team/x402';
const client = await createX402Client({
gatewayUrl: 'https://x402.zan.top',
privateKey: process.env.PRIVATE_KEY as `0x${string}`,
autoPayment: true,
preAuth: true,
});
const response = await client.chat('deepseek-v4-flash', {
messages: [{ role: 'user', content: 'Explain blockchain consensus in one paragraph.' }],
max_tokens: 256,
});
console.log(response.data.content);
console.log(response.data.usage);
// { prompt_tokens: 12, completion_tokens: 85, total_tokens: 97 }Rolling settlement
AI billing uses a pay-after-use model that minimizes upfront friction.
How it works
| Step | What happens | Payment |
|---|---|---|
| First call | Gateway forwards to upstream model, records actual token usage | None (free) |
| Subsequent calls | Gateway checks previous call's settlement status before forwarding | Settles previous call's cost |
On each subsequent call, the gateway checks the previous call's record:
- pending → returns HTTP 402 requesting payment for the previous call's token cost → SDK auto-signs → gateway settles and forwards the new request
- settled → forwards the new request directly (no payment needed this time)
With autoPayment: true, the SDK handles the 402 → sign → retry cycle transparently. Your code sees only a successful response.
Billing formula
Cost (USDC) = input_tokens × input_price_per_token + output_tokens × output_price_per_token
Precision: 6 decimal places (USDC atomic units).
Example: Calling deepseek-v4-flash (input: 0.14 USDC/1M tokens, output: 0.28 USDC/1M tokens) with 500 input tokens and 200 output tokens:
500 × 0.000000140 + 200 × 0.000000280 = 0.000070 + 0.000056 = 0.000126 USDC
Settlement status
| Status | Meaning | What happens next |
|---|---|---|
| pending | Previous call completed, token cost recorded but not yet paid | Next call triggers 402 → payment → settle |
| settled | Payment confirmed on-chain | Terminal state. Next call proceeds freely |
| failed | Settlement attempt failed (e.g., USDC insufficient) | Next call triggers 402 again for re-payment |
Transition: pending → settled (on success) or pending → failed (on failure) → settled (on re-payment success)
Model discovery
Models and pricing are fetched dynamically from upstream. Query the current catalog:
const { models } = await client.discovery.listAiModels();
models.forEach(m => {
console.log(`${m.id}`);
console.log(` Input: $${m.inputPricePerToken}/token`);
console.log(` Output: $${m.outputPricePerToken}/token`);
});HTTP endpoint (no auth required):
curl https://x402.zan.top/v1/discovery/aiExample response:
{
"result": "OK",
"data": {
"models": [
{
"id": "deepseek-v4-flash",
"inputPricePerToken": "0.000000140",
"outputPricePerToken": "0.000000280"
},
{
"id": "claude-opus-4-6",
"inputPricePerToken": "0.000005000",
"outputPricePerToken": "0.000025000"
}
]
}
}Model availability and pricing may change as upstream providers update their offerings. Always use the discovery endpoint for the latest information.
Multi-protocol compatibility
The gateway supports models from multiple AI providers (OpenAI, Anthropic, Gemini, and more). Regardless of the underlying provider protocol, all models are accessible through the same unified endpoint and interface:
- SDK:
client.chat(modelId, { messages, max_tokens }) - HTTP:
POST /ai/{model}with amessagesarray body
The gateway translates your request to the upstream provider's native protocol internally. You never need to handle protocol differences — just pass the model ID and your messages.
The response format is always unified:
interface AiResponse {
success: boolean;
data: {
model: string;
content: string;
usage: {
prompt_tokens: number;
completion_tokens: number;
total_tokens: number;
};
finish_reason: string;
};
txHash: string | null; // payment tx hash (null on first call)
paymentNetwork: string | null; // e.g. "eip155:8453"
}Raw HTTP interface (reference)
For debugging or non-SDK usage, the gateway exposes a unified AI endpoint:
curl -X POST https://x402.zan.top/ai/deepseek-v4-flash \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{"messages":[{"role":"user","content":"Hello"}]}'Response (first call — free):
{
"success": true,
"data": {
"model": "deepseek-v4-flash",
"content": "Hello! How can I help you?",
"usage": { "prompt_tokens": 12, "completion_tokens": 8, "total_tokens": 20 },
"finish_reason": "stop"
}
}The gateway endpoint is
POST /ai/{model}. Protocol adaptation (OpenAI, Anthropic, Gemini) is handled internally by the gateway when communicating with upstream providers — the user-facing endpoint is always/ai/{model}.
Error handling
| Error | HTTP | Scenario | SDK behavior (autoPayment: true) |
|---|---|---|---|
AiPaymentRequiredError | 402 | Previous call cost pending | Auto-signs payment and retries |
AiModelNotFoundError | 404 | Model does not exist | Throws immediately |
AiUpstreamError | 502/504 | Upstream model failure | Throws (not charged) |
InsufficientFundsError | 402 | Wallet USDC too low | Throws (cannot auto-fix) |
Handling upstream failures
When the upstream model returns an error (502/504), you are not charged. The gateway does not record a pending settlement for failed calls.
import { AiUpstreamError, AiModelNotFoundError } from '@zan_team/x402';
try {
const response = await client.chat('some-model', {
messages: [{ role: 'user', content: 'Hello' }],
});
} catch (err) {
if (err instanceof AiUpstreamError) {
// Not charged — try a different model
const fallback = await client.chat('deepseek-v4-flash', {
messages: [{ role: 'user', content: 'Hello' }],
});
} else if (err instanceof AiModelNotFoundError) {
// Model doesn't exist — check discovery
const { models } = await client.discovery.listAiModels();
console.log('Available models:', models.map(m => m.id));
}
}Next steps
- SDK Reference — Full API documentation
- x402 Payment — How rolling settlement works on-chain
- Service Discovery — Dynamic model catalog access
Updated about 10 hours ago
