x402
Pay the gateway per token from a wallet — the 402 challenge, accepts negotiation, and the PAYMENT-SIGNATURE header.
x402 pays for inference per token from a wallet — no prepaid plan, no sign-up, no vk_ key. The
client and gateway settle it in three exchanges: a 402 challenge, a signed authorization, and a
resend carrying that signature. For where x402 sits next to the workspace key and plan JWT, see
Authentication.
Base only
x402 settles in USDC on Base — mainnet eip155:8453 or the eip155:84532 Sepolia
testnet. No other chain is accepted.
Pay straight from a wallet
The recommended path skips the 402 round trip entirely: wrap fetch with @x402/fetch and
drop it into the OpenAI SDK. The wrapper handles the challenge, signs the authorization, and
resends — your call site looks identical to a normal completion.
import OpenAI from "openai";
import { wrapFetchWithPaymentFromConfig } from "@x402/fetch";
import { UptoEvmScheme } from "@x402/evm/upto/client";
import { privateKeyToAccount } from "viem/accounts";
// The wallet that authorizes and gets metered — fund it with USDC on Base.
const account = privateKeyToAccount(process.env.PAYER_PRIVATE_KEY as `0x${string}`);
// upto: sign a USDC MAXIMUM per request; the gateway runs the job, then settles
// only the tokens actually used (<= the max). Base only.
const fetchWithPayment = wrapFetchWithPaymentFromConfig(fetch, {
schemes: [
{ network: "eip155:8453", client: new UptoEvmScheme(account) }, // Base mainnet
// Base Sepolia testnet: network "eip155:84532"
],
});
// Drop the payment-aware fetch into the OpenAI SDK — no vk_ key; the wallet pays.
const venna = new OpenAI({
baseURL: "https://gateway.venna.net/v1",
apiKey: "x402", // placeholder; the signed payment is the auth, not a key
fetch: fetchWithPayment,
});
const completion = await venna.chat.completions.create({
model: "venna-fast",
messages: [{ role: "user", content: "Ping — paid straight from a wallet." }],
});UptoEvmScheme is what actually signs: on the first attempt the gateway returns 402, the
wrapper reads the challenge, signs a Permit2 authorization for a USDC maximum, and retries with
PAYMENT-SIGNATURE set. Every later call on that fetchWithPayment repeats the same dance
per-request — there's no session to keep alive.
upto never collects above your signature
upto is authorize-max, settle-actual: you sign a USDC maximum per request, the gateway
runs the job, then settles the metered usage — always ≤ the max, never more. Unused
authorization is never taken, and a request that produces no usage (an error, an empty
generation) settles 0.
$0.01 minimum per request
The settlement facilitator does not process transfers below $0.01, so every served
request settles at least 10000 atomic USDC — even when the metered usage is worth less.
Plan for it: on cheap models with short generations you pay the minimum, not the metered
price. For micro-requests, use an MPP session (meters off-chain,
no per-request minimum) or a subscription plan.
If you'd rather see the wire protocol the SDK wrapper is automating — useful for a non-JS client, or for debugging a rejected payment — walk it manually below.
Get the 402 PAYMENT-REQUIRED challenge
A request with no valid payment proof returns 402 with a challenge body instead of a run.
The envelope declares the payment options, scoped to Base by CAIP-2 network id — the client
does not guess them:
{
"x402Version": 2,
"error": "payment required: authorize a USDC maximum to continue",
"accepts": [
{ "scheme": "upto", "network": "eip155:8453", "asset": "USDC" },
{ "scheme": "upto", "network": "eip155:84532", "asset": "USDC" }
]
}Pick a scheme from accepts
The accepts array lists the schemes the gateway will take for this request. The client picks
one, builds the matching signed payload, and resends. upto is what the gateway offers today;
batch-settlement is upcoming:
| Scheme | How it settles |
|---|---|
upto | Sign a USDC maximum (Permit2); the gateway runs the job, then settles the metered usage — ≤ the max, floored at the $0.01 minimum. The primary mode. This is what UptoEvmScheme signs in the SDK example above. |
batch-settlement | Settle a maximum up front to credit a prepaid balance, then meter many requests against it. A payment-channel for wallets that fund ahead instead of signing per request. Not yet available — the gateway does not advertise it in accepts today. |
Resend with the PAYMENT-SIGNATURE header
Resend the original request with a PAYMENT-SIGNATURE header — a base64 JSON payload carrying
the chosen requirements, the signature, and the Permit2 authorization:
curl https://gateway.venna.net/v1/chat/completions \
-H "PAYMENT-SIGNATURE: $VENNA_PAYMENT_SIGNATURE" \
-H "Content-Type: application/json" \
-d '{ "model": "venna-fast", "messages": [{ "role": "user", "content": "ping" }] }'One header serves every scheme — which one applies was settled in the 402 challenge. The
Permit2 spender must be Venna's pinned x402 proxy (a foreign spender is rejected as no proof).
A malformed or absent header re-issues the challenge rather than wedging the request.
Settlement guarantees
- Capped — the settled amount can never exceed the signed maximum.
- Metered, with a floor —
uptosettles the real usage reported after generation (a high estimate refunds itself by settling less), never below the $0.01 facilitator minimum. - Idempotent — settlement is keyed to the single-use Permit2 nonce, so a replayed signature cannot double-charge.
- Zero-cost aborts — a request that produces no usage settles
0, with no on-chain transaction.
Next steps
- Authentication — how x402 compares to the workspace API key and the plan JWT.
- Quickstart — the first-call path with a
vk_key if you would rather skip wallet payments.