# Agent Restaurant Reservation API > Agent-first API for searching and booking restaurant reservations on Resy — instant bookings plus reservation jobs that book the moment a booking window opens. Supports per-account API keys (subscription), MPP (Tempo), and x402 (Base/Solana) wallet authentication. - Agents authenticate via per-account API key (`x-agent-key` header) or crypto wallet (MPP / x402); a key and a wallet are always separate accounts - API keys: $6/month subscription (first 30 days free) — purchase at https://agentres.dev/purchase or contact admin; an active subscription covers all paid operations at $0 - Wallet auth: identity endpoints are free — prove wallet ownership with SIWX (`SIGN-IN-WITH-X` header, preferred; SIWE on Base, SIWS on Solana) or a zero-dollar payment proof (`PAYMENT-SIGNATURE` — cryptographically verified, never settled; works with any x402 client); booking costs $0.01 USDC, a reservation job costs $3.00 USDC, a wait-time query costs $0.01 USDC, and a restaurant-discovery query costs $0.01 USDC - Pay only for success: every paid operation is recorded as a charge (`charge_id`); failed bookings refund automatically, failed/canceled/timed-out reservation jobs become `refund_pending` and are claimed via `POST /api/reservation-jobs/{id}/refund` - Replayed payment proofs return `409 DUPLICATE_PAYMENT` with the original `charge_id` so a lost response can be recovered - 402 responses include both MPP and x402 headers — clients choose either protocol - Do not combine `x-agent-key` with wallet auth in one workflow ## API Docs - [OpenAPI 3.1 spec](https://agentres.dev/openapi.json): Canonical machine-readable schema with request/response types, error codes, `x-guidance`, and `x-payment-info` per endpoint - MCP server (Streamable HTTP): `https://agentres.dev/api/mcp` — same capabilities as the HTTP API for API-key subscribers; authenticate with `Authorization: Bearer ` ## Agent Onboarding - [Onboarding skill — wallet pay-per-use](https://agentres.dev/skill.md): Canonical conversational workflow for x402/MPP wallet auth — setup account, link Resy, search restaurants, check availability, book, create reservation jobs, list reservations, and cancel - [Onboarding skill — API-key subscription](https://agentres.dev/skill.md?auth=apikey): Same workflow geared exclusively to API-key subscription auth (Stripe, `x-agent-key` header) ## Workflow Notes - Start authenticated workflows with `POST /api/account`, then `GET /api/me` - Path A (API key): call `POST /api/account` with `{}`; only ask for the user's Resy.com email if linking Resy is needed. Paid calls need an active subscription (`403 SUBSCRIPTION_REQUIRED` otherwise) - Path B (wallet): ask once for the user's Resy.com email, use it for `POST /api/account` and reuse the same email for `/api/link-resy`; do not describe this as creating or attaching a wallet account - Link Resy via two-step OTP: request code with `POST /api/link-resy`, wait for the 6-digit code, then verify with the same `em_address` - Always fetch fresh `/api/availability` immediately before `/api/book` because `config_id` can expire - For hard-to-get tables whose booking window has not opened yet, use `GET /api/reservation-jobs/options` to check support, then `POST /api/reservation-jobs/create` to create a reservation job that books the moment reservations open - For restaurant recommendations ("recs in the West Village"), use `GET /api/discover/restaurants?neighborhood=west+village` ($0.01 USDC, covered with subscription; no Resy link needed) — specials are always included from a daily-refreshed cache; use `fields=slim` to sweep a neighborhood cheaply (default 50, max 200 results) before drilling into specific restaurants; feed a chosen restaurant's name into `/api/search` to book it on Resy - Booking, reservation-job creation, and cancellation require explicit user confirmation before calling the API ## Auth Protocols - [MPP (Tempo)](https://tempo.xyz): Machine Payments Protocol — 402 challenge via `WWW-Authenticate`, wallet signs and retries with `Authorization: Payment `. Chain: Tempo Mainnet (ID 4217), currency: USDC (`0x20C000000000000000000000b9537d11c60E8b50`), recipient: `0x66717045858D9f598e2ebd046bf42A0B1063C0Fa` - [x402 (Base)](https://www.x402.org): HTTP 402 standard — 402 response includes `PAYMENT-REQUIRED` header, client signs `PaymentPayload` and retries with `PAYMENT-SIGNATURE` header. Chain: Base (ID 8453), currency: USDC (`0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913`), recipient: `0x66717045858d9f598e2ebd046bf42a0b1063c0fa` - [x402 (Solana)](https://www.x402.org): HTTP 402 standard — 402 response includes `PAYMENT-REQUIRED` header, client signs `PaymentPayload` and retries with `PAYMENT-SIGNATURE` header. Chain: Solana (`solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp`), currency: USDC (`EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v`), recipient: `FCFgb8Z63uwim2QpDJW4TGwLqZoENjckwGosLmg26zBS` - SIWX identity (CAIP-122 Sign-In-With-X): the preferred wallet identity mechanism for the $0 endpoints — read the `sign-in-with-x` extension from an identity endpoint's $0 402 `PAYMENT-REQUIRED` header, sign the CAIP-122 message (SIWE on Base, SIWS on Solana), retry with the base64 payload in the `SIGN-IN-WITH-X` header. Nonces are single-use; fetch a fresh challenge per request. Identity only — paid 402s do not carry the extension; paid endpoints always settle via x402/MPP. Clients without SIWX support can instead sign the $0 accepts and send a zero-dollar `PAYMENT-SIGNATURE` proof — both are fully supported ## Endpoints - `POST /api/account`: Setup — returns the account resolved/created from the verified credential (`account_id`, `credential_kind`); optional `email` body sets contact metadata (identity auth) - `GET /api/me`: Account profile, Resy link status, and subscription state (identity auth) - `POST /api/link-resy`: Link Resy account via two-step OTP (identity auth) - `GET /api/search?query=&city=`: Search Resy for restaurants by name, cuisine, or keyword; `city` is optional and defaults to `nyc` (identity auth) - `GET /api/availability?venue_id=&party_size=&day=`: Check available time slots (identity auth) - `POST /api/book`: Book a reservation now — $0.01 USDC on wallet rails, covered with subscription; failed bookings refund automatically (paid auth) - `GET /api/reservations?type=upcoming&limit=10`: List upcoming or past linked Resy reservations (identity auth) - `POST /api/cancel`: Cancel a booked reservation using a `resy_token` from `/api/reservations` (identity auth) - `GET /api/reservation-jobs/options`: List restaurants that support reservation jobs, with booking-window rules (public, no auth) - `POST /api/reservation-jobs/create`: Create a reservation job that books the moment reservations open — best-effort: if the preferred time is taken it books the closest available time, and a booking is not guaranteed; $3.00 USDC on wallet rails, covered with subscription; duplicates (`409 ACTIVE_JOB_EXISTS`) and enqueue failures refund automatically (paid auth) - `GET /api/reservation-jobs?limit=&status=`: List this account's reservation jobs (identity auth) - `GET /api/reservation-jobs/{job_id}`: Job status with payment state; terminal failures show `refund_pending` (identity auth) - `POST /api/reservation-jobs/{job_id}/cancel`: Cancel a queued job; the charge becomes `refund_pending` (identity auth) - `POST /api/reservation-jobs/{job_id}/refund`: Claim the refund for a canceled/failed/timed-out job; idempotent (identity auth) - `GET /api/wait-times`: Live restaurant wait times from camera-based crowd data — one call returns every monitored location with its current status; no Resy link required — $0.01 USDC on wallet rails, covered with subscription (paid auth) - `GET /api/wait-times/history?location=&since=&until=&interval=`: Historical line counts for one location, raw or aggregated — $0.01 USDC on wallet rails, covered with subscription (paid auth) - `GET /api/discover/restaurants?query=&city=&neighborhood=&fields=&has_specials=&limit=&offset=`: Discover Blackbird-network restaurants — free-text search plus city/neighborhood filters. Specials are always attached, refreshed daily (never live): `[]` = checked, no current offers; `null` = never checked. Rows are compact by DEFAULT (`{id, name, specials, specials_checked_at}`, default limit 50/max 200); `fields=full` opts into locations/cuisine/price/complete specials on list rows at 20/max 100. `has_specials=true` returns only restaurants with a current offer (~8% of the catalog) — the right tool for deal-hunting; `has_specials=false` means confirmed-none, and never-checked restaurants are excluded from both. The legacy `include_specials` param is accepted and ignored. No Resy link required — $0.01 USDC on wallet rails, covered with subscription (paid auth) - `GET /api/discover/restaurants/{restaurant_id}`: Blackbird restaurant detail — locations, addresses, coordinates, live open hours — $0.01 USDC on wallet rails, covered with subscription (paid auth) - `GET /api/discover/restaurants/{restaurant_id}/specials`: Complete cached Blackbird specials/offers for one restaurant, e.g. Fly-reward multipliers (`specials` is nullable: `null` = never checked, `[]` = checked with none) — $0.01 USDC on wallet rails, covered with subscription (paid auth)