DEV Community

call402
call402

Posted on Originally published at call402.com

HTTP 402 Is Back — Let Your Agent Pay $0.005 per API Call (Working Code Inside)

Your agent needs an API. The normal options are all built for humans: sign up, verify an email, add a credit card, get an API key, pick a subscription tier, pay for 10,000 calls to use 17 of them.

There is a fourth option, and it is 30 years old: HTTP status code 402 Payment Required was reserved in the original HTTP spec "for future use." The future arrived. The x402 protocol (v2, stewarded by Coinbase) turns 402 into a working payment handshake: the server answers with a price quote, the agent signs a stablecoin payment authorization, a facilitator settles it on-chain, and the API responds — no accounts, no keys, no subscriptions. Payment is the authentication.

This is not a whitepaper tour. Everything below runs against a live store (call402.com) where 15 small APIs — FX rates, phone/email validation, SEC company facts, text structuring, and more — are sold per call for $0.002–$0.005 USDC on Base. The quote you are about to see is a real one, captured from the live server.

Step 1: Ask, get a quote (a real one)

Call any endpoint without paying and you get HTTP 402 plus a machine-readable quote:

curl -X POST https://call402.com/api/phone-lookup \
  -H 'Content-Type: application/json' \
  -d '{"number": "+14155552671"}'
Enter fullscreen mode Exit fullscreen mode
{
  "x402Version": 2,
  "accepts": [{
    "scheme": "exact",
    "network": "eip155:8453",
    "amount": "5000",
    "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
    "payTo": "0xAc6F1C3C3b17040730F16dC24Ee9993e9565BE4A",
    "maxTimeoutSeconds": 300,
    "extra": { "name": "USD Coin", "version": "2" }
  }]
}
Enter fullscreen mode Exit fullscreen mode

Read it like a price tag: amount is in atomic units, so 5000 = $0.005 (USDC has 6 decimals). asset is the USDC contract on Base, payTo is the seller, and you have 300 seconds to pay this exact quote.

Step 2: Pay and call — the complete buyer

With the official TypeScript libraries, the entire buyer is this:

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

const signer = privateKeyToAccount(process.env.EVM_PRIVATE_KEY as `0x${string}`);
const client = new x402Client();
client.register("eip155:*", new ExactEvmScheme(signer));
const fetchWithPay = wrapFetchWithPayment(fetch, client);

const res = await fetchWithPay("https://call402.com/api/phone-lookup", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ number: "+14155552671" }),
});
console.log(await res.json());

// Settlement proof comes back in the PAYMENT-RESPONSE header:
const proof = res.headers.get("PAYMENT-RESPONSE");
if (proof) {
  const settlement = JSON.parse(Buffer.from(proof, "base64").toString("utf8"));
  console.log("tx:", settlement.transaction, "payer:", settlement.payer);
}
Enter fullscreen mode Exit fullscreen mode
npm i @x402/fetch @x402/core @x402/evm viem
Enter fullscreen mode Exit fullscreen mode

The wrapper sees the 402, builds an EIP-3009 payment authorization from the quote, retries with the signature attached, and the facilitator settles the USDC transfer on Base. What comes back is ordinary JSON:

{ "valid": true, "country": "US", "type": "FIXED_LINE_OR_MOBILE",
  "e164": "+14155552671", "national": "(415) 555-2671" }
Enter fullscreen mode Exit fullscreen mode

Every other endpoint at the store — and any x402 seller — works exactly the same way. One buyer, every shop.

Step 3: Don't trust the 200 — verify the settlement

Decode the PAYMENT-RESPONSE header (it is Base64 JSON) and check three things: the transaction exists on a Base explorer with status success, the USDC Transfer log goes from your address to the quote's payTo, and the transferred value equals the quoted amount exactly. If any of the three fails, log it and stop — do not just pay again.

The failures you will actually meet:

Symptom Likely cause Fix
402 again after paying Authorization expired (default window 300 s) Rebuild the payload at retry time, never cache it
invalid_signature Wrong EIP-712 domain or chain Copy extra.name / extra.version from the quote verbatim; chainId 8453
Amount confusion Atomic units vs dollars 5000 atomic = $0.005. Convert once, in one place

Step 4: Put a budget policy in front of the wallet

An agent with a signing key is an agent that can spend. Four rules keep that boring:

  1. Per-call cap (e.g. $0.01) and a daily cap (e.g. $1.00), checked before signing.
  2. Host and asset allowlists — your buyer should refuse quotes from anywhere else.
  3. A dedicated wallet with a capped float. Never your main wallet.
  4. An append-only spend ledger: tx hash, endpoint, amount, reconciled against on-chain transfers.

The full kit is itself sold through x402

The complete integration pack — this TypeScript buyer, a dependency-light Python buyer with manual EIP-3009 signing, the full failure table, and a production checklist — is sold at the same store through the same protocol: POST to https://call402.com/api/x402-integration-pack with no payment and the 402 quote you get is the checkout. Half a cent, settled the way this article just taught you. The longer explainer, with the protocol background, lives at call402.com/learn/x402-explained, and the machine-readable catalog of all 15 endpoints is at call402.com/pricing.

A real question to end on: if your agent had a wallet with a $1/day budget, what is the first thing you would let it buy on its own — and what would you never let it pay for? I am building in this space and genuinely want to know where people draw that line.

Top comments (0)