Skip to main content

REST API Reference

Reservly exposes 7 public endpoints under /api/public/{slug}/. All GET endpoints are publicly accessible without authentication. The POST /book endpoint requires an API key — pass it as Authorization: Bearer rsvly_....

Localization

Business-authored content (names, descriptions, staff bios, ticket-tier names) can be translated. By default every endpoint returns the raw translation maps — name_translations, description_translations, category_translations, bio_translations — and leaves it to you to pick a language.

Alternatively, add ?locale= to /services, /staff, /events or /rentals and Reservly resolves them for you. The base fields carry the translated text, and the now-redundant *_translations keys are omitted from the response. Nested collections are resolved too — events[].inventory[] and add_on_rentals[].

The parameter is fully optional and never fails a request. Omit it and the response is byte-for-byte what it has always been, so existing integrations are unaffected. Supply a language the business does not offer — or a malformed value — and you get the business's own default content with a 200, not an error. The languages a business supports are listed as languages on /info.

Two limits worth knowing: /info does not accept locale (it returns no translatable fields), and rental category has no translations in the data model, so it is returned untranslated.

Deprecations

short_description and short_description_translations were removed on 2026-08-20 (FC-42 — announced for 2026-09-19, removed early pre-launch by founder decision; no registered consumers existed). Read description / description_translations.

Pricing quotes

Catalogue prices are list prices. A business's pricing rules (seasonal, day-of-week, flash-sale, early-bird…) can move what a booking actually costs, so /services, /events and /rentals also return quoted_price beside every price: the price of one unit computed by the same pricing engine the booking flow charges with. Each response carries a quote object stating what the quote assumes. Quote from quoted_price, never price — the list price is not what the customer will pay when rules apply.

Services and rentals quote for the business's current date by default; pass ?date=YYYY-MM-DD to quote a specific booking date (a malformed date returns 400). Events always quote for the event's own date and start time. For rentals the quoted number is the rules-adjusted rate (see price_type). Rules that need a booking time, a cart, or a customer identity are decided at booking time — POST /book returns the authoritative total, and quoted_price is null for unpriced (free) items or when quote.applies_pricing_rules is false.

Business Info

GET/api/public/{slug}/info
Returns public business profile information including name, logo, currency, timezone, enabled modules, social links, action buttons, payment providers, and cancellation policy.

Example Request

curl https://reservly.io/api/public/luxe-salon/info
bash

Example Response

{
  "name": "Luxe Salon",
  "slug": "luxe-salon",
  "logo_url": "https://cdn.reservly.io/logos/luxe-salon.png",
  "currency": "USD",
  "timezone": "America/New_York",
  "default_language": "en",
  "languages": ["en", "es"],
  "modules_enabled": {
    "services": true,
    "events": false,
    "rentals": false
  },
  "social_links": {
    "instagram": "https://instagram.com/luxesalon"
  },
  "action_buttons": [
    {
      "type": "link",
      "label": "Visit Website",
      "icon": "globe",
      "content": "https://luxesalon.com",
      "order": 0
    }
  ],
  "has_payment_providers": true,
  "payment_providers": ["stripe"],
  "cancellation_policy": [
    { "hours_before": 24, "refund_percent": 100 },
    { "hours_before": 2, "refund_percent": 50 }
  ]
}
json

List Services

GET/api/public/{slug}/services
Returns all active services for the business, sorted by display order. Includes pricing, duration, delivery mode, and translation data.

Parameters

NameTypeRequiredDescription
localestringOptionalResolve name and description into this language and omit the *_translations maps. See Localization.
datestringOptionalBooking date (YYYY-MM-DD) quoted_price should assume. Defaults to the business's current date. Malformed values return 400. See Pricing quotes.

Example Request

curl https://reservly.io/api/public/luxe-salon/services
bash

Example Response

{
  "services": [
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "name": "Haircut & Style",
      "description": "Full haircut with wash and blow-dry, finished with a style. Tell us how you like it and we will match the last cut you loved.",
      "duration_minutes": 60,
      "price": 75,
      "quoted_price": 86.25,
      "currency": "USD",
      "image_url": "https://cdn.reservly.io/services/haircut.jpg",
      "allow_multiple": false,
      "has_class_schedule": false,
      "name_translations": { "es": "Corte y Peinado" },
      "description_translations": null,
      "payment_requirement": "full",
      "deposit_value": null
    }
  ],
  "currency": "USD",
  "quote": {
    "date": "2026-08-07",
    "applies_pricing_rules": true,
    "basis": "quoted_price is the engine price of one unit booked on `date` (this business's pricing rules applied). Time-of-day, cart, and customer-specific rules are decided at booking; POST /book returns the authoritative total."
  }
}
json

List Staff

