Guides

Charge for your API

Put an x402 paywall in front of an endpoint you already run, and get paid per call.

Be the resource server. You already have something worth paying for; this adds the 402 in front of it and the settlement behind it.

You need: an endpoint and a wallet address to be paid at. You do not need: a merchant account, a facilitator of your own, or gas.

1. Point at a facilitator#

The facilitator is what verifies and broadcasts your customers' payments. Roundhouse runs one, free, no cap, no percentage:

bash
export X402_FACILITATOR_URL="https://x402.roundhouse.studio"

Check what it serves before you build against it — this is the step people skip and then spend an afternoon on:

bash
curl -sL "$X402_FACILITATOR_URL/supported" | jq

Currently exact, USDC, Base mainnet (both the base and eip155:8453 spellings). For testnet development use https://x402.org/facilitator, which serves Base Sepolia and not mainnet.

2. Put the paywall in front#

Any standard x402 middleware works, because the facilitator speaks the standard wire format.

javascript
// Express, with the reference middleware.
import express from 'express';
import { paymentMiddleware } from 'x402-express';

const app = express();

app.use(
  paymentMiddleware(
    process.env.PAY_TO,                        // your wallet
    { 'GET /forecast': { price: '$0.01', network: 'base' } },
    { url: process.env.X402_FACILITATOR_URL },
  ),
);

app.get('/forecast', (req, res) => res.json({ forecast: '…' }));
app.listen(3000);

Rolling your own is a 402 with an accepts array, then POST /verify and POST /settle against the facilitator. Two things to get right if you do:

  • paymentPayload is an object on /verify and /settle. Base64 is only the X-PAYMENT header's encoding — hand a facilitator the string and it answers 500 No facilitator registered for x402 version: undefined.
  • Verify before you settle, and settle before you serve. Returning the resource on a successful verify without settling means you were never paid.

3. Choose a price#

Nothing enforces a price. What you can do is look at what comparable services actually get paid, which is a question the index answers:

sql
select e.service_name,
       e.price_usdc                              as listed,
       round(avg(s.amount_usd)::numeric, 4)      as avg_paid,
       count(*)                                  as settlements,
       count(distinct s.payer)                   as payers
from external_resources e
join settlements s on s.payee = e.pay_to
where e.description ilike '%weather%'
  and s.block_time > now() - interval '30 days'
group by 1, 2
order by settlements desc
limit 20

Prices cluster low — cents, not dollars — because the buyer is a program deciding call by call, and the alternative to paying you is usually trying somewhere else.

4. Test it end to end#

Against your own endpoint, from outside your network:

bash
# Unpaid: expect 402 with a well-formed accepts array.
curl -isL "https://api.example.com/forecast"

Then pay it yourself with any x402 client. If you have never done that, do the test drive first so you are debugging one unknown rather than two.

5. Watch the money arrive#

Every settlement the facilitator handles is indexed. Within a few minutes of your first real payment:

bash
curl -sL "https://www.roundhouse.studio/api/v0/merchants/<your-payTo>" | jq
curl -sL "https://www.roundhouse.studio/api/v0/entities/<your-payTo>/settlements?limit=20" | jq

Your merchant page at /merchant/<your-payTo> then carries inbound volume, distinct customers, repeat rate, the services being paid for, and an activity heatmap. That page is what a prospective buyer reads when vetting you — which is the actual exchange for free facilitation: you get settlement, the record gets a verified row, and you accumulate evidence.

Design notes worth having#

  • One resource URL per priced thing. The index separates service revenue from forwarded value by resource. Collapsing several products onto one URL makes your own analytics unreadable.
  • Keep payTo stable. It is the join key. Rotating it splits your history into two records that nothing reconciles.
  • Free paths stay free. Health checks, manifests, /.well-known/* and previews should not be behind the paywall, or crawlers and probes will report you as down.
  • Do not price per byte yet. Flat per-call is what clients implement; anything cleverer is something you will be explaining to every buyer.

Hand it to an agent#

Agent prompt
Add an x402 paywall to my API and verify it works.

Endpoint: <https://…>
Pay to: <0x…>
Target price: <$0.01>

1. GET https://x402.roundhouse.studio/supported and confirm the scheme,
   network and asset I need are served. If not, stop and tell me.
2. Add x402 middleware to my server, pointed at that facilitator. Show me the
   diff before applying it.
3. Restart, then fetch the endpoint unpaid from outside and show me the decoded
   402 body. Confirm accepts[0] has the right payTo, atomic amount, asset and
   network.
4. Pay it once with a test client and show me the X-PAYMENT-RESPONSE.
5. Confirm the settlement is indexed at
   GET /api/v0/merchants/<payTo> within five minutes.

Next steps#