payload-reservepayload-reserve

REST API

Five public endpoints under /api/reserve/ for availability checks, booking creation, cancellation, and customer search.

The plugin mounts five endpoints under /api/reserve/. These are Payload custom endpoints — they respect the same access control as the rest of the API.


GET /api/reserve/availability

Returns available time slots for a resource and service on a given date. Slots are derived from the resource's active schedules for that date minus any overlapping reservations with blocking statuses.

Returns 400 if date is missing or not a valid date format.

Query parameters:

ParameterRequiredDescription
resourceYesResource ID
serviceYesService ID
dateYesDate in YYYY-MM-DD format
guestCountNoNumber of guests (used for per-guest capacity filtering)

Example request:

GET /api/reserve/availability?resource=abc123&service=def456&date=2025-06-15

Response:

{
  "slots": [
    { "start": "2025-06-15T09:00:00.000Z", "end": "2025-06-15T09:30:00.000Z" },
    { "start": "2025-06-15T09:30:00.000Z", "end": "2025-06-15T10:00:00.000Z" },
    { "start": "2025-06-15T10:30:00.000Z", "end": "2025-06-15T11:00:00.000Z" }
  ]
}

Example fetch:

const res = await fetch('/api/reserve/availability?resource=abc123&service=def456&date=2025-06-15')
const { slots } = await res.json()

GET /api/reserve/slots

Returns available slots with richer metadata. Accepts an optional guestCount parameter for capacity-aware filtering.

Query parameters:

ParameterRequiredDefaultDescription
resourceYesResource ID
serviceYesService ID
dateYesDate in YYYY-MM-DD format
guestCountNo1Number of guests (used for per-guest capacity mode)

Example request:

GET /api/reserve/slots?resource=abc123&service=def456&date=2025-06-15&guestCount=2

Response:

{
  "date": "2025-06-15",
  "guestCount": 2,
  "slots": [
    { "start": "2025-06-15T09:00:00.000Z", "end": "2025-06-15T09:30:00.000Z" },
    { "start": "2025-06-15T09:30:00.000Z", "end": "2025-06-15T10:00:00.000Z" }
  ]
}

Returns 400 with { "error": "..." } if required parameters are missing or the date is invalid.


POST /api/reserve/book

Creates a new reservation. All Payload collection hooks (conflict detection, end time calculation, status transition validation) run as normal. Runs any registered beforeBookingCreate plugin hooks before saving.

Request body: Same as payload.create data for the reservations collection.

{
  "service": "def456",
  "resource": "abc123",
  "customer": "cus789",
  "startTime": "2025-06-15T10:00:00.000Z",
  "guestCount": 1,
  "notes": "Please use the side entrance.",
  "idempotencyKey": "frontend-uuid-or-form-id"
}

Response: 201 with the created reservation document, or 400/409 if validation fails.

The idempotencyKey field prevents duplicate submissions — if a key has already been used, the request is rejected with a validation error.

Example fetch:

const res = await fetch('/api/reserve/book', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    service: serviceId,
    resource: resourceId,
    customer: customerId,
    startTime: '2025-06-15T10:00:00.000Z',
    idempotencyKey: crypto.randomUUID(),
  }),
})
const reservation = await res.json()

POST /api/reserve/cancel

Cancels a reservation. Requires an authenticated session (req.user). Only the reservation's customer or an admin/staff user can cancel — non-owners receive 403 Forbidden.

Request body:

{
  "reservationId": "res123",
  "reason": "Change of plans"
}

Response: 200 with the updated reservation document.

Returns 401 if not authenticated, 403 if the authenticated user is not the reservation's customer or an admin, 400 if reservationId is missing. The validateCancellation hook enforces the minimum notice period configured in cancellationNoticePeriod.

Example fetch:

const res = await fetch('/api/reserve/cancel', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ reservationId: 'res123', reason: 'Change of plans' }),
})
const updated = await res.json()

GET /api/reserve/customers

Searches customers by name or email. Used internally by the admin CustomerField component. Restricted to admin/staff users — customer-collection users receive 403 Forbidden.

Query parameters:

ParameterRequiredDescription
qYesSearch string (matches name and email)

Response: Array of matching customer documents. Returns 401 if not authenticated, 403 if the user belongs to the customers collection.

On this page