vennaVenna

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:

SchemeHow it settles
uptoSign 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-settlementSettle 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 floorupto settles 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.

On this page