FREE GUIDE

Build and ship your own x402 API

A real-world walkthrough β€” the Toolrail case study, bugs included.

1. Why this matters right now2. The minimal architecture that works3. Real bug #1: Solana testnet vs. devnet4. Choosing a facilitator: testing vs. production5. Choosing WHAT to sell: the 3-question filter6. Where to get data without landing in trouble7. Real bug #2: JSON that isn't JSON8. Real bug #3: the security that bit its own tail9. Production security checklist10. Deploy: from your laptop to the internet in an afternoon11. Getting found: the 5 real channels12. The reality of the numbers (nothing inflated)

1. Why this matters right now

x402 is an open payment protocol built on the HTTP 402 ("Payment Required") status code, which sat unused in the standard since the 90s. Coinbase revived it: when an AI agent calls an API without paying, the server replies 402 with machine-readable payment instructions; the agent pays in USDC (a stablecoin, always worth $1) on Base or Solana, retries, and gets the resource. All in seconds β€” no accounts, no API keys.

The market grew from near-zero to over 100 million cumulative transactions in under a year, with Visa, Mastercard, Google and Stripe joining the x402 Foundation in July 2026. It's still early β€” the median of the ~22,000 listed services earns cents per month β€” but early is the operative word: whoever builds now enters with a track record once the market matures.

This guide documents, step by step, how we built Toolrail (toolrail.dev): a real API, in production, charging real money on two networks, serving official data from seven Latin American countries. This isn't theory β€” it's the path we actually walked, mistakes and fixes included.

2. The minimal architecture that works

An x402 server needs nothing exotic: a normal HTTP server (we used Express/Node.js, though the protocol is language-agnostic) with a payment middleware in front of your routes. The key piece is the 'resource server': an object that knows which networks it accepts, which payment scheme it uses ('exact' is the standard: a fixed price per call), and which wallet address the money should reach.

The internal flow in four steps: (1) the request hits your server, (2) the payment middleware checks whether it carries valid proof of payment, (3) if not, it short-circuits and responds 402 with base64-encoded JSON in a header describing the price and payee, (4) if it does, it verifies the payment against a 'facilitator' (an intermediary that confirms on-chain that the payment is real) and lets the request through to your normal code.

import express from "express";
import { paymentMiddleware, x402ResourceServer } from "@x402/express";
import { HTTPFacilitatorClient } from "@x402/core/server";
import { ExactSvmScheme } from "@x402/svm/exact/server";

const app = express();
const facilitator = new HTTPFacilitatorClient({ url: "https://x402.org/facilitator" });
const resourceServer = new x402ResourceServer(facilitator)
  .register("solana:<CAIP-2-network-id>", new ExactSvmScheme());

app.use(paymentMiddleware(
  { "GET /my-endpoint": { accepts: { scheme: "exact", price: "$0.01", network: "solana:...", payTo: "YOUR_WALLET" } } },
  resourceServer
));

app.get("/my-endpoint", (req, res) => res.json({ valuable: "data" }));
app.listen(3000);

3. Real bug #1: Solana testnet vs. devnet

This cost us an hour on day one β€” we'll save you the trouble. Solana has THREE test networks with confusingly similar names: 'devnet', 'testnet', and 'mainnet' (the real one). The identifier you use when configuring your network matters down to the letter β€” we used 'testnet' and the deploy failed with 'facilitator does not support this scheme on this network', because the free x402.org facilitator only supports 'devnet' for testing, not 'testnet'.

The generalizable lesson: before hardcoding any network identifier, query your facilitator's /supported endpoint (every serious facilitator exposes one) and use exactly what's listed there. Don't trust the protocol's general documentation β€” trust what your specific facilitator supports today.

4. Choosing a facilitator: testing vs. production

For development and testing, the free x402.org facilitator is enough and needs no account. For production β€” real money, and automatic listing in Coinbase's discovery index ('Bazaar') β€” you need the Coinbase Developer Platform (CDP) facilitator, activated with a free account and an API key pair.

One detail we're documenting because it's unclear anywhere else: for the Bazaar to actually catalog you (not just process payments), your server must explicitly register the discovery extension (bazaarResourceServerExtension from the @x402/extensions package) on the resource server. Without that line, you can be charging perfectly and still be invisible in the index β€” we found this by accident, reading the documentation with a magnifying glass after several days.

