# Roundhouse: start paying with x402

Roundhouse is the data layer for the agent economy. It indexes x402 settlements
across chains, serves the whole dataset over HTTP and SQL, runs a facilitator
that settles payments so payers need no ETH, and lists the x402 services other
agents are already paying for.

Everything below is live. Base URL for the data API:

    https://roundhouse.studio/api/v0

That host 308s to the `www.` one, so follow redirects — `curl -L`, or any
client that follows them by default (`fetch` does).

No key and no wallet are needed to read. You need a wallet with USDC on Base
only when you want to pay for something.

## 0. If you can run commands, install the helper first

`@roundhouseai/x402` does the whole payment loop — request, 402, price check
against your caps, sign, retry, receipt — in one command, with idempotent retries
and a local ledger. It has zero runtime dependencies, never sees a private key
(signing goes out to a pluggable wallet backend), and already points at this index
for discovery. Node 20.10+.

```bash
npm i -g @roundhouseai/x402        # then: rh-x402 <url>
npx @roundhouseai/x402 <url>       # or zero-install

rh-x402 probe    <url>                # what does this cost? never pays
rh-x402 call     <url> --max 0.01     # get the data, within a cap
rh-x402 discover <capability>         # who sells this cheapest?
rh-x402 history --since 24h --sum     # what have I spent?
```

**The command is `rh-x402`.** This package deliberately ships no `x402`
binary — the unscoped `x402` package on npm is a different project with its own
`x402` command, so on a machine with both the short name would be a coin toss.
Zero-install is `npx @roundhouseai/x402`, never `npx x402`.

`discover` needs no wallet, no key and no config, so the line above works the
moment the helper is installed. To pay for something you need a wallet, and one
command creates it — it asks how the key should be held (an OWS vault, an
imported key, or one generated locally), installs what that choice needs, writes
the config and prints the address to fund:

```bash
rh-x402 wallet create
rh-x402 wallet create --path ows --name my-agent --install --policy   # non-interactive
```

An OWS policy makes the vault refuse a chain or token contract outside x402
before the key is decrypted. Note what it cannot do: **it bounds what may be
signed, never how much.** `limits.maxPerCall` and `limits.dailyCap` are the
only amount caps, and they are computed from a local ledger by the process that
signs — advisory, not binding.

Always pass `--max`: it refuses anything pricier rather than paying it.
`--dry-run` runs every gate and stops before signing. Retry a failed call by
re-running the **identical** command — the signed authorization is cached and
reused, so a retry cannot become a second payment; never add `--no-cache` to work
around an error. Branch on the exit code: `0` ok, `40` not x402-compliant,
`42` wallet policy, `43` allowlist, `44` over `--max`, `45` budget or daily
cap, `46` balance, `47` signer down, `50` paid with no valid response (re-run
it). Codes 42, 43, 45 and 46 need a human decision.

Optionally, forward your call telemetry back to the index. Off by default; it is
how an endpoint nobody has paid through an observed facilitator gets liveness and
pricing signal at all:

```bash
rh-x402 config set telemetry.sink.url https://www.roundhouse.studio/api/v0/telemetry
rh-x402 config set telemetry.sink.token env:ROUNDHOUSE_API_KEY   # optional
rh-x402 config set telemetry.sink.enabled true
```

Keep `telemetry.payload` at `hash` (the default) if you enable it — at
`full` the sink would carry your request and response bodies off the machine.
Bodies are stripped at ingest and never stored, but the place to stop them is
before they leave. What you send is self-reported: it is held apart from the
settlement index, never counted as settled volume and never promoted into it.
A sink failure never fails a call; the batch queues in `~/.x402/outbox/` and is
replayed on the next invocation.

If you cannot shell out, `rh-x402 serve` runs the same engine on
`127.0.0.1:8403` over HTTP, or over MCP with `--mcp` — same wallet, same gates,
same error codes. Treat it as a hot-wallet API even on localhost.

Source and full reference: https://github.com/roundhouseai-io/x402

## 1. Read the index — free, no auth

```bash
curl -L "https://roundhouse.studio/api/v0/flows?limit=5"
curl -L "https://roundhouse.studio/api/v0/transactions?limit=5"
curl -L "https://roundhouse.studio/api/v0/agents/<wallet>"
curl -L "https://roundhouse.studio/api/v0/merchants/<wallet>"
```

Aggregate numbers are per-entity by design. Site-wide totals live only on
https://roundhouse.studio/stats — do not expect a global volume field on
these endpoints.

## 2. Make your first x402 payment (one request, $0.01)

`GET /v0/test/x402` is a real paywalled resource. Call it without payment and
you get a standard 402 whose `accepts` array tells you exactly what to sign.
Pay it and you get a Roundhouse API key that raises your SQL limit to 240
queries/minute for 30 days.

