Pay per request (x402)

An agent with a crypto wallet can use UberLLM with no account and no API key. It pays for each request in USDC on Base, using the open x402 payment standard (version 2).

This works for chat: POST /v1/chat/completions and POST /v1/messages. Images, video and music still need a key.

To check that pay-per-request is switched on, open api.uberllm.dev/x402. It shows the network, the USDC contract and the wallet that gets paid. If it answers "404 not found", pay-per-request is off. Use a key instead (Quickstart).

How it works

  1. Send the request with no key. The answer is HTTP 402 Payment Required. The PAYMENT-REQUIRED header (base64 JSON, also in the body) says how much the request can cost at most, and which ways to pay are accepted.
  2. Your wallet signs one of those options. Send the same request again with the signature in the PAYMENT-SIGNATURE header.
  3. UberLLM checks the payment, answers, then collects the payment. A normal (non-streaming) answer comes with the receipt in the PAYMENT-RESPONSE header, which includes the on-chain transaction.

Each signature pays for one request. To make another request, sign again.

What you pay

The 402 quotes the most the request can cost. That is your prompt plus max_tokens of output, at the priciest route the request may take, plus 10%. Set max_tokens to keep the quote low.

There are two ways to pay:

  • upto (offered first). You sign the quote as a ceiling. After the answer, only the real cost is taken, rounded up to the next millionth of a dollar. The first payment needs a one-time USDC approval. Where the payment service supports it, that approval needs no gas.
  • exact. The full quoted amount is taken, even if the request used less. Nothing is refunded. Pick exact only if your wallet can't do upto.

You are never charged more than the amount you signed. If nothing is served (no model available, an error before the answer starts), nothing is taken.

Try it with curl

curl -i https://api.uberllm.dev/v1/chat/completions \
  -H 'content-type: application/json' \
  -d '{"model":"deepseek/deepseek-v4-flash","max_tokens":200,"messages":[{"role":"user","content":"Hello"}]}'
# HTTP/1.1 402 Payment Required
# PAYMENT-REQUIRED: eyJ4NDAyVmVyc2lvbiI6Mi…
#
# {"x402Version":2,"error":"PAYMENT-SIGNATURE header is required",
#  "accepts":[{"scheme":"upto","network":"eip155:8453","amount":"…","asset":"0x8335…2913","payTo":"0x…",…},
#             {"scheme":"exact",…}]}

amount is in USDC base units: 1,000,000 is $1. Sign one entry of accepts with your wallet. Then send the same request again with -H 'PAYMENT-SIGNATURE: <base64 payment>'.

From code

An x402 client library does the 402, signing and retry for you. In JavaScript:

import { wrapFetchWithPaymentFromConfig } from "@x402/fetch";
import { ExactEvmScheme } from "@x402/evm";
import { privateKeyToAccount } from "viem/accounts";

const account = privateKeyToAccount(process.env.WALLET_PRIVATE_KEY as `0x${string}`);
const pay = wrapFetchWithPaymentFromConfig(fetch, {
  schemes: [{ network: "eip155:8453", client: new ExactEvmScheme(account) }],
});

const res = await pay("https://api.uberllm.dev/v1/chat/completions", {
  method: "POST",
  headers: { "content-type": "application/json" },
  body: JSON.stringify({
    model: "deepseek/deepseek-v4-flash",
    max_tokens: 200,
    messages: [{ role: "user", content: "Hello" }],
  }),
});
console.log(await res.json());

To pay only the real cost, also register UptoEvmScheme from @x402/evm/upto/client. Libraries for Go and Python are listed at x402.org.

Good to know

  • Streaming works. With "stream": true, the answer streams as usual. The payment is collected when the stream ends. There is no PAYMENT-RESPONSE header, because the headers were already sent. Your wallet shows the transfer.
  • One wallet, at most 4 paid requests at a time.
  • If a payment can't be collected after the answer (for example, the wallet was emptied in the meantime), a normal answer is held back and you get 402 payment_failed. That wallet then can't pay for 24 hours.
  • Version 1 x402 (X-PAYMENT header) is not accepted. Use a version 2 client.
  • Lots of requests? An account with prepaid credit is simpler and has no on-chain step: sign up.

Errors

HTTP meaning do
402 + PAYMENT-REQUIRED no payment, or the payment was refused (the error field says why) sign one of accepts and retry
402 payment_failed the answer was ready but the payment couldn't be collected fund the wallet; that wallet can pay again in 24 hours
400 invalid_payment PAYMENT-SIGNATURE isn't a base64 x402 v2 payment fix the client
429 rate_limited 4 paid requests already running from this wallet wait for one to finish
503 service_unavailable the payment service is briefly down retry in a minute