Agent Quickstart

AI agents can pay per-request with no account, no API key, and no pre-approval. Two protocols supported: x402 (USDC on Base) and MPP (Tempo).

How It Works

1. Agent sends a request to /v1/chat/completions with no auth header

2. Server returns HTTP 402 with payment requirements for both protocols

3. Agent picks a protocol, signs the payment, retries the request

4. Server verifies payment, routes to cheapest seller, streams response

x402 (USDC on Base)

The agent needs a Base wallet with USDC. SI advertises x402 upto first and exact second:

  • upto (preferred): authorize a max amount, then settle only actual usage after the response completes. Requires one-time USDC approval to Permit2; CDP sponsors x402 settlement gas when available.
  • exact (fallback): sign a fixed EIP-3009 payment for the estimated amount. Widely compatible, but may overpay versus actual usage.

Call the API directly at https://api.surplusintelligence.ai (the canonical API host) so redirects never drop the x402 payment headers.

JavaScript / TypeScript (upto, @x402/evm + viem):
import { createPublicClient, createWalletClient, http, publicActions } from 'viem'

import { base } from 'viem/chains'

import { privateKeyToAccount } from 'viem/accounts'

import { UptoEvmScheme } from '@x402/evm'

const endpoint = 'https://api.surplusintelligence.ai/v1/chat/completions'

const account = privateKeyToAccount(process.env.PRIVATE_KEY as 0x${string})

const publicClient = createPublicClient({ chain: base, transport: http() })

const walletClient = createWalletClient({ account, chain: base, transport: http() }).extend(publicActions)

// Important: pass an explicit address. Do not rely on walletClient.address.

const signer = {

address: account.address,

signTypedData: (msg: any) => account.signTypedData(msg),

readContract: publicClient.readContract.bind(publicClient),

getTransactionCount: publicClient.getTransactionCount.bind(publicClient),

estimateFeesPerGas: publicClient.estimateFeesPerGas.bind(publicClient),

}

const body = {

model: 'llama-3.3-70b',

messages: [{ role: 'user', content: 'Say exactly: pong' }],

max_tokens: 8,

}

// 1. Get a 402 challenge.

const challenge = await fetch(endpoint, {

method: 'POST',

headers: { 'Content-Type': 'application/json' },

body: JSON.stringify(body),

})

const paymentRequired = JSON.parse(

Buffer.from(challenge.headers.get('PAYMENT-REQUIRED')!, 'base64').toString(),

)

// 2. Prefer upto; fall back to exact if your client cannot sign Permit2 upto.

const upto = paymentRequired.accepts.find((a: any) => a.scheme === 'upto')

const paymentPayload = await new UptoEvmScheme(signer).createPaymentPayload(2, upto)

const paymentHeader = Buffer.from(JSON.stringify(paymentPayload)).toString('base64')

// 3. Retry the same request with payment attached.

const paid = await fetch(endpoint, {

method: 'POST',

headers: { 'Content-Type': 'application/json', 'PAYMENT-SIGNATURE': paymentHeader },

body: JSON.stringify(body),

})

console.log(paid.status) // 200

console.log(paid.headers.get('PAYMENT-RESPONSE')) // present on success

console.log(await paid.json()) // OpenAI-compatible response body

Python (x402 package):
from x402 import x402_fetch

response = x402_fetch(

'https://api.surplusintelligence.ai/v1/chat/completions',

wallet=wallet,

method='POST',

json={'model': 'claude-opus-4.6', 'messages': [{'role': 'user', 'content': 'Hello'}]}

)

MPP (Tempo)

Uses the Machine Payments Protocol. Agent attaches an Authorization: Payment header.

tempo request POST https://api.surplusintelligence.ai/v1/chat/completions \

-d '{"model": "claude-opus-4.6", "messages": [{"role": "user", "content": "Hello"}]}'

ACP v2 (Virtuals Protocol)

For agents in the Virtuals ecosystem: job-based commerce with on-chain escrow. A dedicated ACP guide is on the roadmap; see the Payments overview for current status.

API Key Auth (SIWE)

Agents with wallets can self-issue API keys — no browser, no Privy:

# Get SIWE challenge

curl .../v1/buyer/auth/challenge?address=0xAgentWallet

Sign and get buyer API key

curl -X POST .../v1/buyer/auth/keys \

-H "Content-Type: application/json" \

-d '{"message": "", "signature": "0x..."}'

Returns inf_xxx buyer key

Use like any OpenAI client

curl .../v1/chat/completions \

-H "Authorization: Bearer inf_xxx" \

-d '{"model": "claude-opus-4.6", "messages": [{"role": "user", "content": "Hello"}]}'

Buyer keys are persistent (survive restarts) and complement x402/MPP (which are per-request). Use SIWE keys for long-running agents, x402 for ephemeral/serverless.

Become a Seller

Agents can also sell inference — list your API capacity programmatically:

# Get seller key via SIWE

curl .../v1/seller/auth/challenge?address=0xAgentWallet

curl -X POST .../v1/seller/auth/keys \

-d '{"message": "...", "signature": "0x..."}'

Returns si_seller_xxx

List an offer

curl -X POST .../v1/seller/offers \

-H "Authorization: Bearer si_seller_xxx" \

-d '{"model": "claude-opus-4.6", "api_key": "your-provider-key",

"seller_base_url": "https://api.venice.ai/api/v1",

"price_input_per_1m": 12.00, "price_output_per_1m": 48.00}'

See the Seller API Reference for full documentation.

Pricing

Pricing is model-specific and market-based. SI routes to the cheapest available seller for the requested model, often below direct provider rates. The final x402 maximum is returned in the 402 challenge. With upto, the buyer authorizes that max but only actual usage is settled; with exact, the full estimate is settled.