GET/api/public/{slug}/staff
Returns active staff members. Optionally filter by service to get only staff qualified for a specific service.

Parameters

NameTypeRequiredDescription
service_iduuidOptionalFilter staff to only those assigned to this service
localestringOptionalResolve name, category and description into this language and omit the *_translations maps. Note bio_translations resolves into description. See Localization.

Example Request

curl "https://reservly.io/api/public/luxe-salon/staff?service_id=a1b2c3d4-e5f6-7890-abcd-ef1234567890"
bash

Example Response

{
  "staff": [
    {
      "id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890",
      "name": "Maria Garcia",
      "description": "Senior stylist with 10 years experience",
      "category": "Stylists",
      "image_url": "https://cdn.reservly.io/staff/maria.jpg",
      "bio_translations": { "es": "Estilista senior con 10 anos de experiencia" }
    }
  ]
}
json

Available Slots

GET/api/public/{slug}/slots
Calculates and returns available booking time slots for a given date and service. Accounts for business hours, staff schedules, existing bookings, blocked time, and schedule overrides.

Parameters

NameTypeRequiredDescription
datestringRequiredDate in YYYY-MM-DD format
service_iduuidRequiredService UUID. Supports comma-separated IDs for multi-service bookings.
staff_iduuidOptionalFilter slots to a specific staff member
is_packagestringOptionalSet to "true" when booking a package (uses any-staff matching)

Example Request

curl "https://reservly.io/api/public/luxe-salon/slots?date=2026-04-15&service_id=a1b2c3d4-e5f6-7890-abcd-ef1234567890"
bash

Example Response

{
  "slots": [
    {
      "time": "09:00",
      "endTime": "10:00",
      "staffId": "f1e2d3c4-b5a6-7890-abcd-ef1234567890",
      "staffName": "Maria Garcia"
    },
    {
      "time": "10:00",
      "endTime": "11:00",
      "staffId": "f1e2d3c4-b5a6-7890-abcd-ef1234567890",
      "staffName": "Maria Garcia"
    },
    {
      "time": "10:00",
      "endTime": "11:00",
      "staffId": "b2c3d4e5-a6b7-8901-cdef-234567890abc",
      "staffName": "Alex Kim"
    }
  ],
  "timezone": "America/New_York"
}
json

Rate limit: 60 requests / minute per IP

Upcoming Events

GET/api/public/{slug}/events
Returns upcoming active public events with capacity information and ticket inventory. Only events on or after today (in the business timezone) are included.

Parameters

NameTypeRequiredDescription
localestringOptionalResolve event name and description — and the nested inventory[] ticket-tier names — into this language, omitting the *_translations maps. See Localization.

Example Request

curl https://reservly.io/api/public/luxe-salon/events
bash

Example Response

{
  "events": [
    {
      "id": "c3d4e5f6-a7b8-9012-cdef-345678901234",
      "name": "Summer Hair Workshop",
      "description": "Learn the latest styling techniques in a three-hour hands-on workshop. Tools and a take-home kit are provided; no experience needed.",
      "date": "2026-05-20",
      "start_time": "14:00",
      "end_time": "17:00",
      "image_url": "https://cdn.reservly.io/events/workshop.jpg",
      "total_capacity": 30,
      "spots_remaining": 18,
      "inventory": [
        {
          "id": "d4e5f6a7-b8c9-0123-def4-567890123456",
          "name": "General Admission",
          "price": 45,
          "quoted_price": 50,
          "total_capacity": 20,
          "spots_remaining": 12,
          "name_translations": null
        },
        {
          "id": "e5f6a7b8-c9d0-1234-ef56-789012345678",
          "name": "VIP Front Row",
          "price": 85,
          "quoted_price": 93.5,
          "total_capacity": 10,
          "spots_remaining": 6,
          "name_translations": null
        }
      ],
      "name_translations": null,
      "description_translations": null,
      "payment_requirement": "full",
      "deposit_value": null
    }
  ],
  "currency": "USD",
  "quote": {
    "date": "2026-08-07",
    "applies_pricing_rules": true,
    "basis": "inventory[].quoted_price is the engine price of ONE unit of that tier for its event's own date and start time (this business's pricing rules applied; `date` here is the purchase date used for sale windows). Cart-level and customer-specific rules settle at booking; POST /book returns the authoritative total."
  }
}
json

List Rentals

GET/api/public/{slug}/rentals
Returns active rental items with pricing, availability constraints, and upsell relationships. Supports hourly and daily rentals.

Parameters

NameTypeRequiredDescription
localestringOptionalResolve name and description — across both rentals[] and add_on_rentals[] — into this language, omitting the *_translations maps. category has no translations and is unaffected. See Localization.
datestringOptionalBooking date (YYYY-MM-DD) quoted_price should assume. Defaults to the business's current date. Malformed values return 400. See Pricing quotes.

