# Anyfare: everything an agent needs > Anyfare is a payment router for AI agents. Put the pay host in front of the link of any x402 or MPP API and pay it from the chain you are on, or with a payment key against a balance of Credits. You pay only for calls the API answered with 2xx. The short guide is https://anyfare.agents.bakingbad.dev/llms.txt. This file holds every endpoint, request and answer, the 402, the errors and the limits. ## Hosts - Pay host: https://pay.anyfare.agents.bakingbad.dev. A routed call is https://pay.anyfare.agents.bakingbad.dev//: the API's link without https://. Also GET /_/check and GET /_/key. - API host: https://api.anyfare.agents.bakingbad.dev. Sign up, payment keys, top-ups, and public reads of calls, receipts and numbers. - Website: https://anyfare.agents.bakingbad.dev. Every page has a Markdown twin: add .md to its URL, or ask for it with Accept: text/markdown. - Console: https://console.anyfare.agents.bakingbad.dev. For people: the sign-in, top-ups and keys with a screen. - OpenAPI, for code generators: https://api.anyfare.agents.bakingbad.dev/openapi.json and https://pay.anyfare.agents.bakingbad.dev/openapi.json. - Agent skill: https://anyfare.agents.bakingbad.dev/skills/anyfare-buyer/SKILL.md. ## Keys - The master key controls the account. It starts with afm_live_ and works on the API host only. It is shown once, at sign-up, and a lost one can't be recovered: the account is lost with it. - A payment key pays calls. It starts with af_live_, works on the pay host only, and is shown once. It has limits the master key sets. Give an agent a payment key, never the master key. - Send either as Authorization: Bearer . A key of the wrong kind answers 401 wrong_key_type. - Keep keys in a file only the user can read. Never print them, paste them into a chat, put them in a URL, or log them. ## What to ask your user Ask before you sign up, before you make a payment key (and agree its limits), before you top up, and before you pay a price above the key's limit. Never raise a limit on your own. ## Start: check, sign up, make a key, call 1. Check a link. Free, no key, and it pays nothing: ```sh curl "https://pay.anyfare.agents.bakingbad.dev/_/check?url=pro-api.coinmarketcap.com/x402/v3/cryptocurrency/quotes/latest" ``` 2. Sign up. The answer has "masterKey" and "freeCredits": a new account may get free Credits, and the answer says how much ("0" when none). The command writes the answer to anyfare-account.json, which only the user can read (umask 077). "masterKey" is shown once. (The sign-up endpoint below has the same request without the file.) ```sh umask 077 curl -s -X POST https://api.anyfare.agents.bakingbad.dev/v1/accounts > anyfare-account.json ``` 3. Make a payment key with limits (see "Payment key limits"). "key" is shown once: ```sh ANYFARE_MASTER_KEY=$(jq -r .masterKey anyfare-account.json) curl -X POST https://api.anyfare.agents.bakingbad.dev/v1/keys \ -H "Authorization: Bearer $ANYFARE_MASTER_KEY" \ -H "Content-Type: application/json" \ -d '{"label":"research","dailyBudget":"5","maxPrice":"0.05"}' ``` 4. Call. A 2xx answer is charged and carries the receipt header; any other answer is free: ```sh curl -i "https://pay.anyfare.agents.bakingbad.dev/pro-api.coinmarketcap.com/x402/v3/cryptocurrency/quotes/latest?symbol=BTC&convert=USD" \ -H "Authorization: Bearer $ANYFARE_PAYMENT_KEY" ``` 5. Read the receipt: GET https://api.anyfare.agents.bakingbad.dev/v1/calls/, with the id from the header. Read what is left on the key: GET https://pay.anyfare.agents.bakingbad.dev/_/key. ## The pay host ### GET /_/check?url= (pay host) Is a link payable, at what price, and what we quote. Free, and pays nothing. - Address: https://pay.anyfare.agents.bakingbad.dev/_/check?url= - Who may call it: No key - `url`: the API's link, with or without `https://`. A query string in it stays. ```sh curl "https://pay.anyfare.agents.bakingbad.dev/_/check?url=pro-api.coinmarketcap.com/x402/v3/cryptocurrency/quotes/latest" ``` Answer, 200: ```json { "payable": true, "target": "https://pro-api.coinmarketcap.com/x402/v3/cryptocurrency/quotes/latest", "price": { "amount": "0.01", "currency": "USD", "asset": "base-usdc", "network": "eip155:8453" }, "quote": { "amount": "0.01", "fee": "0", "currency": "USD" }, "link": "https://pay.anyfare.agents.bakingbad.dev/pro-api.coinmarketcap.com/x402/v3/cryptocurrency/quotes/latest" } ``` A link that can't be paid is still a `200`: `{ "payable": false, "reason": "...", "message": "..." }`. The reasons are `invalid_target` (not a link), `host_not_allowed` (a host we don't route to, our own host, or a private address), `not_payable` (the API asks for no payment), `unsupported_payment` (it asks in a way we don't pay) and `upstream_unavailable` (it didn't answer). `price` is what the API asks. `quote` is what you pay through Anyfare, in USD. `link` is the link to call. Errors: 429 rate_limited. ### ANY // (pay host) Pay any x402 or MPP API: put the pay host in front of its link, without `https://`. - Address: https://pay.anyfare.agents.bakingbad.dev// - Who may call it: Payment key, x402 or MPP - Any method: GET, HEAD, POST, PUT, PATCH, DELETE or OPTIONS. The body and the query go to the API as they are. - Send exactly one of: `Authorization: Bearer `, `PAYMENT-SIGNATURE` (x402), or `Authorization: Payment ...` (MPP). Without one the answer is the `402`. ```sh curl -i "https://pay.anyfare.agents.bakingbad.dev/pro-api.coinmarketcap.com/x402/v3/cryptocurrency/quotes/latest?symbol=BTC&convert=USD" ``` Answer, 402: ``` The combined 402 (see "The 402" below). With a payment: the API's own answer, and the receipt header. ``` You pay only for a `2xx` answer. Any other answer costs nothing. Errors: 400 invalid_target, 400 host_not_allowed, 400 not_payable, 400 multiple_payment_methods, 401 invalid_key, 401 wrong_key_type, 402 insufficient_balance, 402 key_budget_exceeded, 402 key_allowance_exceeded, 402 key_price_limit, 402 payment_invalid, 429 rate_limited, 502 unsupported_payment, 502 quote_exceeded, 502 settlement_failed, 502 response_too_large, 503 upstream_unavailable, 503 payment_unavailable, 503 facilitator_unavailable. ### GET /_/key (pay host) The limits of a payment key and what is left of them, and the balance. - Address: https://pay.anyfare.agents.bakingbad.dev/_/key - Who may call it: Payment key ```sh curl https://pay.anyfare.agents.bakingbad.dev/_/key \ -H "Authorization: Bearer $ANYFARE_PAYMENT_KEY" ``` Answer, 200: ```json { "id": "", "label": "research", "allowance": null, "dailyBudget": "5", "maxPrice": "0.05", "expiresAt": null, "createdAt": "2026-11-12T09:00:00.000Z", "spent": { "today": "0", "total": "0" }, "remaining": { "allowance": null, "dailyBudget": "5", "balance": "0.1" } } ``` `remaining.balance` is what the account can spend now. Errors: 401 unauthorized, 401 invalid_key, 401 wrong_key_type, 429 rate_limited. ## Accounts and payment keys ### POST /v1/accounts (API host) Sign up. Returns the master key, once. - Address: https://api.anyfare.agents.bakingbad.dev/v1/accounts - Who may call it: No key - No body. ```sh curl -X POST https://api.anyfare.agents.bakingbad.dev/v1/accounts ``` Answer, 201: ```json { "id": "", "createdAt": "2026-11-12T09:00:00.000Z", "masterKey": "afm_live_…", "freeCredits": "0.1", "notice": "Store the master key now: it is shown only once. A lost master key can't be recovered, and the account is lost with it." } ``` `freeCredits` is the gift of this sign-up in USD. It is `"0"` when there is none: a new account may get free Credits, and this answer says how much. Errors: 429 rate_limited. ### GET /v1/account (API host) The account the master key belongs to. - Address: https://api.anyfare.agents.bakingbad.dev/v1/account - Who may call it: Master key ```sh curl https://api.anyfare.agents.bakingbad.dev/v1/account \ -H "Authorization: Bearer $ANYFARE_MASTER_KEY" ``` Answer, 200: ```json { "id": "", "createdAt": "2026-11-12T09:00:00.000Z" } ``` Errors: 401 unauthorized, 401 invalid_key, 401 wrong_key_type. ### POST /v1/account/master-key/rotate (API host) A new master key. The old one stops working at once. - Address: https://api.anyfare.agents.bakingbad.dev/v1/account/master-key/rotate - Who may call it: Master key ```sh curl -X POST https://api.anyfare.agents.bakingbad.dev/v1/account/master-key/rotate \ -H "Authorization: Bearer $ANYFARE_MASTER_KEY" ``` Answer, 200: ```json { "masterKey": "afm_live_…" } ``` Save the new key before you do anything else: it is shown once. Errors: 401 unauthorized, 401 invalid_key, 401 wrong_key_type. ### POST /v1/keys (API host) Make a payment key with limits. The key is shown once. - Address: https://api.anyfare.agents.bakingbad.dev/v1/keys - Who may call it: Master key - JSON body, every field optional: `label` (text, at most 60 characters), `dailyBudget` (USD per UTC day), `maxPrice` (USD per call), `allowance` (USD in all), `expiresAt` (a future time, ISO 8601). - Amounts are decimal strings with at most 6 decimals, such as `"0.05"`. Without `dailyBudget` the key gets the platform's default. ```sh curl -X POST https://api.anyfare.agents.bakingbad.dev/v1/keys \ -H "Authorization: Bearer $ANYFARE_MASTER_KEY" \ -H "Content-Type: application/json" \ -d '{"label":"research","dailyBudget":"5","maxPrice":"0.05"}' ``` Answer, 201: ```json { "id": "", "label": "research", "allowance": null, "dailyBudget": "5", "maxPrice": "0.05", "expiresAt": null, "createdAt": "2026-11-12T09:00:00.000Z", "revokedAt": null, "spent": { "today": "0", "total": "0" }, "remaining": { "allowance": null, "dailyBudget": "5" }, "key": "af_live_…" } ``` Errors: 400 invalid_request, 401 unauthorized, 401 invalid_key, 401 wrong_key_type. ### GET /v1/keys (API host) Every payment key of the account, with what each spent. - Address: https://api.anyfare.agents.bakingbad.dev/v1/keys - Who may call it: Master key ```sh curl https://api.anyfare.agents.bakingbad.dev/v1/keys \ -H "Authorization: Bearer $ANYFARE_MASTER_KEY" ``` Answer, 200: ```json { "keys": [ { "id": "", "label": "research", "allowance": null, "dailyBudget": "5", "maxPrice": "0.05", "expiresAt": null, "createdAt": "2026-11-12T09:00:00.000Z", "revokedAt": null, "spent": { "today": "0", "total": "0" }, "remaining": { "allowance": null, "dailyBudget": "5" } } ] } ``` It never returns a key itself. Errors: 401 unauthorized, 401 invalid_key, 401 wrong_key_type. ### PATCH /v1/keys/:id (API host) Change the limits of a payment key. - Address: https://api.anyfare.agents.bakingbad.dev/v1/keys/:id - Who may call it: Master key - JSON body with the fields to change: `label`, `allowance`, `dailyBudget`, `maxPrice`, `expiresAt`. `null` clears a limit that is optional. A field you leave out stays as it is. ```sh curl -X PATCH "https://api.anyfare.agents.bakingbad.dev/v1/keys/$ANYFARE_KEY_ID" \ -H "Authorization: Bearer $ANYFARE_MASTER_KEY" \ -H "Content-Type: application/json" \ -d '{"dailyBudget":"10","maxPrice":null}' ``` Answer, 200: ```json { "id": "", "label": "research", "allowance": null, "dailyBudget": "10", "maxPrice": null, "expiresAt": null, "createdAt": "2026-11-12T09:00:00.000Z", "revokedAt": null, "spent": { "today": "0", "total": "0" }, "remaining": { "allowance": null, "dailyBudget": "10" } } ``` Errors: 400 invalid_request, 404 not_found, 401 unauthorized, 401 invalid_key, 401 wrong_key_type. ### DELETE /v1/keys/:id (API host) Revoke a payment key. It stops working at once. - Address: https://api.anyfare.agents.bakingbad.dev/v1/keys/:id - Who may call it: Master key ```sh curl -X DELETE "https://api.anyfare.agents.bakingbad.dev/v1/keys/$ANYFARE_KEY_ID" \ -H "Authorization: Bearer $ANYFARE_MASTER_KEY" ``` Answer, 200: ```json { "id": "", "revokedAt": "2026-11-12T09:00:00.000Z" } ``` Errors: 404 not_found, 401 unauthorized, 401 invalid_key, 401 wrong_key_type. ### GET /v1/balance (API host) The Credits balance: available, and held for calls in flight. - Address: https://api.anyfare.agents.bakingbad.dev/v1/balance - Who may call it: Master key ```sh curl https://api.anyfare.agents.bakingbad.dev/v1/balance \ -H "Authorization: Bearer $ANYFARE_MASTER_KEY" ``` Answer, 200: ```json { "available": "0.1", "held": "0" } ``` Errors: 401 unauthorized, 401 invalid_key, 401 wrong_key_type. ### GET /v1/payments (API host) Every call the account paid, newest first, in pages. - Address: https://api.anyfare.agents.bakingbad.dev/v1/payments - Who may call it: Master key - `limit`: 1 to 100, default 50. `after`: the `next` of the page before. ```sh curl "https://api.anyfare.agents.bakingbad.dev/v1/payments?limit=5" \ -H "Authorization: Bearer $ANYFARE_MASTER_KEY" ``` Answer, 200: ```json { "payments": [ { "id": "pay_…", "requestId": "", "rail": "credits", "targetHost": "pro-api.coinmarketcap.com", "targetPath": "/x402/v3/cryptocurrency/quotes/latest", "amount": "0.01", "status": "captured", "createdAt": "2026-11-12T09:00:00.000Z", "updatedAt": "2026-11-12T09:00:00.000Z" } ], "next": null } ``` `next` is `null` on the last page. Errors: 400 invalid_request, 401 unauthorized, 401 invalid_key, 401 wrong_key_type. ## Top-ups ### GET /v1/topups/options (API host) The networks and tokens a top-up takes, and the least to send on each. - Address: https://api.anyfare.agents.bakingbad.dev/v1/topups/options - Who may call it: No key ```sh curl https://api.anyfare.agents.bakingbad.dev/v1/topups/options ``` Answer, 200: ```json { "asset": "USDC on NEAR", "networks": [ { "name": "base", "minimum": "1", "tokens": [ { "symbol": "USDC", "address": "0x…", "decimals": 6 } ] } ] } ``` `minimum` is in USD. `tokens` is left out while the token list can't be read: ask again in a moment. Errors: 503 topups_unavailable, 429 rate_limited. ### POST /v1/topups (API host) Ask for a deposit address: send a token there and the balance grows. - Address: https://api.anyfare.agents.bakingbad.dev/v1/topups - Who may call it: Master key - JSON body, all three fields required: `network` and `token` as `GET /v1/topups/options` names them, and `amount` in that token's units, such as `"20"`. ```sh curl -X POST https://api.anyfare.agents.bakingbad.dev/v1/topups \ -H "Authorization: Bearer $ANYFARE_MASTER_KEY" \ -H "Content-Type: application/json" \ -d '{"network":"base","token":"USDC","amount":"20"}' ``` Answer, 201: ```json { "id": "", "status": "waiting", "message": "Waiting for your transfer", "network": "base", "token": "USDC", "amount": "20", "depositAddress": "", "depositMemo": null, "send": "20", "sendAtLeast": "19.9", "estimatedCredits": "19.8", "payBy": "2026-11-12T10:00:00.000Z", "addressExpiresAt": "2026-11-12T10:00:00.000Z", "createdAt": "2026-11-12T09:00:00.000Z", "updatedAt": "2026-11-12T09:00:00.000Z", "deposited": null, "credited": null, "transaction": null, "refunded": null, "refundReason": null } ``` Send at least `sendAtLeast` to `depositAddress` before `payBy`. When `depositMemo` is not `null`, send it with the transfer. Credits are the USDC on NEAR the swap delivers. Errors: 400 unsupported_network, 400 unknown_token, 400 ambiguous_token, 400 invalid_amount, 400 amount_too_small, 400 topup_refused, 429 rate_limited, 502 topup_mismatch, 503 topups_unavailable, 401 unauthorized, 401 invalid_key, 401 wrong_key_type. ### GET /v1/topups/:id (API host) Where a top-up is. - Address: https://api.anyfare.agents.bakingbad.dev/v1/topups/:id - Who may call it: Master key ```sh curl "https://api.anyfare.agents.bakingbad.dev/v1/topups/$ANYFARE_TOPUP_ID" \ -H "Authorization: Bearer $ANYFARE_MASTER_KEY" ``` Answer, 200: ```json { "id": "", "status": "credited", "message": "Added to your balance", "network": "base", "token": "USDC", "amount": "20", "depositAddress": "", "depositMemo": null, "send": "20", "sendAtLeast": "19.9", "estimatedCredits": "19.8", "payBy": "2026-11-12T10:00:00.000Z", "addressExpiresAt": "2026-11-12T10:00:00.000Z", "createdAt": "2026-11-12T09:00:00.000Z", "updatedAt": "2026-11-12T09:00:00.000Z", "deposited": "20", "credited": "19.8", "transaction": "", "refunded": null, "refundReason": null } ``` There is no list of top-ups: keep the `id`. Errors: 404 not_found, 503 topups_unavailable, 401 unauthorized, 401 invalid_key, 401 wrong_key_type. ## Public reads ### GET /v1/catalog (API host) The endpoints Anyfare has routed, with prices and the ways to pay. - Address: https://api.anyfare.agents.bakingbad.dev/v1/catalog - Who may call it: No key - `q`: part of a host or path. `maxPrice`: USD. `limit`: 1 to 100, default 20. `cursor`: the `next` of the page before. ```sh curl "https://api.anyfare.agents.bakingbad.dev/v1/catalog?limit=3" ``` Answer, 200: ```json { "endpoints": [ { "id": "routed:pro-api.coinmarketcap.com/x402/v3/cryptocurrency/quotes/latest", "host": "pro-api.coinmarketcap.com", "path": "/x402/v3/cryptocurrency/quotes/latest", "title": "pro-api.coinmarketcap.com/x402/v3/cryptocurrency/quotes/latest", "summary": "A paid API that Anyfare routes payments to. Unverified: its owner hasn't registered it.", "priceFrom": "0.01", "currency": "USD", "methods": [ "credits", "x402", "mpp" ], "verified": false, "updatedAt": "2026-11-12T09:00:00.000Z", "link": "https://pay.anyfare.agents.bakingbad.dev/pro-api.coinmarketcap.com/x402/v3/cryptocurrency/quotes/latest" } ], "next": null } ``` Errors: 400 invalid_request, 429 rate_limited. ### GET /v1/calls (API host) Finished calls through Anyfare, newest first, in pages. - Address: https://api.anyfare.agents.bakingbad.dev/v1/calls - Who may call it: No key - `paidWith`: near, base, solana, tempo or credits. `status`: paid or free. `service`: part of a host. `host`: an exact host. `endpoint`: an exact path. `page`: from 1. `size`: 1 to 100, default 20. ```sh curl "https://api.anyfare.agents.bakingbad.dev/v1/calls?status=paid&size=3" ``` Answer, 200: ```json { "calls": [ { "id": "pay_…", "at": "2026-11-12T09:00:00.000Z", "service": "pro-api.coinmarketcap.com", "path": "/x402/v3/cryptocurrency/quotes/latest", "method": "GET", "paidWith": "base", "apiPaidWith": "base", "payer": "0x…", "amount": "0.01", "status": "paid", "apiStatus": 200, "ms": 340 } ], "page": 1, "size": 3, "total": 1, "totalCapped": false } ``` `total` is counted up to a cap: `totalCapped` is `true` when there are more. A Credits buyer is never named: `payer` is `null`. Errors: 400 invalid_request, 429 rate_limited. ### GET /v1/calls/stream (API host) Calls as they finish, as server-sent events. The same filters as the list. - Address: https://api.anyfare.agents.bakingbad.dev/v1/calls/stream - Who may call it: No key ```sh curl -N https://api.anyfare.agents.bakingbad.dev/v1/calls/stream ``` Answer, 200, content-type: text/event-stream: ``` retry: 3000 event: call data: {"id":"pay_…","at":"2026-11-12T09:00:00.000Z","service":"pro-api.coinmarketcap.com","path":"/x402/v3/cryptocurrency/quotes/latest","method":"GET","paidWith":"base","apiPaidWith":"base","payer":"0x…","amount":"0.01","status":"paid","apiStatus":200,"ms":340} : ping ``` A comment line `: ping` comes every 15 seconds. Open streams are limited per address; over the limit the answer is `429` with `Retry-After`. Errors: 429 rate_limited, 503 shutting_down. ### GET /v1/calls/:id (API host) The public receipt of one call. - Address: https://api.anyfare.agents.bakingbad.dev/v1/calls/:id - Who may call it: No key ```sh curl "https://api.anyfare.agents.bakingbad.dev/v1/calls/$ANYFARE_CALL_ID" ``` Answer, 200: ```json { "id": "pay_…", "at": "2026-11-12T09:00:00.000Z", "status": "paid", "apiStatus": 200, "service": "pro-api.coinmarketcap.com", "method": "GET", "path": "/x402/v3/cryptocurrency/quotes/latest", "buyer": { "paidWith": "credits", "network": null, "asset": "Credits", "amount": "0.01", "payer": null, "transaction": null, "explorerUrl": null, "settledAt": "2026-11-12T09:00:00.000Z" }, "api": { "paidWith": "base", "network": "eip155:8453", "asset": "USDC", "amount": "0.01", "payTo": "0x…", "transaction": "0x…", "explorerUrl": null, "status": "settled" }, "apiPrice": "0.01", "fee": "0", "ms": { "api": 340, "total": 520 }, "steps": [ { "step": "received", "at": "2026-11-12T09:00:00.000Z" }, { "step": "authorized", "at": "2026-11-12T09:00:00.000Z" }, { "step": "api_signed", "at": "2026-11-12T09:00:00.000Z" }, { "step": "api_answered", "at": "2026-11-12T09:00:00.000Z" }, { "step": "settled", "at": "2026-11-12T09:00:00.000Z" } ] } ``` `api` is `null` when we never paid the API. The last step is `settled` for a paid call and `released` for a free one, and is there only when the payment is final. Errors: 404 not_found, 429 rate_limited. ### GET /v1/stats (API host) Platform numbers: calls, volume, buyers, services, how buyers paid, top-ups. - Address: https://api.anyfare.agents.bakingbad.dev/v1/stats - Who may call it: No key ```sh curl https://api.anyfare.agents.bakingbad.dev/v1/stats ``` Answer, 200: ```json { "updatedAt": "2026-11-12T09:00:00.000Z", "calls": { "today": 12, "7d": 12, "30d": 12, "all": 12 }, "volume": { "today": "0.12", "7d": "0.12", "30d": "0.12", "all": "0.12", "currency": "USD" }, "buyers": { "today": 3, "7d": 3, "30d": 3, "all": 3 }, "services": { "today": 1, "7d": 1, "30d": 1, "all": 1 }, "byPaidWith": { "today": [ { "paidWith": "base", "calls": 12, "volume": "0.12" } ], "7d": [ { "paidWith": "base", "calls": 12, "volume": "0.12" } ], "30d": [ { "paidWith": "base", "calls": 12, "volume": "0.12" } ], "all": [ { "paidWith": "base", "calls": 12, "volume": "0.12" } ] }, "topups": { "30d": { "count": 1, "usd": "20" }, "all": { "count": 1, "usd": "20" } }, "daily": [ { "day": "2026-11-12", "calls": 12, "volume": "0.12" } ] } ``` Counted every few minutes. With nothing counted yet every number is `0` and `updatedAt` is `null`. `daily` is the last 30 UTC days, oldest first. Errors: 429 rate_limited. ### GET /v1/stats/live (API host) Fresh numbers for today and the last 24 hours, and calls per minute. - Address: https://api.anyfare.agents.bakingbad.dev/v1/stats/live - Who may call it: No key ```sh curl https://api.anyfare.agents.bakingbad.dev/v1/stats/live ``` Answer, 200: ```json { "at": "2026-11-12T09:00:00.000Z", "today": { "calls": 12, "volume": "0.12", "buyers": 3, "nearShare": 0.25 }, "last24h": { "calls": 12, "volume": "0.12", "volumeBefore": "0.1" }, "perMinute": [ { "minute": "2026-11-12T09:00:00.000Z", "calls": 1 } ] } ``` Errors: 429 rate_limited. ### GET /v1/stats/top (API host) The top services, endpoints, ways to pay and top-up tokens of a period. - Address: https://api.anyfare.agents.bakingbad.dev/v1/stats/top - Who may call it: No key - `period`: today, 7d, 30d or all. Default 30d. ```sh curl "https://api.anyfare.agents.bakingbad.dev/v1/stats/top?period=7d" ``` Answer, 200: ```json { "period": "7d", "updatedAt": "2026-11-12T09:00:00.000Z", "services": [ { "host": "pro-api.coinmarketcap.com", "calls": 12 } ], "endpoints": [ { "host": "pro-api.coinmarketcap.com", "path": "/x402/v3/cryptocurrency/quotes/latest", "calls": 12 } ], "paidWith": [ { "paidWith": "base", "calls": 12 } ], "topupTokens": [ { "network": "base", "token": "USDC", "count": 1 } ] } ``` Errors: 400 invalid_request, 429 rate_limited. ### GET /v1/services (API host) Services with at least one paid call: price, calls, buyers, volume. - Address: https://api.anyfare.agents.bakingbad.dev/v1/services - Who may call it: No key - `q`: part of a host. `sort`: calls, buyers, volume, endpoints or price. `page`: from 1. `size`: 1 to 100, default 20. ```sh curl "https://api.anyfare.agents.bakingbad.dev/v1/services?sort=calls&size=3" ``` Answer, 200: ```json { "services": [ { "host": "pro-api.coinmarketcap.com", "paidEndpoints": 1, "priceFrom": "0.01", "currency": "USD", "calls": 12, "buyers": 3, "volume": "0.12", "successRate": 1, "p50Ms": 340, "trend": [ 0, 0, 4, 8 ] } ], "page": 1, "size": 3, "total": 1, "totals": { "services": 1, "paidEndpoints": 1, "calls30d": 12 }, "updatedAt": "2026-11-12T09:00:00.000Z" } ``` `calls`, `buyers` and `volume` are the last 30 days. `trend` is paid calls per UTC day, oldest first. Errors: 400 invalid_request, 429 rate_limited. ### GET /v1/services/:host (API host) One service: its numbers, endpoints, days, ways to pay and top buyers. - Address: https://api.anyfare.agents.bakingbad.dev/v1/services/:host - Who may call it: No key - `period`: today, 7d, 30d or all. Default 30d. ```sh curl "https://api.anyfare.agents.bakingbad.dev/v1/services/$ANYFARE_SERVICE_HOST?period=30d" ``` Answer, 200: ```json { "host": "pro-api.coinmarketcap.com", "period": "30d", "updatedAt": "2026-11-12T09:00:00.000Z", "paidEndpoints": 1, "stats": { "calls": 12, "callsBefore": 8, "volume": "0.12", "buyers": 3, "returningShare": 0.33, "successRate": 1, "failedCalls": 0, "p50Ms": 340, "p95Ms": 800 }, "endpoints": [ { "path": "/x402/v3/cryptocurrency/quotes/latest", "method": "GET", "priceNow": "0.01", "calls": 12, "buyers": 3, "volume": "0.12", "successRate": 1, "p50Ms": 340, "link": "https://pay.anyfare.agents.bakingbad.dev/pro-api.coinmarketcap.com/x402/v3/cryptocurrency/quotes/latest" } ], "daily": [ { "day": "2026-11-12", "calls": 12, "volume": "0.12", "buyers": 3 } ], "byPaidWith": [ { "paidWith": "base", "calls": 12, "share": 1, "buyers": 3, "volume": "0.12" } ], "topBuyers": { "share": 1, "buyers": [ { "payer": "0x…", "paidWith": "base", "calls": 12, "spent": "0.12", "lastCallAt": "2026-11-12T09:00:00.000Z" } ] } } ``` `404` when no paid call has reached the host. A Credits buyer is listed with `payer: null` and `paidWith: "credits"`. Errors: 400 invalid_request, 404 not_found, 429 rate_limited. ### GET /v1/endpoints/stats (API host) The numbers of one endpoint: calls, buyers, volume, days, ways to pay. - Address: https://api.anyfare.agents.bakingbad.dev/v1/endpoints/stats - Who may call it: No key - `host` and `path`, both required: the exact host and the path without a query. `period`: today, 7d, 30d or all. Default 30d. ```sh curl "https://api.anyfare.agents.bakingbad.dev/v1/endpoints/stats?host=$ANYFARE_SERVICE_HOST&path=$ANYFARE_SERVICE_PATH&period=30d" ``` Answer, 200: ```json { "host": "pro-api.coinmarketcap.com", "path": "/x402/v3/cryptocurrency/quotes/latest", "period": "30d", "updatedAt": "2026-11-12T09:00:00.000Z", "stats": { "calls": 12, "buyers": 3, "volume": "0.12", "successRate": 1, "p50Ms": 340 }, "daily": [ { "day": "2026-11-12", "calls": 12 } ], "byPaidWith": [ { "paidWith": "base", "calls": 12 } ] } ``` An endpoint with no paid call answers `200` with zeros. Errors: 400 invalid_request, 429 rate_limited. ## The 402 A call to https://pay.anyfare.agents.bakingbad.dev// with no payment answers 402 with every way to pay at once. It is never cached. The headers: ``` HTTP/1.1 402 Payment Required content-type: application/json cache-control: no-store payment-required: www-authenticate: Payment id="…", realm="pay.anyfare.agents.bakingbad.dev", method="tempo", intent="charge", request="", expires="…" ``` The body is JSON. "accepts" holds the x402 options (the same list is in the PAYMENT-REQUIRED header, in base64), "credits" says how to pay with a key, and the WWW-Authenticate: Payment header holds the MPP charge on Tempo. Amounts in "accepts" are in the token's smallest unit (USDC has 6 decimals, so 10000 is $0.01). The values below are shortened: ```json { "x402Version": 2, "error": "Payment required", "resource": { "url": "https://pay.anyfare.agents.bakingbad.dev/pro-api.coinmarketcap.com/x402/v3/cryptocurrency/quotes/latest", "description": "pro-api.coinmarketcap.com/x402/v3/cryptocurrency/quotes/latest, through Anyfare" }, "accepts": [ { "scheme": "exact", "network": "eip155:8453", "asset": "0x…", "amount": "10000", "payTo": "0x…", "maxTimeoutSeconds": 300, "extra": { "name": "USD Coin", "version": "2" } }, { "scheme": "exact", "network": "solana:…", "asset": "…", "amount": "10000", "payTo": "…", "maxTimeoutSeconds": 300, "extra": { "feePayer": "…" } }, { "scheme": "exact", "network": "near:mainnet", "asset": "…", "amount": "10000", "payTo": "…", "maxTimeoutSeconds": 300, "extra": {} } ], "credits": { "price": "0.01", "currency": "USD", "authorization": "Bearer ", "signup": { "method": "POST", "url": "https://api.anyfare.agents.bakingbad.dev/v1/accounts" }, "topUp": { "method": "POST", "url": "https://api.anyfare.agents.bakingbad.dev/v1/topups", "options": "https://api.anyfare.agents.bakingbad.dev/v1/topups/options" } } } ``` The price is the same on every chain. Retry the same call (same method, path, query and body) with exactly one way to pay. Two at once answer 400 multiple_payment_methods. ### Pay with a payment key Send Authorization: Bearer af_live_… . The balance is held when the call starts, taken after a 2xx answer, and released otherwise. ### Pay with x402 (USDC on NEAR, Base or Solana) 1. Pick an option in "accepts". Sign it with an x402 v2 client for its network, "exact" scheme. Hand the option back as it is, "extra" included. 2. Send the same call with PAYMENT-SIGNATURE: (X-PAYMENT, the v1 header, is read too). 3. Sign it valid for at least 15 seconds, and no longer than maxTimeoutSeconds. A signed payment can be used once. 4. On NEAR, a payer has one payment in flight at a time: wait for it to settle before the next. 5. A 2xx answer settles your payment and carries PAYMENT-RESPONSE (base64 settlement, with the transaction). Any other answer settles nothing. ### Pay with MPP (USDC.e on Tempo) 1. Read the charge in WWW-Authenticate: Payment. It is bound to the pay host and has an expiry. 2. Sign a Tempo transaction for it in pull mode (an mppx client does this). Do not broadcast it: Anyfare does, after the API answers 2xx. A transaction you broadcast yourself is refused. 3. Send the same call at once with Authorization: Payment . The transaction must stay valid for at least 15 seconds. 4. A 2xx answer carries Payment-Receipt. ### The receipt header - Payment key: Anyfare-Receipt: id="pay_…", amount="0.01", currency="USD". The id is the call's id: https://api.anyfare.agents.bakingbad.dev/v1/calls/ is its public receipt, and https://anyfare.agents.bakingbad.dev/calls/ its page. - x402: PAYMENT-RESPONSE. MPP: Payment-Receipt. Their calls are listed in GET https://api.anyfare.agents.bakingbad.dev/v1/calls, filterable by host and endpoint. ## Payment key limits Set when the key is made, changed with PATCH https://api.anyfare.agents.bakingbad.dev/v1/keys/. They live in Anyfare's database: an agent can't talk its way past them. - dailyBudget: USD the key may spend in a UTC day. Over it: 402 key_budget_exceeded until 00:00 UTC. Default when you give none. - maxPrice: the highest price of one call. A dearer call: 402 key_price_limit. No limit when it is null. - allowance: USD the key may spend in all. Spent: 402 key_allowance_exceeded. No limit when it is null. - expiresAt: after it the key answers 401 invalid_key. Never when it is null. - label: a name, at most 60 characters. - Every key spends from the account's one balance. GET https://pay.anyfare.agents.bakingbad.dev/_/key shows "remaining" for the key and the balance. Revoking a key (DELETE) stops it at once. ## Top-ups Send any token from any chain a swap service supports to a deposit address, and the Credits arrive as USDC on NEAR. 1. GET https://api.anyfare.agents.bakingbad.dev/v1/topups/options lists the networks, their tokens, and the least to send (minimum, in USD). The list changes: read it each time. 2. POST https://api.anyfare.agents.bakingbad.dev/v1/topups with network, token and amount (master key). Ask your user first. 3. Send at least "sendAtLeast" of the token to "depositAddress" (with "depositMemo" when it is not null) before "payBy". Less than that is "incomplete": send the rest. Do not send after "payBy": the address expires. 4. Poll GET https://api.anyfare.agents.bakingbad.dev/v1/topups/ every few seconds until "status" is final. "credited" is the USD added to the balance. ``` - quoting: Getting a deposit address. - waiting: Waiting for your transfer. - incomplete: Received less than the least to send. Send the rest before payBy. - processing: Received. Converting. - credited (final): Added to your balance. - quote_failed (final): No deposit address: the quote was refused. Nothing to send. - quote_unknown (final): No deposit address: the quote did not answer. Nothing to send. Ask again. - expired (final): The time to pay ran out. Do not send to this address. - refunded (final): Not added. Anyfare holds the amount and will return it. - failed (final): Stopped. Anyfare is looking into it. ``` There is no list of top-ups: keep the id. ## The public reads No key. Any origin may read them. Each is limited per address: a 429 comes with Retry-After. They never name a Credits buyer: "payer" is null for Credits, and the receipt never shows a query string, a body or a header of a routed call. - Calls and receipts: GET https://api.anyfare.agents.bakingbad.dev/v1/calls, GET https://api.anyfare.agents.bakingbad.dev/v1/calls/stream, GET https://api.anyfare.agents.bakingbad.dev/v1/calls/. - Numbers: GET https://api.anyfare.agents.bakingbad.dev/v1/stats, /v1/stats/live, /v1/stats/top, /v1/services, /v1/services/, /v1/endpoints/stats. - Services agents paid, as a catalog with prices: GET https://api.anyfare.agents.bakingbad.dev/v1/catalog. - Pages with a Markdown twin: https://anyfare.agents.bakingbad.dev/services.md, https://anyfare.agents.bakingbad.dev/calls.md, https://anyfare.agents.bakingbad.dev/check.md?url=, https://anyfare.agents.bakingbad.dev/calls/.md. ## Errors Every error is {"error": {"code": "...", "message": "..."}}. 401 carries WWW-Authenticate: Bearer. 429 carries Retry-After. - 400 invalid_request (API host): The request is malformed. The message says what is wrong. Fix it and send it again. - 400 invalid_target (pay host): The link is not // with a DNS name. Check it with GET /_/check. - 400 host_not_allowed (pay host): Anyfare does not route to this host: it is blocked, it is our own, or it is a private address. Use another API. - 400 not_payable (pay host): The API asks for no payment, or not in a way a call can answer. Call it directly. - 400 multiple_payment_methods (pay host): Send exactly one of a payment key, an x402 payment and an MPP payment. - 400 unsupported_network (API host): Top-ups do not come from that network. The message lists the networks, and GET /v1/topups/options too. - 400 unknown_token (API host): No such token on that network. Use a symbol or address from GET /v1/topups/options. Never send a key here. - 400 ambiguous_token (API host): More than one token has that symbol. Send its contract address. - 400 invalid_amount (API host): The amount has more decimals than the token has, or is not a plain decimal. - 400 amount_too_small (API host): The top-up is worth less than the network's minimum. Send more. - 400 topup_refused (API host): The swap service refused the quote. No address was made. Change the token or the amount. - 401 unauthorized (both hosts): No key was sent. Send Authorization: Bearer : the master key to the API host, a payment key to GET /_/key. - 401 invalid_key (both hosts): The key is unknown, revoked, expired, or not a key. Ask your user for a new one. - 401 wrong_key_type (both hosts): A master key went to the pay host, or a payment key to the API host. Use the other key. - 402 insufficient_balance (pay host): The balance does not cover the price. Ask your user to top up, then call again. - 402 key_budget_exceeded (pay host): The key's daily budget is spent. It resets at 00:00 UTC. Ask your user before you raise it. - 402 key_allowance_exceeded (pay host): The key's allowance is spent. Ask your user for a new key or a higher allowance. - 402 key_price_limit (pay host): The price is above the key's highest price per call. Ask your user before you raise it. - 402 payment_invalid (pay host): The x402 or MPP payment does not match an option, was used before, or was refused. Nothing moved. Request the call again for the options and sign a new payment. - 404 not_found (API host): No such thing for this account: a key, a top-up, or a call that is not finished. - 429 rate_limited (both hosts): Too many requests from this address. Wait Retry-After seconds. - 502 unsupported_payment (pay host): The API asks in a way Anyfare does not pay. Nothing was charged. Use another API. - 502 quote_exceeded (pay host): The API raised its price after the quote. Nothing was charged. Check the link again. - 502 settlement_failed (pay host): The payment could not be settled, so the answer was not sent. Retry the call. - 502 response_too_large (pay host): The answer is too big to wait for a payment. Nothing was charged. - 502 topup_mismatch (API host): The quote was not what you asked for, so no address was given. Nothing to send. Ask again. - 503 upstream_unavailable (pay host): The API or our payer failed. Nothing was charged. Retry later. - 503 facilitator_unavailable (pay host): The service that checks x402 payments did not answer. Nothing was paid. Retry. - 503 payment_unavailable (pay host): A payment could not be checked, or another one on NEAR is in flight. Nothing was paid. Retry after Retry-After. - 503 redis_not_ready (pay host): Anyfare is not ready. Nothing was paid. Retry in a moment. - 503 topups_unavailable (API host): Top-ups are off, or the swap service did not answer. Nothing to send. Retry later. - 503 shutting_down (API host): The server is restarting. Open the stream again. ## Limits Requests are limited per address: sign-ups, checks, calls with no payment, public reads, streams and top-ups. Over a limit the answer is 429 rate_limited with Retry-After: wait that many seconds and send it again. A payment key has its own limit of calls per minute. Do not retry in a loop. ## Money Amounts are USD decimal strings, such as "0.01", with at most 6 decimals. Times are ISO 8601 UTC. Days are UTC days. The numbers in the answers above are examples, and every key, address and id in them is a placeholder.