Skip to content

X402 Payment Protocol

AiMo Network uses the X402 protocol for all payment processing. X402 enables direct cryptocurrency payments for AI model inference with automatic payment verification.

Overview

X402 payments are used in two ways on AiMo Network:

  1. Managed (with API Key): Automatic X402 flow using Coinbase server wallets - See API Key Method
  2. Direct (without API Key): Manual X402 implementation by client - See Direct X402 Method

Using X402 Direct Payment

When calling the API without an Authorization header, you implement the X402 protocol yourself.

Endpoint Details

Base URL: https://devnet.aimo.network/api

Endpoint: POST /v1/chat/completions

Supported Networks:
  • Solana Mainnet: USDC payments
  • Base Mainnet: USDC payments

Quick Start with X402 SDK

Installation

npm install x402-fetch viem

Basic Usage with Base

import { createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { wrapFetchWithPayment } from "x402-fetch";
import { base } from "viem/chains";
 
// Create a wallet client
const account = privateKeyToAccount("0xYourPrivateKey");
const client = createWalletClient({
  account,
  transport: http(),
  chain: base,
});
 
// Wrap the fetch function with payment handling
const fetchWithPay = wrapFetchWithPayment(fetch, client);
 
// Make a request - payment is handled automatically
const response = await fetchWithPay("https://devnet.aimo.network/api/v1/chat/completions", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    model: "openai/gpt-4o",
    messages: [
      { role: "user", content: "Explain quantum computing" }
    ],
    max_tokens: 500
  })
});
 
const data = await response.json();
console.log(data);

The x402-fetch SDK automatically:

  1. Detects 402 Payment Required responses
  2. Parses payment requirements
  3. Creates and signs the payment transaction
  4. Retries the request with payment proof
  5. Returns the final response

Streaming Responses

The X402 SDK works seamlessly with streaming responses:

const response = await fetchWithPay("https://devnet.aimo.network/api/v1/chat/completions", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    model: "anthropic/claude-3-5-sonnet",
    messages: [{ role: "user", content: "Tell me a story" }],
    stream: true,
    max_tokens: 500
  })
});
 
// Process streaming response
const reader = response.body.getReader();
const decoder = new TextDecoder();
 
while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  
  const chunk = decoder.decode(value);
  process.stdout.write(chunk);
}

Advanced Configuration

Customize the SDK behavior with options:

const fetchWithPay = wrapFetchWithPayment(fetch, client, {
  onPaymentRequired: (paymentInfo) => {
    console.log('Payment required:', paymentInfo);
  },
  onPaymentSent: (txHash) => {
    console.log('Payment sent:', txHash);
  },
  onError: (error) => {
    console.error('Payment error:', error);
  },
  paymentTimeout: 120000, // 2 minutes in milliseconds
});

Request Format

The endpoint accepts standard OpenAI-compatible request format:

{
  "model": "openai/gpt-4o",
  "messages": [
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": "Your question here"}
  ],
  "stream": false,
  "max_tokens": 500,
  "temperature": 0.7,
  "top_p": 1.0
}
Supported Parameters:
  • model (required): Model name (e.g., openai/gpt-4o) or direct format (provider_pubkey:model_name)
  • messages (required): Array of message objects with role and content
  • stream: Enable streaming responses (default: false)
  • max_tokens: Maximum tokens to generate
  • temperature: Sampling temperature (0.0 to 2.0)
  • top_p: Nucleus sampling parameter
  • All other standard OpenAI parameters

Network Selection

The endpoint returns payment options for both Solana and Base networks. You can choose which network to use for payment:

Via Header (Optional):
curl -X POST "https://devnet.aimo.network/api/v1/chat/completions" \
  -H "X-Preferred-Network: solana" \
  -H "Content-Type: application/json" \
  -d '...'

Supported values: solana, base

Error Handling

Payment Expired

If you don't complete payment within the time limit:

{
  "error": {
    "message": "Payment request expired",
    "type": "payment_expired",
    "code": 402
  }
}

Solution: Start a new payment request.

Payment Verification Failed

If the payment transaction cannot be verified:

{
  "error": {
    "message": "Payment verification failed",
    "type": "payment_verification_failed",
    "code": 402
  }
}
Possible causes:
  • Transaction not yet confirmed on-chain
  • Incorrect payment amount
  • Payment sent to wrong address
  • Transaction signature invalid

Solution: Wait for transaction confirmation and retry, or verify payment details.

Insufficient Payment

If the payment amount is less than required:

{
  "error": {
    "message": "Insufficient payment amount",
    "type": "insufficient_payment",
    "code": 402,
    "details": {
      "required": "0.05",
      "received": "0.03"
    }
  }
}

Solution: Submit the correct payment amount.

Best Practices

Transaction Confirmation

