# How an agent pays for a single public-data request

2026-08-03

> HTTP 402, sign USDC, retry — or a bby_live_ key. The product is the JSON. x402 is how the agent pays for it.

- Index: https://fetcher.sh/blog.md
- This page (HTML): https://fetcher.sh/blog/how-an-agent-pays-for-a-public-data-request

![A white robot arm in a workshop](https://images.unsplash.com/photo-1485827404703-89b55fcc595e?auto=format&fit=crop&w=1600&q=80)

Photo by Alex Knight on [Unsplash](https://unsplash.com/?utm_source=fetcher_sh&utm_medium=referral).

An agent should not open a dashboard to fetch a tweet. It should call a URL, pay if asked, and read JSON. That loop is the only thing this note is about. The product is still public web data. x402 is the rail.

Call a priced path with no payment. The response is **402 Payment Required**. The `payment-required` header is machine-readable: amount, asset (USDC), network (Base first, then Polygon, Arbitrum, Monad, Solana), recipient. The agent signs and retries with `X-Payment`. Libraries such as `@x402/fetch` run that loop so your code looks like an ordinary `fetch`.

Prepaid credits skip the loop. `Authorization: Bearer bby_live_…` debits a balance minted at [/topup](/topup). MCP clients do the same on `https://mcp.fetcher.sh`: paid tools return requirements in `_meta` unless a key is already on the connection. Free tools — `search_endpoints`, `describe_endpoint`, `check_balance` — do not charge. The envelope is always `{ status, message, data }`.

This is not a primer on trading USDC, and it is not the x402 spec as a crypto essay. For “Twitter without a developer account,” use the [Twitter host note](/blog/twitter-x-public-data-without-developer-platform). For whether you pay a month or a GET, use [pay per call](/blog/pay-per-call-vs-monthly-api-plans).

## A minimal client

Configure `@x402/fetch` with an ExactEvmScheme for `eip155:8453` (Base), then:

`fetch('https://twitter.fetcher.sh/api/search?query=hello')`

The wrapper handles 402. Or top up and send the Bearer key. Setup for agents is [`/skill.md`](/skill.md). Human docs: [/docs](/docs).

MCP is the same idea on a different transport. Point the client at `https://mcp.fetcher.sh`. Paid tools return payment requirements in `_meta` unless you already put a key on the connection. Free tools search the catalog without charging, so an agent can discover an endpoint before it spends.

A few practical rules save a lot of retries:

- Do not scrape HTML for a price. Read the 402.
- Do not store a human’s credit card in the agent. USDC on the advertised networks, or a prepaid key.
- Do not treat a 402 as an application bug. It is the checkout.
- Do not send the key to the wrong host naming scheme. `twitter.fetcher.sh` is the Twitter API; `fetcher.sh/api/twitter/…` still works as a compatibility path, but discovery documents point at the service origin.

Failed calls still return JSON. That matters more for agents than for humans. An HTML error page is a dead end for a tool-using model. An envelope with `status` and `message` is something it can branch on.

## When a key is the right answer

Sign-every-call is elegant when the agent already has a wallet and you do not want a long-lived secret in the environment. It is awkward when a cron runs sixty times a day and you would rather debit a balance.

In that case mint a key at [/topup](/topup), put `bby_live_` in the environment, and forget the 402 loop until the balance runs out. Credits do not expire. The key works on every host. Rotation is “mint another, delete the old one,” not “re-apply to a platform.”

MCP connections that already carry the key never see payment requirements on paid tools. Connections that do not will, and the client should be ready to settle or to fail closed. Free discovery tools stay free either way, which is how an agent can look up `google_maps_place_search` before it spends.

## A case: a cron that grounds itself once an hour

A small bot answers “what did the open web say about this repo in the last hour?” It should not hold a Google Cloud key, and it should not keep a human in the loop to paste a SERP.

Each hour it:

1. Calls [google.fetcher.sh](https://google.fetcher.sh) with `site:github.com` plus the repo name ([operators](/blog/google-search-results-json-site-filetype)).
2. Optionally pulls a News pass on [google-news.fetcher.sh](https://google-news.fetcher.sh) if the story is a headline, not a repo.
3. Writes a short summary with the rows in context ([live grounding](/blog/grounding-an-agent-on-live-google-results)).

Payment is either a wallet on the fetcher wrapper, or a `bby_live_` key in the environment. The bot never sees a dashboard. If it fails, the error is JSON. If it succeeds, the cost is the GETs.

That is all “an agent pays” means here. Grounding is a different job. OSINT is a different job. The rail is: challenge, sign or debit, JSON.

## A case: a chat agent that should not keep a secret

A desktop agent runs on a user’s machine. Putting a shared `bby_live_` key in the prompt is a leak waiting to happen. Putting the user’s wallet behind `@x402/fetch` means each GET is a payment they can see, for an amount the 402 already named.

The agent searches X, fetches a tweet, maybe pulls a YouTube comment thread. Each call is a checkout. The user can refuse. The agent does not accumulate a surprise invoice at the end of the month, because there is no month.

If that same agent later grows into a hosted service with many users, a prepaid key in the *server* environment is usually cleaner than asking every end user to sign USDC. The rail supports both. Pick the one that matches who is allowed to spend.

Grounding, OSINT, and market research all sit on top of this loop. They are not substitutes for it. If the agent cannot pay, it cannot fetch. If it can pay, the rest of the catalog is just URLs.
