Give your agentone line.Get paid.
checkouts.md is an open format that lets coding agents and app builders add a working checkout to any project. Railbed is the default provider.
Read checkouts.md and add a checkout to this app.
New to Railbed? Create an account first. It takes your business name and the wallet you’ll be paid in.
Works with Claude Code, Codex, Cursor, Copilot, Windsurf, Lovable, Bolt, Replit and v0.
One pasted line starts the run. Your agent reads checkouts.md, which answers agents in Markdown and people with this page.
Steps 1–2 · Approval
Your agent works in your account. You approve it once.
Start with a Railbed account: your business name and the wallet you’ll be paid in. When your agent asks to connect, it shows you a link and a code. Open the link, check the code matches, choose Test and Live or Test only, and approve.
The keys go straight from Railbed into your project’s settings or your host’s secrets. You never copy them, and they never appear in the chat with your agent.
- The code has to match. Your agent and the Railbed page show the same eight characters.
- Keys are made once. Railbed creates them when your agent collects them, and hands them over a single time.
- Your team hears about Live keys. Railbed emails your owners and developers whenever one is made.
- You stay in charge. Every change shows in your dashboard, and you can revoke the keys in Developers.
Under the hood POST /api/connect
A device sign-in, the same shape TVs and command lines use. Your agent starts it and keeps a private device code; you see only the short code.
POST https://checkouts.md/api/connect
{ "client": "Claude Code", "project": "lumen" }
201 { "user_code": "7HQ2-XK4M",
"verification_uri_complete": "https://app.railbed.io/connect?code=7HQ2-XK4M",
"device_code": "rbdc_…", "interval": 3, "expires_in": 900 }
POST https://checkouts.md/api/connect/token
{ "device_code": "rbdc_…" }
202 { "status": "pending" } // until you approve
200 { "status": "approved", "keys": { "test": {…}, "live": {…} } } // once| Answer | Means |
|---|---|
| 202 pending | Not approved yet. Ask again after interval seconds. |
| 200 approved | The keys, created now and returned this once. |
| 403 access_denied | The person declined. |
| 410 expired_token | Fifteen minutes passed. Start again. |
| 410 already_delivered | The keys were handed over already. |
| 429 slow_down | Asked faster than interval. |
npx checkouts.md login does all of this and writes RAILBED_SECRET_KEY into .env (Test) and your host’s secrets (Live), printing only rb_test_••••3f9a. Full detail in the playbook.
Step 3 · The file
CHECKOUTS.md records how a project takes money.
It sits at the project’s root: provider, mode, products and prices, where the checkout lives, what must happen after payment, the names of its secrets (never the values) and test evidence. Any agent that later touches payments reads it first. Think AGENTS.md or llms.txt, for money.
---
checkouts: 0.1
provider: railbed
mode: test
currency: USD
---
# Checkouts
## Products
| id | name | price |
| ----------- | ---------------- | ----- |
| credits_500 | 500 credits | 9.00 |
| course_pro | Lighting course | 49.00 |
## After payment
On `payment.paid`, re-read the payment by id,
then grant what was bought: credits, or the course.
Code: src/billing/fulfil.ts
## Wiring
Checkout POST /api/checkout src/routes/checkout.ts
Webhook POST /api/railbed/hook src/routes/railbed-hook.ts
Secrets RAILBED_SECRET_KEY, RAILBED_WEBHOOK_SECRET
## Evidence
- 2026-10-14 test payment pay_8KfW2q paid, course granted
- Live: ready, Live key in host secrets
checkouts: 0.1The format version.
provider: railbedAny provider can implement the format; Railbed is the default.
## ProductsWhat the agent may charge for. Prices are decimal strings in the currency’s units.
## After paymentWhat must happen once money arrives, and where that code lives.
SecretsNames only. Values live in your host, never in git or chat.
## EvidenceThe last test with its payment id, so the next agent can trust the setup.
The full format, with every field and the rules a provider follows, is in spec.md. A blank file to start from: templates/CHECKOUTS.md.
Step 4 · Wiring
Wired from a recipe for your stack.
A server route, a Pay button and a webhook handler that checks every signature. Each recipe is a Markdown page your agent follows from start to finish: the exact files it adds, the environment variables, how to test it and how to go live.
const res = await fetch('https://pay.railbed.io/v1/checkout_sessions', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.RAILBED_SECRET_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': order.id,
},
body: JSON.stringify({
amount: '49.00',
currency: 'USD',
description: 'Lighting course',
reference: order.id,
success_url: 'https://example.com/thanks?order={REFERENCE}',
}),
});
const session = await res.json(); // send the buyer to session.url
R3A decimal string in the currency’s units.
Step 5 · Proof
Nothing goes live until a test payment proves it.
In Test mode your agent pays its own checkout with a simulated card. No card is charged and no money moves, but everything else is real: Railbed sends a signed payment.paid event to your app, your app checks the signature, reads the payment back by its id and fulfils the order.
- Pay once
- Railbed signs
payment.paid. Your app checks the signature, re-reads the payment by id and fulfils the order. - Resend
- The same event arrives again. The order is keyed on the payment id, so nothing happens twice.
- Break the seal
- The signature fails and the event is turned away. The redirect back to your site never marks anything paid.
Check the signature yourself Railbed-Signature
Every event carries Railbed-Signature: t=…,v1=…: an HMAC-SHA256 of {t}.{raw body} with your endpoint’s secret. During a secret change it carries two v1 values; accept either.
import crypto from 'node:crypto';
export function verify(rawBody, header, secret, toleranceSec = 300) {
const parts = header.split(',').map((p) => p.trim().split('='));
const t = Number(parts.find(([k]) => k === 't')?.[1]);
const sigs = parts.filter(([k]) => k === 'v1').map(([, v]) => v);
if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false;
const expected = crypto.createHmac('sha256', secret)
.update(`${t}.${rawBody}`).digest('hex');
return sigs.some((s) => s.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(s), Buffer.from(expected)));
}Python, PHP and the other stacks are in each recipe. To test locally, your webhook URL must be reachable from the internet: a temporary tunnel or your platform’s preview URL works.
Step 6 · Live
Then it flips the switch. Nothing else changes.
When the test has passed, your agent switches to the Live key that has waited in your host’s secrets since the approval (made then, if you chose Test and Live, and never in the chat), and writes the evidence into CHECKOUTS.md: the test payment’s id and the date. The route, the button and the webhook are the ones the test just proved.
The evidence stays in the file, so the next agent that touches payments reads the test’s id and date before it changes anything. Your first sale arrives the way the test did: the same signed payment.paid to your webhook, the same order, now with a real card.
Paste one line. Your agent does the rest.
Read checkouts.md and add a checkout to this app.
First time? Create a Railbed account, then paste the line. Your agent asks you for one approval, and nothing else.
Where the line goes, tool by tool
Coding agents run a small command that keeps keys out of the chat. App builders connect over HTTPS and keep the keys in the platform’s secrets, never in the chat.
In your project folder, start claude and paste the line.
npx checkouts.md login.env for Test, your host’s secrets for Live. Add the skill with npx checkouts.md skill.
General notes
Five rules every agent follows. Fig. 1 and the recipes cite them by number.
- R1
Secrets never enter chat, logs or git. Only their names go in CHECKOUTS.md.
- R2
Paid means a verified signed webhook, then a re-read of the payment by id. Never the redirect back to your site.
- R3
Amounts are decimal strings in the currency’s units, like
"49.00". - R4
Test before Live, and record the evidence.
- R5
Ask the person only for the account and the approval. Everything else is the agent’s job.
Default provider
Railbed
Railbed takes cards from any customer and settles every sale to a wallet you control. Built for businesses other processors turn away.
- Nothing to freeze. Every sale settles to a wallet you control. Railbed never holds your money.
- No reserve. Nothing is held back from your sales.
- Fees from 0.9% per sale, shown on each payment in your dashboard.
Building a payments platform? Implement checkouts.md for your provider. The spec’s Providers section says what it takes: spec.md.
The files an agent reads
This page explains. The files below instruct: every request, every error and every recipe in full, written for agents to follow.
| No. | Item | What it is |
|---|---|---|
| 1 | index.md | This page as Markdown, when your agent asks for it |
| 2 | playbook.md | The procedure, start to finish, with every error and its fix |
| 3 | spec.md | The CHECKOUTS.md format, version 0.1 |
| 4 | recipes/<stack>.md | One recipe per framework or app builder |
| 5 | skill/SKILL.md | The installable skill |
| 6 | llms.txt | The index for language models; llms-full.txt has everything in one file |
| 7 | POST api/connect | Asks for access to a Railbed account, for its person to approve |
| 8 | npx checkouts.md | The command line: login, webhook, test, skill, status |
| 9 | mcp.railbed.io/mcp | Railbed’s MCP server, for assistants that work on an account |
$ curl -H "Accept: text/markdown" https://checkouts.md
# checkouts.md
> You are reading checkouts.md. To add a checkout to the project you are
> working on, follow playbook.md from step 1: https://checkouts.md/playbook.md. …
> Ask the person for two things only: a Railbed account and one approval.
> Never ask them to paste a key into the chat, and never print one.
…Questions
Do I need to know how to code?
No. Your agent writes the code and runs the test. You create the Railbed account, approve your agent once, and check the result.
Can my agent move my money?
No. The keys let it create checkouts, payment links and webhook endpoints, and run test payments. Railbed never holds your money: every sale settles straight to the wallet you control.
What does it cost?
checkouts.md is free and open. Railbed’s fee starts at 0.9% per sale, and the dashboard shows each payment’s fees.
Which agents work?
Any agent that can read a web page and edit your project. Coding agents use npx checkouts.md; app builders that can’t run commands connect over HTTPS.
Can I use a different provider?
The format is open. A provider that offers a safe connect step, a test mode, signed events and payments you can read back can implement it. Railbed is the default, and today the only one.
What if my agent gets stuck?
The playbook lists every error an agent can meet and how to fix it. If you’re still stuck, email support@railbed.com.