Integrate your REST API
Already run a REST API? Coal lets agents discover and pay per call for it — without you rebuilding anything. Your API stays exactly where it runs. Coal sits in front, handles the x402 payment, and forwards the paid request to your origin. Funds land in your wallet, non-custodially.
This page is the proxy-mode path: zero code on your side. If you'd rather keep Coal off your request path and run a few lines of middleware in your own server instead, see SDK mode — the payment + payout model below is identical.
The shape: bundles and paywalls
An API Bundle is your API: one origin URL, plus the auth Coal needs to call it. Inside the bundle, each endpoint you want to monetize is a paywall — one method + path template + price.
- Bundle = the API you're wrapping (origin URL, shared auth).
- Paywall = one priced endpoint inside it (e.g.
GET /user/{id}→ $0.003).
Most paid APIs ship many endpoints — user lookup, search, follower lists. You configure the origin + auth once on the bundle, then add one paywall per endpoint, each with its own price.
How a paid call flows
When an agent hits https://api.usecoal.xyz/p/{bundle-slug}/{path}, Coal:
- Looks up the bundle by slug.
- Finds the child paywall whose method + path template matches.
- Returns 402 Payment Required with x402 PaymentRequirements if there's no
X-Paymentheader. - Settles the EIP-3009 USDC payment on Base — splitting your fee and paying your wallet in the same transaction (see below).
- Forwards the original request to your origin URL, with your stored auth header decrypted and attached, plus a
Coal-Signatureproving the request came from Coal. - Pipes your origin's response back, stamped with
x-payment-response: 0x…(the settle tx hash).
The agent's wallet never needs ETH — it signs an off-chain authorization and Coal's operator broadcasts the on-chain transfer.
How Coal knows it's your API and pays your wallet
This is the part most people ask about, and the answer is simple: identity is baked into the resource, not the request.
When you create a bundle in the console, you're signed in as you — so Coal stores it under your merchant account, permanently wired to your payout wallet. Every paid call resolves the public identifier (the bundle slug, or your custom domain) back to your account and pays the wallet bound to it.
The agent can't redirect a cent
The caller only ever provides a signed payment. They never choose where the money goes — Coal derives the payout from whoever owns the bundle. That binding was set the moment you created it, under your authenticated session. No API key on the request path can change it.
The split to your wallet happens in the same on-chain transaction, three ways depending on your setup:
- Enrolled in the CoalFeeRouter (default for Pro/Design Partner) → the settle pays the router, which atomically takes Coal's fee and sends the remainder straight to your wallet. Non-custodial — Coal never holds your funds.
- You deployed a 0xSplits contract → payment goes to your split address.
- Neither → payment goes directly to your payout address.
You set your payout wallet once in Console → Settings → Payout Address. Paywalls can't be created until it's set, and settlement can't proceed without it.
Reachable two ways: Coal's URL and your own domain
By default your bundle lives at https://api.usecoal.xyz/p/{slug}/…. You can also serve it from a domain you own — and both work at once.
After you add a custom domain, the exact same bundle answers at:
https://api.usecoal.xyz/p/twitter-aio/user/44196397— Coal's URLhttps://api.twitter-aio.com/user/44196397— your domain
Both hit the same paywalls, settle the same way, pay the same wallet. Agents that discover you through Coal's catalog use Coal's URL; anyone you hand your own URL to uses your domain. Coal routes by Host header internally.
To set it up (Console → Paywalls → your bundle → Custom domain):
- Add a
CNAMEon your domain pointing tocname.vercel-dns.com. - Register the domain on the bundle and ping
dev@schemalabs.xyzto attach it on Coal's side (TLS is auto-provisioned). - Once DNS propagates,
https://your-domain/{path}routes to your bundle by Host header.
Custom domains are a proxy-mode feature — they front the same Coal bundle. If you run the SDK in your own server instead, your domain is already the endpoint by definition; see SDK mode.
The three secrets
Integrations involve up to three credentials. They're easy to conflate, so here's exactly what each one is:
| Secret | You set it… | What it's for |
|---|---|---|
| Upstream auth header | on the bundle, in the console | Your key to your upstream API (e.g. a RapidAPI key). Coal encrypts it and injects it on each forward. The agent never sees it. Optional — only if your origin needs auth. |
Origin signature secret (COAL_FORWARDER_SECRET) | Coal generates it; you put it on your origin | Lets your origin verify the Coal-Signature header and reject anything that didn't come through Coal. Optional but recommended — it's what stops someone who finds your origin URL from bypassing the paywall. |
Coal API key (coal_live_…) | you generate at /console/keys | Calling Coal's management REST API from your backend (create checkouts, manage paywalls programmatically). Not used by the proxy path or the payment SDK at all. |
You do NOT need a Coal API key to accept agent payments
The proxy path and the payment SDK are keyed by the resource (bundle slug / paywall id), not by an API key. The coal_live_ key is only for hitting Coal's management API. If you're just monetizing endpoints, you'll never touch it.
Upstream auth header forwarding
When you create a bundle, you can attach one origin auth header (typically x-api-key or Authorization). Coal encrypts the value at rest with AES-256-GCM and never re-displays it after save. On every paid call it's decrypted in memory and attached to the forwarded request — never sent to the agent. This is how you monetize an API you call with your own key (e.g. a RapidAPI passthrough) without leaking that key.
Origin signature secret
Every forward from Coal carries Coal-Signature: t=…,v1=… — an HMAC-SHA256 over the request, keyed on your bundle's secret. Drop coalOriginGuard (one line) on your origin and it rejects any request that didn't come from Coal. Full setup, including verifiers for Python/Go/PHP/Ruby, is in the integration guide.
Slugs
Bundle and paywall slugs are URL-safe (^[a-z0-9-]{3,80}$) and unique across the platform. Coal reserves a few words (admin, api, app, console, docs, pay, webhooks, …) that can't be used. If you don't provide a slug, Coal generates one from the name; collisions get a short counter (twitter-aio-2).
Two ways to set a bundle up
Proxy (manual) — paste your origin URL, add endpoints one at a time. Best when you have a handful of endpoints.
OpenAPI import — paste your spec URL and Coal bulk-creates one paywall per operation, auto-priced. Best for any API with an OpenAPI / Swagger spec. See OpenAPI import.
Open Console → Paywalls → New Paywall ▾ → Proxy to upstream API. Prefer to run middleware in your own server with no proxy at all? That's SDK mode.
Where it lives in the console
API bundles are filed under Paywalls — they're the upstream-proxy flavor of a paywall.
/console/paywalls— every paywall, filterable by Standalone vs Upstream/console/paywalls/upstream/{id}— bundle detail: child paywalls, the origin signature secret + middleware snippet, and the custom-domain card/console/paywalls?create=proxy— create a new bundle
Old /console/api-bundles URLs 308-redirect to the new paths.
