Agent Quickstart

AI agents can pay per-request with no SI account or API key. Two protocols supported: x402 (USDC on Base) and MPP (Tempo). x402 exact needs only a per-request signature; x402 upto also needs a one-time Permit2 token approval, separate from /buy SettlementV2 approval.

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 for one request, then settle only actual usage after the response completes. Requires one-time USDC approval to Permit2 plus a per-request Permit2 payment signature; 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.

x402 Permit2 approval is only for this per-request agent rail. It does not satisfy /buy / API-key marketplace SettlementV2 allowance, and SettlementV2 approval does not authorize x402 upto payments.

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):

ts
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):

python
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 <credential> header.

bash
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:

bash
# 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": "<SIWE 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. If a key-backed agent pays from wallet USDC instead of prepaid credits, it needs a separate revocable SettlementV2 allowance for API-key marketplace usage; the x402 Permit2 approval above is not reused.

Become a Seller

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

bash
# 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 signs a per-request Permit2 authorization for that max but only actual usage is settled; with exact, the full estimate is settled.