Documentation

Build on Rail402

Publish paid APIs, build autonomous agents, and integrate x402 micropayments on Base. Everything an agent needs to discover, pay for, and call an API — settled in USDC.

Introduction

What is Rail402

Rail402 is an agent-native marketplace for paid APIs. Providers publish REST endpoints with per-call USDC pricing. AI agents discover those endpoints through a structured registry, pay per request on Base via the x402 protocol, and receive a response — all autonomously, with no API keys, accounts, or subscriptions.

Payment as authentication

The core idea: the payment is the authentication. Instead of issuing credentials, a provider returns a standard HTTP 402. The agent pays in stablecoin, the proof is verified on-chain, and the data is returned. No session state, no key rotation, no human in the loop.

Because the transaction hash is the credential, the model composes cleanly with agent runtimes, MCP servers, and multi-agent pipelines — settings where per-call economic settlement is the only access-control model that scales to software acting on its own behalf.

Who it's for

You are…Start here
A provider with an API to monetizeJump to For providers
Building an agent that needs live dataJump to For agents
Using Claude, Codex, Antigravity or CursorSet up the MCP server
Integrating the discovery registryRead Agent discovery

How x402 payments work

Request lifecycle

The x402 flow is a two-step HTTP pattern built on standard status codes:

  1. Agent calls POST /api/services/[id]/call with the request payload.
  2. Rail402 returns HTTP 402 with a payment object: recipient wallet, USDC amount, network, and a 10-minute expiry.
  3. Agent submits a USDC transfer on Base (~2s finality) and captures the transaction hash.
  4. Agent retries with an x-payment-proof header containing the txHash and payerWallet.
  5. Rail402 verifies the on-chain transfer and returns HTTP 200 with the provider response.

Input is validated against the service's inputSchema before the challenge is issued — a malformed request returns 400and never reaches the provider. The SDK's fetchWithPayment performs steps 2–5 for you in a single call.

The payment object

The 402 body carries everything needed to settle. The same fields appear at the top level (for x402 clients) and under a payment key (for convenience).

FieldExampleMeaning
typex402_payment_requiredDiscriminator that marks an x402 challenge.
amountAtomic50000Exact USDC to transfer, in atomic units (6 decimals). Send this value.
amount0.05Human-readable USDC amount (display only).
payTo0x2DDa…191aProvider wallet — the USDC recipient.
networkbaseSettlement network. base = mainnet.
chainId8453Base mainnet (8453) or Base Sepolia (84532).
currencyUSDCSettlement token.
expiresAtISO 8601Challenge expiry — 10 minutes from issuance.
Always transfer amountAtomicexactly. Underpayment is rejected, and the value is already denominated in USDC's 6-decimal base units — no conversion required.

Proof & verification

After paying, the agent retries with an x-payment-proof header. The proof is a small JSON object:

x-payment-proof
1{
2  "txHash": "0x91c9…6055",      // required — the USDC transfer hash
3  "payerWallet": "0x8A05…0C08"  // recommended — the paying account
4}

The gateway verifies the transaction on-chain before proxying the call. It checks that the:

  • transaction succeeded and is a USDC transfer on the expected network;
  • token contract matches the canonical USDC address for that network;
  • recipient equals the service's payTo wallet;
  • amount is at least the registered price (underpayment is rejected);
  • txHash has not been used for this service before (replay protection).

Expiry & replay rules

Payments are non-refundable. Requirements expire after 10 minutes. Each txHash is single-use — reusing one returns 409 Conflict. Pay a fresh transaction per call.

Replay protection is what distinguishes an x402 settlement from a plain USDC transfer: the gateway indexes every proof, so a transaction can unlock a given service exactly once.

SDKs & tooling

Everything is open source and published. The SDK handles the x402 handshake and on-chain verification so you never implement it by hand.

@rail402/x402npm · TypeScript

Make any REST endpoint x402-payable, and pay for x402 endpoints as an agent. Express, Next.js & FastAPI adapters.

npm install @rail402/x402 viem
View on npm
rail402-x402PyPI · Python

The Python distribution: FastAPI middleware and on-chain verification.

pip install rail402-x402[fastapi]
View on PyPI
@rail402/mcpnpm · MCP server

Give Claude, Codex, Antigravity, Cursor & Base MCP direct access to the marketplace: list, inspect, pay for, and call any API.

npx -y @rail402/mcp@latest
View on npm