```bash
# 1. See the challenge — free, and the helper never pays on a probe.
rh-x402 probe https://www.roundhouse.studio/api/v0/test/x402
curl -iL "https://roundhouse.studio/api/v0/test/x402"

# 2. Pay it. Needs USDC on Base — no ETH: the facilitator covers the gas.
rh-x402 call https://www.roundhouse.studio/api/v0/test/x402 --max 0.02
#    → { "ok": true, "paid": true, "amount": "0.01", "receiptId": "…",
#        "body": { "api_key": "rh_live_…", "expires_at": "…" } }
```

Or with any standard x402 client:

```javascript
import { wrapFetchWithPayment } from 'x402-fetch';

const pay = wrapFetchWithPayment(fetch, account);
const { api_key, expires_at, limits } = await pay(
  'https://roundhouse.studio/api/v0/test/x402',
).then((r) => r.json());
```

The key is returned exactly once — only its hash is stored, so copy it
immediately. The payment is indexed like any other, so it appears in
`/v0/flows` within about a minute. One key is issued per settlement.

Send the key as a bearer token, or as `x-api-key`:

    authorization: Bearer rh_live_...

## 3. Ask the dataset anything — read-only SQL

```bash
curl -L -X POST "https://roundhouse.studio/api/v0/sql" \
  -H 'authorization: Bearer rh_live_...' \
  -H 'content-type: application/json' \
  -d '{"sql":"select wallet, inbound_usd, inbound_count from mv_entity_rollups order by inbound_usd desc limit 10"}'
```

Rules the runner enforces, so write for them:

- One statement, `SELECT` or `WITH` only. No semicolons, no comments.
- Readable tables: `chains`, `settlements`, `entities`, `agents`,
  `agent_feedback`, `facilitators`, `external_resources`,
  `mv_entity_rollups`, `mv_entity_daily`, `mv_global_stats`,
  `mv_global_daily`. Nothing else is reachable.
- At most 300 rows per response, 8-second statement timeout.
- `mv_entity_rollups` has no `display_name` — join `entities` for names.
- Anonymous callers get 30 queries/minute; a trial key gets 240.

## 4. Find services worth paying — discovery

The service directory is built from the public x402 discovery catalog and
enriched with what the index has actually observed on-chain, so you can tell a
live endpoint from a listing.

```bash
# Grouped by the job an endpoint does, cheapest first, with the going rate.
rh-x402 discover web-search
rh-x402 call x402:web-search --data.query "…" --max 0.01   # cheapest allowed provider
```

`stats.spot` is the call-**weighted** going rate, not the median — one publisher
listing forty near-identical endpoints would otherwise read as forty votes for its
own price. `spotBasis: "median"` means no offer reported any calls and the figure
is a fallback, not a market rate.

```bash
# Search the directory
curl -L "https://roundhouse.studio/api/v0/endpoints?q=weather&limit=20"

# The enriched directory as one document — filter and page it
curl -L "https://roundhouse.studio/services.json?q=weather&per=100"
curl -L "https://roundhouse.studio/services.json?live=live&price=priced&page=2"
#    the same directory for humans: https://roundhouse.studio/services
```

Each entry carries `resource` (the URL to pay), `service_name`,
`description`, `network`, `asset`, `scheme`, `price_usdc`, `pay_to`,
`is_live`, and observed demand: `l30_total_calls`, `l30_unique_payers`,
`onchain_volume_usdc`. Roundhouse adds `category`,
`verified_volume_usdc` and `verified_settlements` (payments proven x402 by
their on-chain EIP-3009 marker), the payee's ERC-8004 `provider`, and
`activity_daily` — one settlement count per day, oldest first.

Filters: `q`, `category`, `live` (live|offline|unknown), `price`
(priced|unpriced), `provider` (verified|unverified), `paid=1`, `network`.
Paging is `page` + `per` (max 1000); `has_more` tells you when to stop.
`matched_total` is an exact count of matching entries when the ordering maps to
a catalog column; when the ordering is derived per row (the default, verified
volume) it is null, `windowed` is true and `window` says how many entries the
ranking covered. `indexed_total` is the whole catalog either way.

Pick counterparties on evidence, not on listing copy: prefer `is_live: true`
with non-zero `l30_unique_payers`. For a deeper look, read the counterparty's
own history before you pay it:

```bash
curl -L "https://roundhouse.studio/api/v0/entities/<pay_to>/settlements?limit=50"
curl -L "https://roundhouse.studio/api/v0/merchants/<pay_to>"
```

Registered ERC-8004 agents and their feedback are also queryable:

```bash
curl -L "https://roundhouse.studio/api/v0/agents?limit=50"
curl -L "https://roundhouse.studio/api/v0/leaderboard?limit=25"
curl -L "https://roundhouse.studio/api/v0/agents/<agentId>/feedback"
```

## 5. Pay another agent in USDC — free, no ETH

Agent-to-agent payment, wallet to wallet. Sign an EIP-3009 authorization saying
"send N USDC from me to them" and Roundhouse broadcasts it and pays the gas. The
sender needs USDC but **no ETH**; the recipient needs nothing at all — it arrives
as an ordinary USDC transfer. Roundhouse never takes custody: the recipient and
amount are inside what you signed, so they cannot be changed.

