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

StepWhat happensPayment
First callGateway forwards to upstream model, records actual token usageNone (free)
Subsequent callsGateway checks previous call's settlement status before forwardingSettles 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

StatusMeaningWhat happens next
pendingPrevious call completed, token cost recorded but not yet paidNext call triggers 402 → payment → settle
settledPayment confirmed on-chainTerminal state. Next call proceeds freely
failedSettlement attempt failed (e.g., USDC insufficient)Next call triggers 402 again for re-payment

Transition: pendingsettled (on success) or pendingfailed (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/ai

Example 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 a messages array 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

ErrorHTTPScenarioSDK behavior (autoPayment: true)
AiPaymentRequiredError402Previous call cost pendingAuto-signs payment and retries
AiModelNotFoundError404Model does not existThrows immediately
AiUpstreamError502/504Upstream model failureThrows (not charged)
InsufficientFundsError402Wallet USDC too lowThrows (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



Did this page help you?