An agent-native booking service for AI agents, over MCP. Your agent escrows a USDC budget, searches within scope, and books — only the real price is captured, the rest refunded. Public beta: the testing sandbox works today; production isn't funded yet.
BookingLayer turns real-world booking into a programmatic service for AI agents:
There are no logins. The production catalogue lists hotels (live) with flights/restaurants following; the testing sandbox mocks every kind so you can run the full flow now.
One service, two endpoints:
| Mode | MCP endpoint | What it does |
|---|---|---|
| Testing (recommended) | /test/mcp | Full flow on mock inventory. No wallet, no funds, no signup — the server mints a throwaway wallet and self-signs. Bookings succeed on a mock ledger. |
| Production | /mcp | Real surface, same flow — but it cannot complete bookings yet. We're the merchant-of-record (not a marketplace) and have no pre-funded capital to pay suppliers, so book won't settle. |
Connect to the testing endpoint, then a booking is three calls (the SDK/MCP handles the budget escrow + signing):
verify({ budgetUsdc:80, kinds:["flight","restaurant"] }) # escrow + token + availability search({ type:"flight", location:"LHR", destination:"CDG" }) # what's available book({ type:"flight", location:"LHR", destination:"CDG" }) # captured from budget
budgetUsdc is the cap per item; you escrow the sum. When every available part is booked it settles once and the unused budget is refunded. rescind pulls out at any time.
A proposal (an EIP-712 intent mandate) is a signed statement: “I will buy a booking that satisfies these constraints, up to this budget.” It does two things:
Step 1 is gated by a Proof-of-Work challenge (anti-abuse, rate-limited by IP). Solve it, submit your intent, and you receive a search token good for 24 hours, rate-limited per token. The SDK/MCP solves the PoW for you (the testing sandbox uses a trivial difficulty). Three ways to verify:
POST /v1/verify/challenge # → { seed, difficulty }; solve it POST /v1/verify # proposal + pow → token | signingUrl GET /v1/verify/:id # poll a pending approval POST /v1/verify/extend # extend the token another 24h
The server speaks the MCP Streamable HTTP transport — it works with the official @modelcontextprotocol/sdk and any MCP client (Claude, Cursor, …). Just point at the URL:
// MCP client config — testing sandbox { "mcpServers": { "booking-layer": { "url": "https://booking-layer.ianb-sia.workers.dev/test/mcp" } } }
Prefer code? Import the zero-dependency SDK straight from the URL — no npm install:
import BookingLayer from "https://booking-layer.ianb-sia.workers.dev/sdk/booking-layer.mjs"; const bl = new BookingLayer(); // testing; new BookingLayer({mode:"production"}) for prod await bl.connect(); await bl.verify({ budgetUsdc:80, kinds:["flight","restaurant"] });
The human-friendly install page and /mcp.json have copy-paste config for both modes.
| Tool | Does |
|---|---|
| status | Mode (testing/production), your wallet, and whether you hold a token. |
| list_services | What can be booked (live + coming-soon). |
| verify | Escrow a budget → search token + initial availability. budgetUsdc is per item. |
| poll_verification | Poll a pending human approval until the token is ready. |
| search | Availability within scope — one tool for every service (pick with type). No payment. |
| book | Book a part; its price is captured from the escrowed budget. |
| rescind | Pull out and get refunded ($1 only if inventory still existed). |
The same capabilities over plain HTTP — for agents not using MCP, or for your own SDK. The MCP tools and the SDK wrap exactly these. Typical flow (paths are under /test/v1/… for the sandbox):
POST /v1/verify/challenge # PoW challenge → { seed, difficulty } POST /v1/verify # signed intent + budget → search token POST /v1/search # token-gated availability POST /v1/quote # firm, price-locked quote POST /v1/book # book a quote; captured from the budget
Authorization is a signed intent, approved once and optionally standing — revocable any time via POST /v1/access/revoke.
The budget is escrowed at verify, with a cap per item. Each book accrues its actual price; when the plan completes, it settles once — the booked total is captured and the unused margin is refunded. The design is non-custodial: funds can only move to the merchant (on confirmation) or back to the payer (on failure/timeout) — never elsewhere.
| Method & path | Purpose |
|---|---|
| GET /v1/discovery | Service descriptor |
| GET /v1/schema | Full machine manual (flow, proposal, errors) |
| GET /v1/catalogue | Bookable services + fees |
| POST /v1/verify/challenge | PoW challenge (step 1) |
| POST /v1/verify | Verify a proposal → search token |
| POST /v1/search | Token-gated search (step 2; type filter) |
| POST /v1/quote | Firm quote + x402 requirement |
| POST /v1/book | Book by x402 (402 until paid) |
| POST /v1/access/grant · /revoke | Full access for an agent (by wallet) |
| GET /v1/bookings/:id | Status + receipt |
Search is cheap but not free to us, and a proposal is a commitment. To keep the service fast and the supplier relationships healthy:
| Code | HTTP | Meaning |
|---|---|---|
| payment_required | 402 | Supply a signed USDC authorization in X-PAYMENT. |
| authorization_failed | 403 | Outside the proposal’s scope or budget. |
| authorization_revoked | 403 | This proposal was revoked. |
| details_required | 422 | Missing traveler details for this kind. |
| price_exceeded | 409 | Live price rose past your authorized amount; refunded. |
| rate limit exceeded | 429 | Slow down; see Retry-After. |