Always wait for transaction confirmation before submitting payment proof:

  • Solana: Wait for "confirmed" or "finalized" commitment level
  • Base: Wait for at least 1 block confirmation

Payment Expiration

Payment requests expire based on the maxTimeoutSeconds field (typically 300 seconds / 5 minutes). Plan your payment flow accordingly:

  1. Read the maxTimeoutSeconds value from the payment option
  2. Calculate expiration time and show a countdown to users
  3. Request a new payment if expired
const solanaOption = paymentResponse.accepts.find(opt => opt.network === 'solana');
const expiresAt = Date.now() + (solanaOption.maxTimeoutSeconds * 1000);
console.log(`Payment must be completed by: ${new Date(expiresAt)}`);

Gas Fees

Factor in blockchain gas fees when displaying total costs to users:

  • Solana: Typically ~0.000005 SOL per transaction
  • Base: Variable based on network congestion

Error Recovery

The X402 SDK handles errors automatically, but you can add custom error handling:

import { createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { wrapFetchWithPayment } from "x402-fetch";
import { base } from "viem/chains";
 
const account = privateKeyToAccount(process.env.PRIVATE_KEY);
const client = createWalletClient({
  account,
  transport: http(),
  chain: base,
});
 
const fetchWithPay = wrapFetchWithPayment(fetch, client, {
  onError: async (error, retryCount) => {
    console.error(`Payment error (attempt ${retryCount}):`, error);
    
    if (retryCount < 3) {
      // Wait before retry
      await new Promise(resolve => setTimeout(resolve, 1000 * retryCount));
      return true; // Continue retrying
    }
    
    return false; // Stop retrying
  }
});
 
try {
  const response = await fetchWithPay("https://devnet.aimo.network/api/v1/chat/completions", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      model: "deepseek/deepseek-chat",
      messages: [{ role: "user", content: "Hello!" }],
      max_tokens: 100
    })
  });
  
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error("Request failed after retries:", error);
}

Manual X402 Flow (Advanced)

For advanced users who need direct control, you can implement the X402 flow manually without the SDK.

Manual Request Flow

  1. Make initial request without payment
  2. Receive 402 response with payment options
  3. Create and submit payment transaction on your chosen network
  4. Retry request with X-Payment: {network}:{transaction_signature} header
Example 402 Response:
{
    "error": "X-PAYMENT header is required",
    "accepts": [
        {
            "network": "solana",
            "maxAmountRequired": "123",
            "payTo": "Ge3jkza5KRfXvaq3GELNLh6V1pjjdEKNpEdGXJgjjKUR",
            "maxTimeoutSeconds": 300,
            "asset": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
        },
        {
            "network": "base",
            "maxAmountRequired": "123",
            "payTo": "0xf59bcCde20a59d49Ab0384BEB8fd874D28C46dEB",
            "maxTimeoutSeconds": 300,
            "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
        }
    ],
    "x402Version": 1
}
Submit Payment Proof:
curl -X POST "https://devnet.aimo.network/api/v1/chat/completions" \
  -H "Content-Type: application/json" \
  -H "X-Payment: base:0x1a2b...transaction-hash...3c4d" \
  -d '{...your request...}'

For full manual implementation details, refer to the X402 Protocol Specification.

Comparison of Payment Methods

FeatureAPI Key (Managed X402)Direct X402
AuthenticationAPI key requiredNone required
Account SetupDashboard accountWallet only
Payment MethodAutomatic (Coinbase wallets)Manual blockchain tx
Payment FlowTransparentExplicit 402 flow
Transaction FeesMinimal (managed)Gas fees per request
SDK SupportStandard HTTP clientx402-fetch required
Best ForProduction apps, high volumeDecentralized apps, testing

Security Considerations

Payment Verification

All payments are verified on-chain before processing requests. The system:

  1. Checks transaction exists and is confirmed
  2. Verifies recipient address matches
  3. Confirms payment amount is sufficient
  4. Ensures payment_id hasn't been used before

Private Key Safety

Never expose your private keys in your code:

// ❌ DON'T: Hardcode private keys
const account = privateKeyToAccount("0x1234567890abcdef...");
 
// ✅ DO: Use environment variables
const account = privateKeyToAccount(process.env.PRIVATE_KEY);
 
// ✅ DO: Use secure key management in production
// For browser apps, use wallet connection libraries:
// - Base/EVM: wagmi, ConnectKit, RainbowKit
// - Solana: @solana/wallet-adapter

Rate Limiting

The X402 endpoint has rate limits to prevent abuse:

  • Maximum 10 pending payment requests per IP
  • Maximum 100 requests per hour per IP

SDK Resources

Support

For issues with X402 payments:

  1. Check the x402-fetch documentation for SDK-specific help
  2. Review Error Handling documentation
  3. Verify transaction on blockchain explorer:
  4. Join our Discord server for community support
  5. Contact support@aimo.network for direct assistance

See Also