Documentation

Docs

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.

What this is

BookingLayer turns real-world booking into a programmatic service for AI agents:

  • Agents connect over MCP (Streamable HTTP) and get a native booking toolset — or import a zero-dependency SDK from the URL.
  • A booking is funded from an escrowed budget (per-item caps); the design is non-custodial and settles once per plan.

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.

Testing vs production

One service, two endpoints:

ModeMCP endpointWhat it does
Testing (recommended)/test/mcpFull 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/mcpReal 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.
In beta, use testing. Production is deployed to validate the real path end-to-end up to settlement; it just isn't wired with money.

Quickstart

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.

The proposal model

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:

  • Scopes search — you query availability inside the proposal’s constraints (kind, place, dates, party).
  • Pre-authorizes purchase — if a match is found, it can be booked without another signature, up to the budget. Authorization can be one-shot or standing (revocable any time).
A proposal is an intent to purchase, not a free search key. Treat it as a commitment — see fair use.

Verification, tokens & Proof-of-Work

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:

  • You hold a signed proposal (per-plan, or a standing/full-access mandate, or just to extend) → token immediately.
  • Full-access on file for (principal, agent) → token immediately, no extra step.
  • Neither → you get a signingUrl to get the proposal signed and (optionally) a callbackUrl we POST the token to once it is — so the agent keeps working meanwhile.
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

For agents · MCP & SDK

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.

Tools

ToolDoes
statusMode (testing/production), your wallet, and whether you hold a token.
list_servicesWhat can be booked (live + coming-soon).
verifyEscrow a budget → search token + initial availability. budgetUsdc is per item.
poll_verificationPoll a pending human approval until the token is ready.
searchAvailability within scope — one tool for every service (pick with type). No payment.
bookBook a part; its price is captured from the escrowed budget.
rescindPull out and get refunded ($1 only if inventory still existed).

HTTP API

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.

Money & escrow

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.

In beta this runs in testing, where the budget and settlement are simulated on a mock ledger — no real money moves. Production uses the same flow with real USDC over x402, and isn't funded yet.

Endpoints

Method & pathPurpose
GET /v1/discoveryService descriptor
GET /v1/schemaFull machine manual (flow, proposal, errors)
GET /v1/catalogueBookable services + fees
POST /v1/verify/challengePoW challenge (step 1)
POST /v1/verifyVerify a proposal → search token
POST /v1/searchToken-gated search (step 2; type filter)
POST /v1/quoteFirm quote + x402 requirement
POST /v1/bookBook by x402 (402 until paid)
POST /v1/access/grant · /revokeFull access for an agent (by wallet)
GET /v1/bookings/:idStatus + receipt

Fair use & rate limits

Search is cheap but not free to us, and a proposal is a commitment. To keep the service fast and the supplier relationships healthy:

  • Rate limit. Requests are capped per IP (currently 120/min); responses carry X-RateLimit-* headers and a 429 with Retry-After when exceeded.
  • Search-to-book ratio. Submitting a proposal means you intend to buy if a fitting option exists. An extreme search-to-book ratio signals abuse and gets throttled.
  • Cancellations. Repeated cancellations after booking are abuse and are penalized.
  • Enforcement. Sustained abuse leads to escalating rate limits and, ultimately, an IP ban.
In short: don’t use proposals as a free search API. Search because you intend to book.

Errors

CodeHTTPMeaning
payment_required402Supply a signed USDC authorization in X-PAYMENT.
authorization_failed403Outside the proposal’s scope or budget.
authorization_revoked403This proposal was revoked.
details_required422Missing traveler details for this kind.
price_exceeded409Live price rose past your authorized amount; refunded.
rate limit exceeded429Slow down; see Retry-After.