Docs · discovery API
Read the board from code.
Read-only JSON for agents that need an x402 endpoint that answered recently. No key, CORS open. Add ?pretty=1 to any endpoint for indented output.
Quick start
One call, live listings back
curl "https://callboard.website/api/services?status=live"Each service in the response carries
- status
- Live
- latencyMs
- <1
- payment.price
- 0.001 USDC
Values above are the demo endpoint’s last probe.
What “live” means
A service is Live when, at checkedAt, an unauthenticated request got 402 within 3s and every accepts[] entry named scheme, network, amount, payTo and asset. That is all it proves.
- Degraded: a 402 challenge slower than 3s, or only partly valid.
- Down: timeout (8s), network or TLS error, blocked target, more than 2 redirects, or HTTP 5xx.
- Unverified: 200 or another non-402 status, a 402 with no x402 body, or not checked yet.
A probe is one GET, then a POST with body {} if the GET did not return 402, sharing one 8s budget. Bodies are capped at 64KB. No cookies, auth or payment headers are sent, and nothing is ever paid.
GET/api/services
Listings with their latest cached probe. Without sort, Live comes first, then Degraded, Unverified and Down.
| param | type | default | notes |
|---|---|---|---|
| q | string | — | Case-insensitive match on name, description, URL host and category. |
| category | string | — | One of data, ai, finance, media, tools, other. |
| status | string | — | live, degraded, down or unverified. |
| network | string | — | Payment network as advertised, e.g. base, solana. |
| maxPrice | number | — | Max price per call in whole asset units (0.01 = one cent of USDC). Unknown-decimal assets are excluded. |
| sort | string | status | latency, price or newest. Missing values sort last. |
| limit | integer | 50 | Page size, 1 to 50. |
| cursor | string | — | Opaque nextCursor from the previous page. |
| owner | string | — | Only listings registered by this Solana address. |
- qstring
- Case-insensitive match on name, description, URL host and category.
- categorystring
- One of data, ai, finance, media, tools, other.
- statusstring
- live, degraded, down or unverified.
- networkstring
- Payment network as advertised, e.g. base, solana.
- maxPricenumber
- Max price per call in whole asset units (0.01 = one cent of USDC). Unknown-decimal assets are excluded.
- sortstringdefault status
- latency, price or newest. Missing values sort last.
- limitintegerdefault 50
- Page size, 1 to 50.
- cursorstring
- Opaque nextCursor from the previous page.
- ownerstring
- Only listings registered by this Solana address.
curl "https://callboard.website/api/services?status=live&maxPrice=0.01"GET/api/services/[id]
One listing by its registration signature, with every parsed accepts[] entry and the full probe. Returns 404 for unknown ids and 410 for listings removed by their owner.
curl "https://callboard.website/api/services/<signature>?pretty=1"POST/api/probe
Runs a fresh probe (no cache). Blocked targets are refused before any request: https on port 443 or 8443 only, resolved to a public IP, each redirect (max 2) checked again.
curl -X POST "https://callboard.website/api/probe" -H "content-type: application/json" -d '{"url":"https://api.example.com/x402/forecast"}'Caching
/api/servicessendsCache-Control: public, s-maxage=60, stale-while-revalidate=120.- Probe results are cached for 120s per URL; concurrent requests for one URL share a single probe.
- Each request probes at most 25 stale endpoints, 8 at a time. The rest keep their last result.
checkedAtis when our server last got an answer. There is no background monitoring.- The on-chain registry is re-read at most every 30s.
Rate limits
POST /api/probe: 20 requests per minute per IP, 16 concurrent probes globally.- Over either limit: HTTP 429 with a
Retry-Afterheader in seconds. - Limits live in memory per server instance, so they are best effort on serverless.
Registry format
No database. A listing is one Solana transaction: a 0-lamport transfer to the registry address, an SPL Memo v2 instruction (MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr) holding compact JSON, and a 400k compute-unit limit.
{"v":1,"action":"add","url":"https: / / api.example.com/ x402/ forecast","name":"Hourly forecast","desc":"One forecast for a lat/ lon, JSON.","category":"data"}| param | type | default | notes |
|---|---|---|---|
| v | number | 1 | Format version. Anything else is ignored. |
| action | string | — | add, update or remove. |
| url | string | — | The endpoint; it identifies the listing. Up to 300 characters. |
| name | string | — | Up to 40 characters. Required for add and update. |
| desc | string | "" | Up to 140 characters. |
| category | string | other | data, ai, finance, media, tools, other |
- vnumberdefault 1
- Format version. Anything else is ignored.
- actionstring
- add, update or remove.
- urlstring
- The endpoint; it identifies the listing. Up to 300 characters.
- namestring
- Up to 40 characters. Required for add and update.
- descstringdefault ""
- Up to 140 characters.
- categorystringdefault other
- data, ai, finance, media, tools, other
The whole memo must fit in 566 bytes.
- devnet
- D6tk1BXdV9x9VXahWY5V5EFZzXgg8TVYiTPkn6ptJGEU
- mainnet-beta
- 4uypN6fgPVLdng1FrvVgM2BvCx7g89PYPJwyZyHkjE4M
Ownership rules
- The fee payer of the first valid add for a URL owns it.
- Only the owner’s later memos count, and the latest wins.
- A remove from the owner hides the listing; the owner may add it again later.
- Memos from other wallets for an owned URL, and malformed memos, are ignored.
Demo endpoint
/api/demo-x402 is Callboard’s own test fixture, not a third-party service. It always answers 402 with a sample requirement in devnet USDC, which has no value on any deployment, so a demo payment can never cost real money.
curl -i "https://callboard.website/api/demo-x402?pretty=1"