---
title: "Place a reservation (async — a call is placed to the merchant)"
method: POST
path: "/v1/bookings"
---

# Place a reservation (async — a call is placed to the merchant)

`POST /v1/bookings`

## Request

- Base URL: `https://mercantry.org`
- URL: `https://mercantry.org/v1/bookings`
- Auth: one of:
  - none
  - API key in header `x-api-key`

Returns booking_id with state=queued immediately. Poll GET /v1/bookings/{id} or supply callback_url for webhooks. With accept_within_window=true (recommended), merchant counter-offers inside ±window_minutes auto-confirm without a round-trip. Retry safety: send a unique client_reference_id (or Idempotency-Key header); retrying with the same value returns the existing booking (200, idempotent_replay=true) instead of double-booking.

## Headers

- `Idempotency-Key` string

## Request body

- object
  - `merchant_id` string, uuid, required
  - `party_size` integer, required
  - `datetime` string, required: Requested time, ISO-8601. Naive (2026-07-18T19:00) means the merchant's local wall time; an explicit offset is also accepted.
  - `window_minutes` integer
  - `accept_within_window` boolean
  - `reservation_name` string, required
  - `contact` string: Optional phone/email for confirmation relay to the end human.
  - `special_requests` string
  - `callback_url` string: Webhook URL for booking state-change events.
  - `client_reference_id` string: Your unique ID for this booking request (a UUID is ideal). Retrying with the same value returns the existing booking instead of creating a duplicate; scoped per API key.
  - `sandbox_outcome` 'confirmed' | 'no_answer' | 'counter_offer' | 'fully_booked' | 'merchant_declined' | 'bad_data': TEST ONLY, sandbox merchants (sandbox: true): force the simulated call's result so an integration can exercise a chosen branch on demand. Rejected with sandbox_outcome_requires_sandbox_merchant for real merchants. Walkthrough: /demo.

## Response `200`

Idempotent replay: {ok, booking_id, state, idempotent_replay: true} — an existing booking matched client_reference_id; nothing new was created.

## Other responses

- `201`: Accepted: {ok, booking_id, state: queued}.
- `400`: Structured rejection, e.g. merchant_not_phone_verified, requires_deposit_not_supported_in_v1, party_size_out_of_range (with the merchant's real range in `allowed`).
- `401`: invalid_api_key | key_throttled_high_no_show_rate (keys are optional; omit rather than guess).
- `404`: unknown_merchant.
- `409`: client_reference_conflict: this client_reference_id was already used with different request parameters — use a fresh reference for a genuinely new booking.
- `429`: rate_limited — wait Retry-After seconds, then resume.

---

[API](https://skmtc.dev/mercantry/apis/registry-agent-native-merchant-registry-rest-mirror.md) · [All operations](https://skmtc.dev/mercantry/apis/registry-agent-native-merchant-registry-rest-mirror/llms.txt) · [OpenAPI document](https://skmtc.dev/mercantry/apis/registry-agent-native-merchant-registry-rest-mirror/revisions/0a9bf614fe96?raw)
