Dev.to WebDev 🛠 Dev 👁 0 📖 5 min read

Brave just shipped x402. Here are both 402s, measured byte by byte.

Brave just shipped x402. Here are both 402s, measured byte by byte. November 13, 2026 · measured at 12:20Z On November 12, 2026 Brave announced that its Search API now accepts agentic payments over x402: no account, n

Brave just shipped x402. Here are both 402s, measured byte by byte.

November 13, 2026 · measured at 12:20Z

On November 12, 2026 Brave announced that its Search API now accepts agentic payments over x402: no account, no API key, $0.005 per request, USDC on Base, settled through Brave's own facilitator. Eight paths — web, news, images, videos, LLM context, and three local-search routes — behind search.agent.s.brave.app. The announcement helpfully recommends purl, the Stripe-developed CLI wallet.

This is the first time a major search vendor has put a pay-per-request 402 in front of its own index. It is also the first time we can hold our 402 next to someone else's and count bytes, instead of arguing about shapes in the abstract. So we did exactly that, unpaid, both sides, and wrote down the numbers.

The same protocol, two very different documents

Brave (search.agent.s.brave.app) minia2a (/x402/web-search)
Status 402 402
Total response headers 1,371 B 7,100 B
Payment-Required value 1,280 chars 5,292 chars
Response body 0 B 3,967 B = the base64-decoded document, byte for byte
Price in the challenge "5000" ($0.005) "10000" ($0.01)
Network / asset eip155:8453 / 0x8335…2913 eip155:8453 / 0x8335…2913
maxTimeoutSeconds 300 120
Document keys x402Version, error, resource{url, description, mimeType, serviceName, tags, iconUrl}, accepts[], extensions x402Version, error, resource, accepts[], extensions.bazaar{input, output.example}, budgetStandard, confirmationRequired, nextSteps, reliability, reliabilityLabel

The identical part is the one that matters most: version 2, eip155:8453, the same USDC contract, an accepts[0] that names scheme, network, amount, asset and payTo. A wallet that understands one document understands the other. That is the whole point of a protocol, and it is worth saying plainly on the day it starts being true across vendors.

The divergence is in what the document contains and where it travels.

Choice 1: the challenge lives in a header, or in a header and a body

Brave's proxy documents its own behaviour: "The answer is a 402 with an empty body: everything is in the response headers." That is a coherent choice and it keeps the response tiny. It is also a constraint on the client: an agent that reads bodies — because that is how every other API error is delivered — sees nothing. Their docs compensate by saying it three times in llms.txt.

We ship the same document twice: once base64 in Payment-Required, and once as the response body, byte-identical to the decoded header. A client can be lazy and read the body; a strict client can read the header; both get the same JSON. Twice the bytes, half the ways to get it wrong.

That body is not free. Our largest route's 402 currently prints a 5,387-byte retry line against an 8,190-byte proxy limit — 66% of the budget, with the rest held for the client's own payment header. Brave's 1,280-byte challenge has room to spare. Both designs work. The question a seller should ask is which failure is more likely in their fleet: an agent that only reads bodies, or an agent whose HTTP client truncates headers. We chose the first.

Choice 2: say what is not for sale, and why

The most useful part of Brave's llms.txt is the list of endpoints that are not sold, with reasons:

  • Answers (/res/v1/chat/completions) — billed per query and per token, which one fixed price cannot express.
  • Autosuggest and Spellcheck — they cost less than the fee a facilitator takes to settle a single payment.
  • Summarizer — deprecated.

And the rule that follows from it: "A path outside this table is a 404, never a payable 402." We verified it — /res/v1/chat/completions answers 404 with a zero-byte body, and a POST to a sold path answers 405. No challenge, no price, nothing to misread.

This is a better rule than it looks. The worst state an endpoint can be in is advertised but unpayable: a 402 that names a price on a route with no settlement branch behind it. It converts a discovery success into a payment failure, and the buyer never learns which one it was. We hit that class of bug and now guard against it directly — every endpoint we advertise must land on a route whose handler can actually settle a payment, and unlisted ids answer 404 rather than a challenge. Brave's "404, never a payable 402" is the same invariant, stated from the vendor's side.

Choice 3: the price floor is now a competitive number

Brave sells at 0.5 cents. Our catalog's floor is 1 cent, because a published price is stored as an integer number of cents; sub-cent listings are not expressible yet. That is a real constraint, not a marketing position, and it is the kind of thing that only becomes visible when someone else publishes a smaller number.

The interesting part is what Brave's own llms.txt says about it: a facilitator takes a fee per settled payment, and at some price that fee eats the sale. That is why autosuggest and spellcheck sit unsold rather than at a lower price. Anyone racing to the bottom of the price axis should read that sentence twice — the floor is not a policy, it is arithmetic.

What we took from it

  • The protocol is converging. Two independent deployments, same version, same chain, same asset, same accepts[] shape. Interop is no longer hypothetical.
  • Where the document travels is still a vendor choice. Header-only versus header-plus-body is not specified by the protocol and changes what clients must implement. Read the vendor's llms.txt before writing the client.
  • "The 402 is authoritative, the published table is advisory" is the right ordering, and Brave says it explicitly. Prices drift; the challenge at pay time is the contract.
  • Declaring what you don't sell is cheaper than supporting it badly. Three lines in a text file removed three ambiguous endpoints from an agent's discovery surface.

All numbers measured 2026-11-13 between 12:15Z and 12:22Z with unpaid requests against https://search.agent.s.brave.app/res/v1/llm/context?q=tallest+mountains and https://minia2a.uk/x402/web-search?q=tallest+mountains. Header sizes are total response-header bytes including status line and dates; the Payment-Required figure is the value length only. Prices and paths come from Brave's published llms.txt and openapi.json, cross-checked against the live 402.

Corrected 2026-11-13 12:45Z, about twenty minutes after publication: the first version printed maxTimeoutSeconds as 3 (a truncated read of the decoded document) and counted the Payment-Required value together with its trailing newline (1,281 and 5,293). The measured values are 300, 1,280 and 5,292. Both live endpoints were re-read to confirm; nothing else changed.

Originally published at minia2a.uk.

📰 Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.