Reservory REST API
Public API surface. All responses are JSON. CORS-enabled where indicated (anon endpoints). Mutating POSTs accept an Idempotency-Key header for safe client retries.
Machine-readable spec: /api/openapi.json (OpenAPI 3.1, covers the public booking + payment surface). Import into Postman, Stoplight, or any SDK generator.
Auth at a glance
- anon — no auth; CORS-open; rate-limited where relevant
- signed token — HMAC token issued at booking-create or waiver-dispatch; passed as a header (
X-Booking-Token) or URL segment - operator staff+/manager+/admin+ — Supabase JWT bearer;
requireOperatorenforces the role floor server-side
Booking
/api/widget/experience?tenant=&experience=anonWidget bootstrap. Returns experience metadata + first 40 available slots (capacity-aware).
/api/bookings/holdanonAcquire a 10-minute soft hold on N seats. Rate-limited 10/min/IP.
{ slot_id, experience_id, seats }Supports Idempotency-Key header. CORS-enabled.
/api/bookingsanonConvert a hold into a booking. Returns a signed booking_token for the customer payment-intent route.
{ hold_id, slot_id, experience_id, venue_id, customer:{email,first_name,last_name?,phone?}, guest_count, notes? }Supports Idempotency-Key. Idempotent: same key + body returns cached response.
/api/bookings/[id]/canceloperator manager+Cancel a held / payment-pending / confirmed booking. Does NOT refund.
/api/bookings/[id]/check-inoperator staff+Stamp checked_in_at + checked_in_by_user_id. Idempotent.
Payments
/api/embed/bookings/[id]/payment-intentsigned tokenCustomer-facing PI creation. Requires X-Booking-Token (HMAC issued at booking-create).
/api/payments/bookings/[bookingId]/payment-intentoperator manager+Operator-side PI creation (in-person collection).
/api/payments/refundsoperator manager+Refund (full or partial) a previously confirmed payment.
{ paymentIntentId, amountCents?, reason?: duplicate|fraudulent|requested_by_customer }/api/payments/connect/onboarding-linkoperator admin+Start or resume Stripe Connect Standard onboarding. Returns a hosted URL.
Operator CRUD
/api/venuesoperator manager+Create a venue.
{ name, slug, timezone?, currency? }/api/venues/[id]operator manager+Update venue name/status/timezone.
/api/experiencesoperator manager+Create an experience.
/api/experiences/[id]operator manager+Update experience.
/api/slotsoperator manager+Create a slot. Capacity defaults to experience.default_capacity.
{ experience_id, starts_at, ends_at, capacity? }/api/slots/[id]operator manager+Delete a slot (only if unbooked).
Waivers
/api/waivers/[token]signed tokenReturn waiver + booking context. Token is HMAC, 14d TTL.
/api/waivers/[token]/signsigned tokenPersist signature (data URL) + signer name. Idempotent on re-sign.
{ signer_name, signature_data_url }Team
/api/team/inviteoperator admin+Invite a teammate by email + role.
{ email, role: admin|manager|staff, first_name? }/api/team/members/[id]operator admin+Change role.
/api/team/members/[id]operator admin+Revoke membership. Refuses last-owner removal and self-removal.
Webhooks (outbound)
/api/webhooks/endpointsoperator admin+Create a subscription. Signing secret returned once.
{ url, events:[booking.created, booking.confirmed, booking.cancelled, refund.created, waiver.signed] }/api/webhooks/endpoints/[id]operator admin+Delete a subscription. Pending deliveries dropped.
GDPR + import + alerts + data
/api/data-exportoperator admin+Download a JSON bundle of all tenant data.
/api/deletion-requestsoperator admin+Queue a customer for anonymisation. 30-day cooling-off.
{ customer_email, reason? }/api/deletion-requests/[id]/canceloperator admin+Cancel a pending deletion.
/api/import/customers/previewoperator admin+Parse a CSV, auto-detect columns, return preview.
{ csv }/api/import/customers/commitoperator admin+Upsert previewed rows.
{ rows: [...] }/api/alerts/[id]/resolveoperator admin+Mark a capacity alert resolved.
{ notes? }/api/tenants/waiver-textoperator manager+Get current per-tenant waiver override.
/api/tenants/waiver-textoperator admin+Set or reset (empty string) waiver override.
{ waiver_text }Webhook signatures
Outbound webhook deliveries include X-Reservory-Timestamp and X-Reservory-Signature: v1,<hex>. The signature is HMAC-SHA256 of `${timestamp}.${rawBody}` with your endpoint's signing secret. Reject deliveries older than 5 minutes to mitigate replay attacks.