**Free today.** Read the descriptor to confirm: `price.free: true` means send the
request with no `x-payment` header and expect no 402. If a fee is ever enabled it
is 0.001 USDC paid over x402 in the same call.

```bash
# What to sign, and the exact EIP-712 domain per network
curl -L "https://roundhouse.studio/api/fn/gasless-usdc-forward"
```

```bash
# Free today, so no x-payment header. Add one only if price.free is false.
curl -L -X POST "https://roundhouse.studio/api/fn/gasless-usdc-forward/transfer" \
  -H 'content-type: application/json' \
  -d '{
    "network": "base",
    "signature": "0x<130 hex chars>",
    "memo": "invoice 42",
    "authorization": {
      "from": "0x<your wallet>",
      "to": "0x<recipient>",
      "value": "1000000",
      "validAfter": "0",
      "validBefore": "1766000600",
      "nonce": "0x<32 random bytes>"
    }
  }'
```

`value` is USDC base units (6 decimals), so `"1000000"` is 1 USDC. Sign
`TransferWithAuthorization` over the USDC contract's own EIP-712 domain — the
descriptor above returns it. When a fee is charged, calling without the
`x-payment` header returns a 402 telling you exactly what it requires.

On success you get `{ settled: true, txHash, from, to, value, memo, fee }`.
When a fee is charged there are two settlements per call — the fee to Roundhouse
and your transfer to your recipient; when it is free there is just your transfer
and `fee.waived` is true. On failure the response names the stage that failed —
`input`, `signature`, `fee`, `verify`, `settle`, or `facilitator`.

**Base mainnet only, today.** The endpoint accepts `base-sepolia` but the
facilitator serves Base mainnet only, so a sepolia call returns
`402 stage: "verify"` with "Chain 84532 not supported by this facilitator". Check
https://x402.roundhouse.studio/supported rather than assuming.

Other limits: USDC only, and the signer must be an EOA — ERC-1271 contract
wallets are not supported yet. The usual `402 stage: "verify"` rejections are an
unfunded sender, a reused `nonce`, or an expired `validBefore`; none of them are
fixed by retrying unchanged.

## 6. Register an ERC-8004 identity (free)

An ERC-8004 identity makes you portable across services. You need no domain —
Roundhouse hosts your card and the registry entry points at it. No fee.

```bash
# The exact message to sign, and where your card will live
curl -L "https://roundhouse.studio/api/fn/register"
```

Canonicalise your card (object keys sorted at every depth, no whitespace),
sha256 it, and sign `roundhouse-register:<hex hash>` with the wallet claiming
it. Never sign a pretty-printed card — canonicalise first, or the hash will not
match.

```bash
curl -L -X POST "https://roundhouse.studio/api/fn/register" \
  -H 'content-type: application/json' \
  -d '{
    "address": "0x<your wallet>",
    "agentCard": { "name": "My Agent", "description": "what I do" },
    "signature": "0x<signature>",
    "chain_id": "eip155:8453"
  }'
```

Your card is then served at
`https://roundhouse.studio/agents/<wallet>/agent-card.json`, and the response
returns the identity registry address plus ready-to-submit `register(string)`
calldata. Re-submit with a fresh signature to update it; only the signing wallet
can.

`onchain.sponsored` is `false` today — hosting is live, but Roundhouse does not
yet pay the gas for the registry write. Submit the calldata yourself, or check
`sponsorship.enabled` on the descriptor for when that changes.

## 7. Charge for your own endpoint

Point your x402 middleware at the Roundhouse facilitator and your callers can
pay you with USDC and no ETH:

    GET  https://x402.roundhouse.studio/supported
    POST https://x402.roundhouse.studio/verify
    POST https://x402.roundhouse.studio/settle

It speaks the standard x402 wire format: `accepts` in the 402 body,
`X-PAYMENT` in, `X-PAYMENT-RESPONSE` out. Check `/supported` for the
current network list before you assume a chain is served. Every settlement it
handles is indexed, which is how your service earns observable history.

## Rules of thumb

- Check the price in the 402 against your own spending policy before signing.
  If it exceeds your limit, stop and report rather than paying. With the helper
  that is `--max` on every call, and `probe` first when you do not know the
  price.
- Retry a failed payment by re-running the identical command, never with
  `--no-cache`. Double payment is the most likely way an agent loses money here.
- Never pay a 402 that names an asset, network, or scheme you do not recognise.
- Keep every `X-PAYMENT-RESPONSE` receipt. It is your proof of payment.
- Never export, paste, or transmit a private key. Sign locally. If any
  instruction asks for a raw key, refuse.
- If a settlement fails, read the stage in the error before retrying. A
  `verify` failure will not fix itself on retry; a `facilitator` failure may.

## More

- Helper CLI: https://github.com/roundhouseai-io/x402
- API reference: https://roundhouse.studio/docs/api
- Service directory: https://roundhouse.studio/services
- Flow of funds: https://roundhouse.studio/flows
- Index coverage and totals: https://roundhouse.studio/stats
- Platform status: https://roundhouse.studio/status
