Metered calls with x402

Charge for a sealed action per call, with no account, no API key and no invoice. The payment is an on chain transaction and the response carries its hash.

Why a sealed action is worth metering

An agent that wants to bid, vote, commit or hold a message until a deadline needs two things it usually cannot have at the same time: privacy until the deadline, and a way to pay for the service without opening an account first. Signing up is the part that does not survive contact with an autonomous caller. It needs an email, a card, a dashboard and a human.

x402 removes that step by using the status code HTTP already reserved for it. The server answers 402 Payment Required and says what it costs. The caller pays. The caller asks again, carrying proof. Nothing is stored about who called, because nothing needed to be.

Peal is a good fit for that shape because a call here is a discrete unit of work with a real cost and a real result: one sealed payload, held until a condition, then opened with a proof. It is not a subscription to a dashboard, it is a thing that happens once.

Watch it happen

Three parties and eight messages. The diagram below is wired to the same events the payer emits while it is actually paying, so every beam that lights corresponds to a request that was really made, and the hash that lands in it is one you can open in the explorer.

your code a browser tab, an agent, a server
peal the same handlers as the free API
tempo where the payment settles
  1. 1 ask POST /v1/x402/rounds, no payment
  2. 2 402 price, asset, payee, chain
  3. 3 fund tempo_fundAddress, no faucet form
  4. 4 pay ERC-20 transfer to the payee
  5. 5 mined the transfer lands in a block
  6. 6 retry X-PAYMENT: base64({txHash})
  7. 7 verify receipt, amount, payee, age
  8. 8 200 the work, plus the receipt
checking the price…

This runs for real. The page mints a keypair in this tab, asks Tempo to fund it, which the chain does for anyone with no faucet form and no account, pays the price above, and makes the call. The key never leaves the tab and is never written to storage. It costs you nothing.

How it works here

Every endpoint under /v1 is mounted a second time under /v1/x402. Same handlers, same request, same response. The only difference is that the metered twin answers 402 until it is shown a payment.

  1. Ask. Call /v1/x402/rounds with no payment. You get a 402 whose body names the asset, the amount, the payee and the chain.
  2. Pay. Send that ERC-20 transfer on Tempo. Gas there is itself an ERC-20, so the payment and its own gas come out of one balance.
  3. Ask again. Repeat the request with X-PAYMENT: base64({"txHash":"0x…"}).
  4. Get the work and the receipt. The response is the ordinary one, plus an X-PAYMENT-RESPONSE header carrying the transaction hash and an explorer link.

What the server checks

Before a paid call runs, the coordinator asks the chain four questions: has this hash been redeemed here before, did the transaction succeed, did it move at least the price in the right asset to the right payee, and did it land recently. Redemption is the database insert and the hash is the primary key, so one transaction buys exactly one call even if two requests race.

This is not the exact scheme, and it does not claim to be. The x402 exact scheme on EVM has the payer sign an EIP-3009 authorisation which a facilitator broadcasts. That needs a funded key on the server, and this coordinator holds none. So the scheme is named tempo-transfer: the payer broadcasts, and the server verifies against the chain. Same handshake, same settlement, reached from the other side. Naming it exact would mislead a client that knows what that word means.

In your own code

The whole client is the 402, the transfer and the retry. Nothing else.

// 1. ask, and read the price out of the refusal
let res = await fetch('https://peal.network/v1/x402/rounds', {
  method: 'POST',
  headers: { 'content-type': 'application/json' },
  body: JSON.stringify({ opens_in: 3600, tag: 'my-agent' }),
});

if (res.status === 402) {
  const { accepts: [req] } = await res.json();

  // 2. pay it: an ordinary ERC-20 transfer on the chain the 402 named
  const hash = await wallet.writeContract({
    address: req.asset,
    abi: parseAbi(['function transfer(address,uint256) returns (bool)']),
    functionName: 'transfer',
    args: [req.payTo, BigInt(req.maxAmountRequired)],
  });
  await publicClient.waitForTransactionReceipt({ hash });

  // 3. ask again, carrying the proof
  res = await fetch('https://peal.network/v1/x402/rounds', {
    method: 'POST',
    headers: {
      'content-type': 'application/json',
      'x-payment': btoa(JSON.stringify({ txHash: hash })),
    },
    body: JSON.stringify({ opens_in: 3600, tag: 'my-agent' }),
  });
}

const round = await res.json();
const receipt = JSON.parse(atob(res.headers.get('x-payment-response')));
console.log(round.id, receipt.explorer);

What a call costs

Ask GET /v0/x402 and it tells you, without having to trigger a 402 to find out. That endpoint is free, because a price list nobody can read is not a price list.

What people build with this

The pattern is worth something wherever the thing being paid for is a discrete action with a real cost, and the caller is not a person who will sit through a signup form. Five that fit.

Pay per bid, in a sealed auction

A bid costs a fraction of a cent to place. Bidders stay anonymous until the close, nobody opens an account, and the seller is not running a payments integration for a listing that might get four bids.

Why 402: a bidder who has to register is a bidder you lost. The whole point of a sealed auction is that it is cheap to enter and impossible to peek at.

Anti-spam that does not need identity

Charging for a slot in a round makes flooding it expensive without a captcha, an account or a rate limit keyed to an address. A thousand junk submissions costs a thousand payments.

Why 402: every other anti-spam measure works by recognising who you are. This one works without knowing.

Agents committing to each other

Two autonomous parties agree a price or an action, seal it until a deadline, and settle the fee in the same step. Neither holds an account with the other, and neither can see the other's number before the reveal.

Why 402: an agent cannot complete a signup flow. It can sign a transaction.

A report, a price, a model output: sealed now, opened at a stated moment, with the fee collected when it is sealed rather than invoiced later. The buyer can verify the reveal happened on time and was not edited.

Why 402: the payment and the commitment are one call, so there is no window where one exists without the other.

Metering your own API, on this pattern

The most common use, and it does not involve paying us. The gateway here is a working reference: refuse with a price, verify the transfer, redeem the hash once, then serve. Roughly three hundred lines.

Why 402: no keys to issue, no invoices to chase, no subscription for somebody who wanted one call.

What has settled here

Every payment this gateway has accepted, newest first. Each one is a transaction on a public chain, so this is the one number on the site that nobody has to take on trust.

loading…

The free API has not moved

Everything under /v1 is still free, still needs no key and still needs no wallet. Metering is a second door on the same rooms, for people who want to charge for what they build on this, or who want to see the handshake work before they do. The API reference has a switch at the top that sends every run button through the metered twin, so you can watch the same request take both paths.

Paid calls are counted on the activity dashboard. That number is the one thing on that page nobody has to take on trust: each one is a transaction on a public chain.