x402 for Buyers

Two services run on this website, each on a different x402 scheme. Both are called through x402, with no accounts, no API keys, and no manual approval step before your first request. This page assumes you're writing a Node or TypeScript client — a script or backend holding its own private key, not a browser wallet flow — and shows the client-side code for both.

What you need

  • An EVM wallet — Optimism and Base are Ethereum layer-2 networks, so any Ethereum wallet works — or just a private key, for a script.
  • A small amount of USDC (a dollar stablecoin) on Optimism or Base — a few cents covers many requests. No ETH needed: you pay no gas, the facilitator submits every transaction.
  • npm install @x402/evm @x402/fetch viem

The two live endpoints

EndpointSchemeDoesPrice
imagegen-agent.fretchen.eu/genimgexactGenerates an image, mints it as an NFT~$0.07 / call
llm-agent.fretchen.eubatch-settlementOpenAI-shaped chat completion~$0.003 / message

Both are consumed on the site by the AI Image Generator and the AI Assistant — those are the UIs; the endpoints above are what your own code calls directly.

Which scheme, when

exact is one signature, one on-chain settlement, one result — the right shape for a single paid call. batch-settlement opens a USDC payment channel with one on-chain deposit, then every further message is an off-chain signed voucher against that channel — no transaction, no wallet prompt, until the channel is claimed later. Use it for many small calls to the same service, like a chat session.

TypeScript — exact scheme (image generation)

The official @x402/fetch SDK handles the 402 → sign → retry cycle for you:

import { x402Client, wrapFetchWithPayment } from "@x402/fetch";
import { registerExactEvmScheme } from "@x402/evm/exact/client";
import { privateKeyToAccount } from "viem/accounts";

const signer = privateKeyToAccount(`0x${PRIVATE_KEY}`);
const client = new x402Client();
registerExactEvmScheme(client, { signer });

const fetchWithPayment = wrapFetchWithPayment(fetch, client);

// Payment is handled automatically on the 402 response
const response = await fetchWithPayment(
  "https://imagegen-agent.fretchen.eu/genimg",
  {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ prompt: "A futuristic cityscape" }),
  }
);

const result = await response.json();
console.log("Image:", result.image_url);
console.log("NFT mint tx:", result.transaction_hash);

Loading the live spec…

TypeScript — batch-settlement (chat)

Unlike exact, this needs one network picked up front — client.register(network, scheme) below — because the channel it opens is specific to one chain. registerExactEvmScheme above has no such call because it can act on whichever network the 402 response names.

batch-settlement has no registerExactEvmScheme-style helper — the scheme is constructed directly with a signer and a channel store. The first call opens the channel: a deposit sized to cover several messages, not just one, so it moves more than the per-message price. Every call after that signs an off-chain voucher and settles instantly — no deposit, no wallet prompt:

import { x402Client, wrapFetchWithPayment } from "@x402/fetch";
import { BatchSettlementEvmScheme, InMemoryClientChannelStorage }
  from "@x402/evm/batch-settlement/client";
import { privateKeyToAccount } from "viem/accounts";

const account = privateKeyToAccount(`0x${PRIVATE_KEY}`);
// Minimal signer shape the scheme needs — an EVM account already satisfies it.
const signer = { address: account.address, signTypedData: (a) => account.signTypedData(a) };

// In-memory here; a browser client would persist this to localStorage so an
// open channel survives a page reload instead of opening a new one each visit.
const storage = new InMemoryClientChannelStorage();
const scheme = new BatchSettlementEvmScheme(signer, { storage });

const client = new x402Client();
client.register("eip155:8453", scheme); // Base, in CAIP-2 eip155:<chainId> form

const fetchWithPayment = wrapFetchWithPayment(fetch, client);

// OpenAI chat-completions shape — model must be one the agent advertises
const response = await fetchWithPayment("https://llm-agent.fretchen.eu", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    model: "mistral-large-latest",
    messages: [{ role: "user", content: "Hello" }],
  }),
});

const result = await response.json();
console.log(result.choices[0].message.content);

Loading the live spec…

Loading the live spec…

The batch-settlement contract is deployed on Base (mainnet and Sepolia) and Optimism mainnet — not Optimism Sepolia. Check llm-agent.fretchen.eu/openapi.json for the live, authoritative list of what the agent actually accepts.

What's protected, what isn't

Each payment is individually signed via EIP-3009 (exact) or the batch-settlement channel's voucher scheme. Every authorization is bound to a specific amount, recipient, and expiration — the protocol never has blanket access to your funds. A batch-settlement channel escrows only what you deposit; a voucher can never claim more than that.

Unspent escrow is not gone: a batch-settlement channel is withdrawable after a delay (currently ~24 hours in this facilitator's deployment) if you stop using it. See x402_batch_settlement_buyer.ipynb below for the withdrawal mechanics.

Try it without writing code

Both endpoints have a runnable Deno notebook in the facilitator's notebooks/ directory — genimg_x402_buyer.ipynb (exact) and x402_batch_settlement_buyer.ipynb (batch-settlement) — or use the live UIs directly: AI Image Generator and AI Assistant.

Comments

Loading comments...