Validate an agent-services.json discovery document against the Rail402 spec.

npx @rail402/validate-spec ./agent-services.json
View on npm

Browse the source on github.com/Rail402 — see Resources for the full repo map.

For providers

There are two ways to monetize an API. Most providers use the marketplace; advanced providers can also accept x402 directly on their own infrastructure.

Option A — Publish on the marketplace

Expose a plain HTTPS endpoint that accepts a JSON body and returns JSON. You do notadd any payment code — Rail402's gateway handles the 402 challenge, on-chain verification, and replay protection, then proxies the request to your endpoint. USDC settles directly to your wallet.

  1. Build a public HTTPS endpoint (POST, JSON in/out, internet-reachable).
  2. Define JSON Schemas for input and output — agents read these to call you.
  3. Connect your wallet — it becomes the payout address.
  4. Submit on the Publish page. New services enter pending_review; once approved they go live in the marketplace.
Validate your discovery document any time: npx @rail402/validate-spec ./agent-services.json

Option B — Accept x402 on your own server

Want to charge for an endpoint outside the marketplace? Wrap it with @rail402/x402. One wrapper adds the full 402 → verify → respond flow.

server.ts
1import { withX402 } from "@rail402/x402";
2
3app.post(
4  "/api/risk",
5  withX402(
6    async (req, res) => {
7      // payment already verified; req.x402.payerWallet is available
8      res.json(await yourBusinessLogic(req.body));
9    },
10    { price: "0.05", wallet: process.env.PROVIDER_WALLET, network: "base" },
11  ),
12);
app/api/risk/route.ts
1// app/api/risk/route.ts
2import { withX402Payment } from "@rail402/x402";
3
4export const POST = withX402Payment(
5  async (req, { x402 }) => Response.json({ score: 0.92, paidBy: x402.payerWallet }),
6  { price: "0.05", wallet: process.env.PROVIDER_WALLET!, network: "base" },
7);
main.py
1from rail402_x402 import X402Middleware
2
3X402Middleware(app, price="0.05", wallet=PROVIDER_WALLET, network="base", protected_paths=["/api/risk"])

Deploy-ready templates: Rail402/provider-starter.

For agents & consumers

Three ways to call a paid API, from highest-level to lowest.

Option A — SDK (recommended)

fetchWithPayment takes a viem wallet and transparently settles the 402, then retries — the whole handshake in one call.

agent.ts
1import { fetchWithPayment } from "@rail402/x402";
2import { createWalletClient, http } from "viem";
3import { privateKeyToAccount } from "viem/accounts";
4import { base } from "viem/chains";
5
6const wallet = createWalletClient({
7  account: privateKeyToAccount(process.env.AGENT_PRIVATE_KEY as `0x${string}`),
8  chain: base,
9  transport: http(),
10});
11
12const res = await fetchWithPayment(
13  "https://www.rail402.app/api/services/{id}/call",
14  { method: "POST", body: JSON.stringify({ input: { address: "0x…" } }) },
15  wallet,
16);
17console.log(await res.json());

Option B — MCP (Claude, Codex, Antigravity, Cursor & Base MCP)

Add @rail402/mcp and your model can browse, price-check, pay for, and call any marketplace API itself. Tools: list_services, get_service_details, call_service, check_payment_status.

The config below is the standard MCP format — drop it into your client's config file (claude_desktop_config.json, Codex's MCP settings, or Antigravity's mcp_config.json).

claude_desktop_config.json
1{
2  "mcpServers": {
3    "rail402": {
4      "command": "npx",
5      "args": ["-y", "@rail402/mcp@latest"],
6      "env": {
7        "RAIL402_API_BASE": "https://www.rail402.app",
8        "RAIL402_NETWORK": "base",
9        "RAIL402_PRIVATE_KEY": "0xYourAgentWalletKey"
10      }
11    }
12  }
13}

RAIL402_PRIVATE_KEY is required only for paid call_servicecalls; discovery works read-only without it. Use a dedicated agent wallet funded with only what you're willing to let the agent spend.

Option C — Raw HTTP

No SDK? Implement the two-step flow directly:

manual-x402.ts
1// 1. First call — expect 402
2const challenge = await fetch(callUrl, {
3  method: "POST",
4  headers: { "Content-Type": "application/json" },
5  body: JSON.stringify({ input }),
6});
7const { payment } = await challenge.json(); // { payTo, amountAtomic, network, ... }
8
9// 2. Transfer USDC(payment.payTo, payment.amountAtomic) on Base -> txHash
10
11// 3. Retry with proof
12const result = await fetch(callUrl, {
13  method: "POST",
14  headers: {
15    "Content-Type": "application/json",
16    "x-payment-proof": JSON.stringify({ txHash, payerWallet }),
17  },
18  body: JSON.stringify({ input }),
19});

Agent discovery

Registry endpoints

Rail402 publishes a machine-readable registry at three canonical endpoints:

EndpointFormatBest for
/api/agent/servicesJSONProgrammatic discovery, pageable, CORS-open
/.well-known/agent-services.jsonJSONStandard well-known location
/llms.txtPlain textLLM context windows

The document format is an open, versioned standard. Read the spec and the full x402 flow at Rail402/agent-services-spec, and validate your own with @rail402/validate-spec.

Service schema

Each entry is self-describing — an agent can select, price-check, and invoke a service in a single discovery pass. The key fields:

FieldDescription
id / slugStable identifier and human-readable handle. Either works in the call URL.
price{ amount, currency } — per-call cost in USDC.
networkSettlement network (base).
capabilities / tagsKeywords for capability-based routing and search.
inputSchema / outputSchemaJSON Schemas — build a valid request and parse the response.
endpointThe call URL to POST against.
reliability{ verified, successRate, averageLatencyMs, totalCalls } — live operational stats.
playgroundUrlTry the service with a simulated payment, no wallet required.
GET /api/agent/services
1{
2  "id": "cmpjq32i80002qaimfb2fezm4",
3  "slug": "wallet-risk",
4  "name": "Wallet Risk Score API",
5  "capabilities": ["risk", "wallet", "security"],
6  "price": { "amount": "0.05", "currency": "USDC" },
7  "network": "base",
8  "endpoint": "https://www.rail402.app/api/services/{id}/call",
9  "inputSchema":  { /* JSON Schema */ },
10  "outputSchema": { /* JSON Schema */ },
11  "reliability": {
12    "verified": true,
13    "successRate": 99.5,
14    "averageLatencyMs": 132,
15    "totalCalls": 2059
16  },
17  "playgroundUrl": "https://www.rail402.app/playground/wallet-risk"
18}

API reference

Status codes

StatusMeaningAction
400Input failed schema validation.Fix the request body to match inputSchema.
402Payment required. Includes the payment object.Pay on Base, retry with x-payment-proof.
403Service exists but is not published.Wait for the service to go live.
404No service matches that id or slug.Re-check the id from the discovery registry.
409txHash already used (replay rejected).Submit a new on-chain transaction.
429Rate limited (10 req / 10s / IP).Wait for X-RateLimit-Reset, then retry.
502Provider endpoint unreachable or timed out.Try again later.
500Internal Rail402 error.Retry once; contact support if it persists.

Rate limits

All call endpoints: 10 requests per 10 seconds per IP. On a 429, response headers tell you when to retry:

429 response headers
1X-RateLimit-Remaining: 0
2X-RateLimit-Reset: 1717056123000

Resources

Repositories

RepoWhat it is
Rail402/x402-sdk@rail402/x402 — provider middleware + agent client (TS & Python)
Rail402/provider-starterDeploy-ready Express / Next.js / FastAPI paid-API templates
Rail402/agent-services-specThe discovery standard + @rail402/validate-spec CLI
Rail402/rail402-mcp@rail402/mcp — MCP server for Claude, Codex, Antigravity, Cursor & Base MCP
Rail402/examplesLangChain, Claude, OpenAI & Base MCP reference agents
Rail402/awesome-rail402Curated ecosystem index

Drop-in agent prompt

Paste this into any LLM system prompt to make it a Rail402-capable agent:

agent-prompt.txt
1You are an AI assistant that can call paid APIs on Rail402.
21. Discover services at https://www.rail402.app/api/agent/services.
32. Read inputSchema and build a valid request body.
43. Call the service's call endpoint. If HTTP 402, read the payment object.
54. Transfer USDC to payment.payTo on Base. Capture the txHash.
65. Retry with x-payment-proof: {"txHash":"0x...","payerWallet":"0x..."}.
76. Return the provider response to the user.
8
9Never expose private keys. Validate output before irreversible actions.
10Payment requirements expire after 10 min - never reuse a txHash.
Network: Base mainnet · Settlement: USDC 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913