Example Request

curl https://reservly.io/api/public/luxe-salon/rentals
bash

Example Response

{
  "rentals": [
    {
      "id": "a7b8c9d0-e1f2-3456-abcd-789012345678",
      "name": "Private Styling Suite",
      "description": "Fully equipped private suite for events, with styling chairs, mirrors, a wash station and its own entrance. Sleeps up to twelve guests comfortably.",
      "category": "Spaces",
      "price": 150,
      "quoted_price": 172.5,
      "price_type": "hourly",
      "quantity": 2,
      "image_url": "https://cdn.reservly.io/rentals/suite.jpg",
      "min_rental_days": null,
      "max_rental_days": null,
      "min_rental_hours": 2,
      "max_rental_hours": 8,
      "name_translations": null,
      "description_translations": null,
      "payment_requirement": "deposit_percent",
      "deposit_value": 25
    }
  ],
  "rental_upsells": [
    {
      "rental_id": "a7b8c9d0-e1f2-3456-abcd-789012345678",
      "upsell_rental_id": "b8c9d0e1-f2a3-4567-bcde-890123456789",
      "is_required": false,
      "sort_order": 0
    }
  ],
  "currency": "USD",
  "quote": {
    "date": "2026-08-07",
    "applies_pricing_rules": true,
    "basis": "quoted_price is the engine-adjusted rate (price_type unchanged) for a booking on `date`, this business's pricing rules applied to the listed rate as a single-unit base. Duration, quantity, setup fees, duration discounts, and time/cart/customer-specific rules settle at booking; POST /book returns the authoritative total."
  }
}
json

Create a Booking

POST/api/public/{slug}/book
Creates a new booking. The end time is calculated automatically from the combined duration of the selected services. If the business has payment providers connected and the service requires payment, the response includes payment details.

Parameters

NameTypeRequiredDescription
service_idsuuid[]RequiredArray of service UUIDs to book
datestringRequiredBooking date in YYYY-MM-DD format
timestringRequiredStart time in HH:MM format (24-hour)
customer_namestringRequiredFull name of the customer
customer_emailstringRequiredCustomer email address
staff_iduuidOptionalPreferred staff member UUID
customer_phonestringOptionalCustomer phone number
form_dataobjectOptionalCustom form field responses. Reserved keys beginning with an underscore are ignored on API-key requests — in particular `_consent`, which records marketing/SMS opt-in and can only be set by the customer on the business’s own booking page.
party_sizenumberOptionalNumber of guests (defaults to 1)
class_schedule_iduuidOptionalClass session UUID. For a class-based service the session is resolved from date + time and its seat is claimed automatically, and a time with no session is rejected — so you normally omit this. Send it only to disambiguate a date and time where two sessions of the same class start together.
sourcestringOptionalAttribution source (e.g. "vapi", "n8n", "make"). Auto-tagged as "api" if omitted and request lacks browser headers.
preferred_providerstringOptionalPreferred payment provider: "stripe"

Request Body

{
  "service_ids": ["a1b2c3d4-e5f6-7890-abcd-ef1234567890"],
  "date": "2026-04-15",
  "time": "10:00",
  "customer_name": "Jane Smith",
  "customer_email": "jane@example.com",
  "customer_phone": "+1-555-0123",
  "staff_id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890",
  "source": "n8n",
  "party_size": 1
}
json

Example Request

curl -X POST https://reservly.io/api/public/luxe-salon/book \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer rsvly_YOUR_API_KEY" \
  -d '{
    "service_ids": ["a1b2c3d4-e5f6-7890-abcd-ef1234567890"],
    "date": "2026-04-15",
    "time": "10:00",
    "customer_name": "Jane Smith",
    "customer_email": "jane@example.com"
  }'
bash

Example Response

{
  "success": true,
  "booking": {
    "id": "e5f6a7b8-c9d0-1234-abcd-567890123456",
    "date": "2026-04-15",
    "start_time": "10:00",
    "end_time": "11:00",
    "status": "pending",
    "source": "n8n",
    "services": [
      {
        "name": "Haircut & Style",
        "duration_minutes": 60,
        "price": 75
      }
    ]
  }
}
json

Rate limit: 10 req/min (unauthenticated) | 100 req/min (authenticated)

Common Error Codes

StatusMeaningExample
400Invalid parametersMissing required field, bad date format, invalid UUID
403Business pending deletionThe business account is scheduled for removal and no longer accepts bookings
404Not foundInvalid slug, service ID does not exist, or resource is inactive
409Booking conflictThe requested time slot is already booked or no longer available
429Rate limitedToo many requests. Retry after the period indicated in the Retry-After header.
500Server errorAn unexpected error occurred. Contact support if it persists.