Skip to main content

Waitlist

Join a waitlist when a desired time slot is unavailable. The system automatically offers slots when they become available.

Overview

The waitlist system allows members to:

  • Queue for fully-booked time slots
  • Receive automatic offers when slots open (cancellations, reschedules)
  • Accept offers within a configurable time window
  • Track position and priority in the queue

Waitlist Entry Model

FieldTypeDescription
idstringUnique identifier
tenantIdstringTenant scope
clubIdstringClub scope
resourceIdstringTarget resource
memberIdstringRequesting member
desiredStartDateTimeDesired start time
desiredEndDateTimeDesired end time
priorityScorenumberPriority ordering (higher = first offered)
statusWaitlistStatusCurrent status
offeredAtDateTimeWhen slot was offered
offerExpiresAtDateTimeDeadline to accept offer
acceptedAtDateTimeWhen offer was accepted
cancelledAtDateTimeWhen entry was cancelled

Waitlist Status

StatusDescription
ACTIVEWaiting for a slot to open
OFFEREDSlot offered, awaiting acceptance
ACCEPTEDOffer accepted, reservation created
EXPIREDOffer expired, entry returned to queue or closed
CANCELLEDManually cancelled by member or admin

REST API

List Waitlist Entries

GET /facility-waitlist?tenantId=1&clubId=10&resourceId=42&status=ACTIVE

Query Parameters:

  • tenantId (required) - Tenant scope
  • clubId (optional) - Club scope
  • resourceId (optional) - Filter by resource
  • memberId (optional) - Filter by member
  • status (optional) - Filter by status
  • desiredFrom (optional) - Filter by desired start time
  • desiredTo (optional) - Filter by desired end time

Join Waitlist

POST /facility-waitlist
Content-Type: application/json

{
"tenantId": "t-1",
"clubId": "c-1",
"resourceId": "r-42",
"memberId": "m-9",
"desiredStart": "2026-01-15T10:00:00Z",
"desiredEnd": "2026-01-15T11:00:00Z"
}

Response:

{
"id": "wl-123",
"tenantId": "t-1",
"clubId": "c-1",
"resourceId": "r-42",
"memberId": "m-9",
"desiredStart": "2026-01-15T10:00:00Z",
"desiredEnd": "2026-01-15T11:00:00Z",
"priorityScore": 100,
"status": "ACTIVE",
"createdAt": "2026-01-14T08:30:00Z"
}

Cancel Waitlist Entry

POST /facility-waitlist/:id/cancel?tenantId=1&clubId=10
Content-Type: application/json

{
"reason": "No longer needed"
}

Accept Offered Slot

When a slot is offered, accept it to create a reservation:

POST /facility-waitlist/:id/accept?tenantId=1&clubId=10

Response includes the created reservation:

{
"waitlistEntry": {
"id": "wl-123",
"status": "ACCEPTED",
"acceptedAt": "2026-01-14T09:15:00Z"
},
"reservation": {
"id": "res-456",
"resourceId": "r-42",
"memberId": "m-9",
"startTime": "2026-01-15T10:00:00Z",
"endTime": "2026-01-15T11:00:00Z",
"status": "ACTIVE"
}
}

Decline Offered Slot

Decline to return to the queue or remove from waitlist:

POST /facility-waitlist/:id/decline?tenantId=1&clubId=10

Admin Operations

Offer Slot Manually

Admins can manually offer a slot:

POST /facility-waitlist/:id/offer?tenantId=1&clubId=10
Content-Type: application/json

{
"offerExpiresAt": "2026-01-14T10:00:00Z"
}

Expire Offer

Mark an offer as expired (automated by scheduler):

POST /facility-waitlist/:id/expire?tenantId=1&clubId=10

GraphQL API

Query Waitlist

query FacilityWaitlist {
facilityWaitlist(filters: {
tenantId: "t-1"
resourceId: "r-42"
status: ACTIVE
}) {
id
memberId
desiredStart
desiredEnd
priorityScore
status
createdAt
}
}

Join Waitlist

mutation JoinWaitlist {
createFacilityWaitlistEntry(data: {
tenantId: "t-1"
clubId: "c-1"
resourceId: "r-42"
memberId: "m-9"
desiredStart: "2026-01-15T10:00:00Z"
desiredEnd: "2026-01-15T11:00:00Z"
}) {
id
priorityScore
status
}
}

Accept Offer

mutation AcceptWaitlistOffer {
acceptFacilityWaitlistEntry(id: "wl-123", tenantId: "t-1", clubId: "c-1") {
waitlistEntry {
id
status
acceptedAt
}
reservation {
id
startTime
endTime
}
}
}

Auto-Offer Workflow

When a reservation is cancelled or rescheduled:

  1. System identifies waitlist entries matching the freed slot
  2. Entries are sorted by priorityScore (highest first)
  3. Top entry receives an offer with offerExpiresAt (default: 1 hour)
  4. If accepted → reservation created, entry marked ACCEPTED
  5. If expired → entry marked EXPIRED or returned to queue
  6. If declined → next entry receives offer
┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│ Cancellation │────▶│ Find Matching │────▶│ Offer to Top │
│ or Reschedule │ │ Waitlist Entry │ │ Priority Entry │
└─────────────────┘ └─────────────────┘ └────────┬────────┘

┌───────────────────────────────┴───────────────────────────────┐
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Accepted │ │ Expired │ │ Declined │
│ │ │ │ │ │
│ Create │ │ Offer Next │ │ Offer Next │
│ Reservation│ │ or Close │ │ Entry │
└─────────────┘ └─────────────┘ └─────────────┘

Priority Scoring

Default priority calculation:

priorityScore = basePriority + memberTierBonus + earlyBirdBonus

Where:

  • basePriority = 100 (default)
  • memberTierBonus = 0-50 based on membership tier
  • earlyBirdBonus = points for joining waitlist early

Higher scores are offered first. Priority can be customized via the rules provider.

Notifications

When offers are made:

  • Email: Slot availability notification with accept/decline links
  • Push: Mobile push notification with deep link
  • SMS: Optional SMS for high-priority offers

Configure notification preferences in member settings.