TollboothTollbooth
Documentation

Integrate an x402 service

Wrap any API in the x402 payment protocol, list it on Tollbooth, and start getting paid per call in USDC on Base. Everything below works against this app's own API routes.

Overview

x402 revives the dormant 402 Payment Required HTTP status. A client calls your endpoint; if it has not paid, you respond 402 with a machine-readable list of acceptable payments. The client pays in USDC on Base, then retries with an X-PAYMENT header. Tollbooth sits on top: it verifies your endpoint actually speaks x402, then tracks uptime and reputation.

Wrap

Return 402 + payment requirements for unpaid requests.

Verify

Tollbooth probes the live endpoint and parses the challenge.

Earn

Each paid call settles to your wallet on Base.

Example endpoint implementation

The only hard requirement for verification is that an unpaid request receives a real HTTP 402 with a parseable accepts array.

app/api/route/route.ts
// A minimal x402-enabled endpoint (Next.js route handler).
// Unpaid requests get a 402 with payment requirements; paid requests run.
import { NextResponse } from "next/server";

const PAY_TO = "0x9A7c1F3B2e4D5a6c7B8e9F0a1b2C3d4E5f6A7b8C";
const USDC_BASE = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";

export async function POST(req: Request) {
  const payment = req.headers.get("X-PAYMENT");

  // No payment? Challenge with 402 + x402 payment requirements.
  if (!payment) {
    return NextResponse.json(
      {
        x402Version: 1,
        accepts: [{
          scheme: "exact",
          network: "base",
          maxAmountRequired: "10000",        // 0.01 USDC (6 decimals)
          asset: USDC_BASE,
          payTo: PAY_TO,
          resource: "https://api.you.dev/v1/route",
          description: "One completion",
          maxTimeoutSeconds: 60,
        }],
      },
      { status: 402 }
    );
  }

  // Verify + settle the payment via your x402 facilitator here.
  //   const settled = await facilitator.verify(payment, requirement);
  //   if (!settled) return new NextResponse("Invalid payment", { status: 402 });

  const { prompt } = await req.json();
  return NextResponse.json({ completion: await runModel(prompt) });
}

Service manifest

The manifest is the portable descriptor of your service. Copy it from any service page, or generate it when you list. Schema version:

agent402/manifest@1

manifest.json
{
  "schema": "agent402/manifest@1",
  "name": "LLM Router",
  "description": "Routes prompts to the cheapest capable model.",
  "category": "ai-inference",
  "endpoint": "https://api.nimbus.dev/v1/route",
  "x402": {
    "network": "base",
    "scheme": "exact",
    "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
    "payTo": "0x9A7c1F3B2e4D5a6c7B8e9F0a1b2C3d4E5f6A7b8C",
    "maxAmountRequired": "10000"
  },
  "input": { "type": "object", "properties": { "prompt": { "type": "string" } } },
  "output": { "type": "object", "properties": { "completion": { "type": "string" } } }
}

Verification flow

When you register a service (or hit /api/verify), Tollbooth runs these checks in order. A service is only marked verified when all executed checks pass.

  1. 1Endpoint responds We can reach the URL within a timeout.
  2. 2Returns HTTP 402 Unpaid requests are challenged with 402.
  3. 3Payment requirements parsed The x402 `accepts` array is valid.
  4. 4Wallet valid payTo is a valid address and matches the listing.
  5. 5Test payment prepared An `exact` payment intent can be built.
  6. 6Settlement verified Tollbooth receives a paid response or payment response header.
  7. 7Valid response returned Paid replay returns a schema-valid body.

Try it live on the verification page.

API reference

GET
/api/services

List services. Supports ?category, ?chain, ?verified=true, ?q, ?minUptime, ?maxPrice, ?sort.

GET
/api/services/:id

Fetch a single service (by id or slug) plus its generated manifest.

POST
/api/services

Register a new service. Runs verification immediately; the result sets the stored status.

register a service
curl -X POST https://www.trytollbooth.com/api/services \
  -H "Content-Type: application/json" \
  -d '{
    "name": "LLM Router",
    "endpoint": "https://api.nimbus.dev/v1/route",
    "category": "ai-inference",
    "priceUsdc": 0.01,
    "wallet": "0x9A7c1F3B2e4D5a6c7B8e9F0a1b2C3d4E5f6A7b8C",
    "chain": "base",
    "description": "Routes prompts to the cheapest capable model."
  }'

# => 201 { "service": { ... }, "verification": { "status": "pending", "steps": [ ... ] } }
POST
/api/verify

Run the live x402 verification pipeline against an endpoint + wallet.

verify an endpoint
curl -X POST https://www.trytollbooth.com/api/verify \
  -H "Content-Type: application/json" \
  -d '{
    "endpoint": "https://api.nimbus.dev/v1/route",
    "wallet": "0x9A7c1F3B2e4D5a6c7B8e9F0a1b2C3d4E5f6A7b8C",
    "serviceId": "svc_llm_router"
  }'

# => { "verification": { "status": "pending", "httpStatus": 402, "steps": [ ... ] } }
POST
/api/test-call

Unpaid probe (or, with pay:true, a real paid x402 call). Records a CallRecord and any settlement tx.

POST
/api/manifests

Ingest one or many agent402/manifest@1 manifests; upserts the owning agent by wallet and verifies each.

POST
/api/claim/nonce

Issue a nonce + message for wallet-ownership proof.

POST
/api/claim/verify

Verify a signed nonce (EIP-191). Ownership is only stored on a valid signature.

GET
/api/health

Health history + derived uptime/latency for a service (?serviceId=).

POST
/api/health

Run a real uptime probe now — one service, or all non-demo services.

POST
/api/crawl

Run discovery adapters (manual URLs, GitHub, Farcaster/Virtuals placeholders); saves live endpoints as unclaimed.

Payment execution boundary

Tollbooth performs live reachability, 402 detection, requirement parsing, wallet validation, and paid replay. Set X402_EVM_PRIVATE_KEY to a funded Base/Base Sepolia key so the official x402 SDK can sign the payment.