Hoodx402 docs
Everything you need to accept per-call payments from AI agents on Robinhood Chain — or to let an agent pay for anything without an account.
Overview
Hoodx402 has three roles. Most readers are one of the first two:
- API provider — wraps an HTTP endpoint with a price. Agents pay you per call; you never handle keys, invoices, or merchant infrastructure.
- Agent — any HTTP client with a wallet. It calls an API, receives a price, signs one payment, and gets the response plus an on-chain receipt.
- Facilitator — Hoodx402's service that verifies signed payments and settles them on-chain, so neither side waits on the other.
Payments use the x402
open standard: the API answers 402 Payment Required with terms in a
header, the agent signs an EIP-3009 transfer-with-authorization, and
the facilitator settles in USDG. No subscriptions, no API keys, no chargebacks.
Quickstart — provider
Wrap an existing route. If it answers today, it can earn per call.
import { x402 } from "@Hoodx402/sdk";
// your server, unchanged
const api = x402.wrap(app, {
asset: "0x…", // EIP-3009 token contract
assetName: "USDG", // EIP-712 domain name
assetVersion: "1",
chainId: 31337,
payTo: "0x…", // your payout address
decimals: 6,
});
api.route("GET /v1/quote", handler, {
price: "0.001", // human decimal — converted once, at registration
}); What the SDK does for you
- Intercepts the first unauthenticated request and answers
402with a challenge header. - Forwards the request with an
X-PAYMENTsignature to your handler once payment is verified. - Returns a receipt header on every paid call, so both sides can audit it later.
Requirements
- Node 20+ and any HTTP framework (Express, Fastify, Hono —
wrapadapts to the request/response objects). - A payout address on Robinhood Chain testnet. Settlement lands there; you never sign anything as a provider.
The settlement flow
One call moves through four states. Each header below is part of the pilot spec.
1 · API answers 402
HTTP/2 402 PAYMENT REQUIRED
x-402: asset=0x… # EIP-3009 token contract
amount=1000 # smallest units (0.001, 6 decimals)
decimals=6 name=USDG version=1
chain-id=31337 facilitator=Hoodx402
pay-to=0x… # provider payout address
nonce=0x… # bytes32, single-use
valid-before=1787903890
Values are URL-encoded when they contain spaces (a token named
USDG Mock arrives as name=USDG%20Mock). The provider
stores every issued challenge — the payer must satisfy the exact quote.
2 · Agent signs once
The agent signs an EIP-3009 TransferWithAuthorization
for amount of the asset, payable to pay-to, valid
until valid-before. The signature is a header — not a transaction.
x-payment: scheme=eip3009 from=0x… # payer — must equal the recovered signer
signature=<65-byte rsv> nonce=0x… 3 · Facilitator settles
The facilitator verifies the signature against the challenge, submits the settled transfer on-chain, and returns the receipt hash. Settlement is idempotent per nonce — a retried call never pays twice.
4 · 200 OK with receipt
HTTP/2 200 OK
x-receipt: 0x91c4…8e02 - settled 0.001 USDG Agent side
Agents get one helper that handles the 402 round-trip. Give it a wallet-capable signer and a spending cap; it never exceeds the cap.
import { x402Fetch } from "@Hoodx402/sdk";
const res = await x402Fetch(
"https://quotes.example/v1/quote?symbol=NVDA",
{ signer, maxPrice: "0.01" }
);
const quote = await res.json();
console.log(res.headers.get("x-receipt")); maxPrice to the highest amount acceptable for one call. The SDK
refuses any challenge above it — treat unexpected prices as untrusted data.
Chain config
| Parameter | Value | Notes |
|---|---|---|
chain | robinhood | EVM. Testnet pilot only for now. |
settlement asset | USDG | Address: TBD — published with the pilot contracts. |
second asset | cbBTC | Planned, routed via the Chainlink CCIP lane. |
RPC | TBD | Testnet endpoint shared with whitelist participants. |
Prices are strings denominated in the asset's smallest unit unless the route
declares decimals. "0.001" USDG means 0.001 USDG — the
SDK converts once, at the route definition, not per call.
Facilitator API
Providers and agents talk to the facilitator over two endpoints. Both are idempotent and safe to retry.
POST /verify
Checks a signed payment against a challenge. Returns valid or a machine-readable reason — nothing moves.
{ "valid": true, "payer": "0x7a…f3", "amount": "0.001" } POST /settle
Submits the verified payment on-chain. Retries with the same nonce return the original receipt.
{ "receipt": "0x91c4…8e02", "tx": "0x7d3b…01aa",
"settled": "0.001" } Registry
Paid endpoints are discoverable. Providers list routes on-chain; agents query the registry instead of hard-coding URLs.
registry.list({ tag: "market-data", chain: "robinhood" });
// → [{ url, price, asset, provider, updatedAt }] Listing requires a small registration stake (returned on delisting). The stake exists so the registry stays worth reading.
Errors
| Status | Code | What happened, what to do |
|---|---|---|
402 | payment_required | Expected on the first call. Read x-402, decide, pay or walk away. |
400 | invalid_signature | The signature did not match the challenge. Re-fetch the 402 — nonces are single-use. |
402 | insufficient_balance | The payer wallet lacks amount USDG. Top up or quote a smaller route. |
413 | price_above_cap | Challenge exceeded the agent's maxPrice. The SDK stopped before signing. |
429 | rate_limited | Facilitator throttle. Wait for Retry-After, then retry — settlement is idempotent. |
503 | facilitator_unreachable | The facilitator is down, your API keeps serving free traffic. Retry paid calls after backoff. |
Status
- Facilitator: live on testnet with design partners.
- SDK:
@Hoodx402/sdk 0.1.x— internal, shared with whitelist participants. - Registry: on-chain listing lands with v0.2.
- Mainnet: gated on the audit — see the roadmap.
Questions or an endpoint you want wrapped? Get whitelist access or open an issue on GitHub.