6. Where to get data without landing in trouble

The golden rule: official sources or explicit open licenses, never scraping pages that don't authorize it. Before connecting any source, we check three things: (1) Is the data a public fact (an official exchange rate, a legislated holiday) or copyrighted content? Official facts have no owner. (2) Does an openly licensed API or dataset exist (MIT, public domain), or is it internal data protected by terms of service? (3) If we use a third party's project, we notify them and offer attribution β€” build relationships, not just code.

An example of what we avoided: YouTube's API explicitly forbids reselling access to its data without Google's written permission, and transcripts aren't even in the official API. An example of what we did do: central banks that publish their historical series as open JSON, no key required β€” zero ambiguity there.

Researcher's trick: when a central bank doesn't document a public API, open its own website and check, in your browser's developer tools, what calls its own interactive chart makes β€” there's almost always an internal, keyless JSON endpoint that its own frontend team already uses. It's 100% legitimate: it's the same data they show publicly, just not formally documented.

7. Real bug #2: JSON that isn't JSON

One of our sources (a central bank) runs an old PHP backend that occasionally appends PHP warning dumps AFTER the valid JSON β€” hundreds of characters of error HTML tacked onto the end of a response that, up to that point, was perfect JSON. Standard JSON.parse() chokes on that.

The fix isn't 'hope it doesn't happen' β€” it's defensive: instead of trusting where the response ends, we count balanced { } braces from the first '{' until the counter returns to zero, and parse only that fragment. Also, on weekends that same source returns the text "n.d." instead of a number β€” so we walk backward through the historical series until we find the last real numeric value.

The lesson: when integrating a government or legacy-infrastructure source, NEVER assume its JSON is guaranteed valid JSON. Write the parser defensively from day one, with retries and garbage-tolerant extraction.

8. Real bug #3: the security that bit its own tail

After a security audit, we added a strict CSP (Content-Security-Policy) to our page: 'default-src none' β€” blocks any resource not explicitly authorized. Perfect for blocking malicious scripts... except it also silently blocked our own browser-tab icon, declared with a plain <link rel="icon"> on the very same page.

Nobody caught it in automated tests because the server served the file perfectly β€” the block happened in the visitor's browser, not on our server. We found it because someone insisted on testing in two different browsers and incognito mode before accepting 'must be caching'. The fix was one line: adding 'img-src self' to the policy.

The lesson: when hardening a page's security, test EVERY resource the page itself needs to load, not just the ones you want to block.

9. Production security checklist

The minimum we apply before announcing a service publicly:

10. Deploy: from your laptop to the internet in an afternoon

We use Render.com with Docker: a free plan is enough to test, a ~$7 USD/month plan for real production (the free tier 'sleeps' after inactivity, adding seconds of latency to the first call). If your service generates PDFs or screenshots, your Dockerfile needs Chromium installed.

The full cycle we use for every change: write code β†’ run automated tests locally β†’ if they pass, push to git β†’ Render auto-deploys via webhook β†’ verify from outside with curl that the change reached production. Never trust that something 'should have worked' β€” always verify the real result.

11. Getting found: the 5 real channels

None of these replace human distribution: ecosystem Discord communities, local developer forums, and β€” if your niche has a natural ally β€” genuine direct outreach, offering real value in the message.

12. The reality of the numbers (nothing inflated)

Be honest with yourself before starting: the median x402 service earns cents per month. The market grew extremely fast but is still young β€” most high-value calls (over $1) concentrate on a handful of established services.

The real value of building now isn't immediate income β€” it's positioning: accumulated track record in discovery indexes, deep learning of an infrastructure that's just maturing. Treat it as a cheap, well-considered bet, not a guaranteed income plan.

Launch checklist

πŸ“„ Get the PDF edition β€” with a printable checklist

The same guide, typeset for offline reading, plus the full 9-point launch checklist on a page you can pin next to your monitor.

Opening the link, your x402 client (or curl, to see the payment challenge) will get the 402 with payment instructions β€” same as any Toolrail endpoint.