Skip to main content

Facility Hours

Configure operating hours for facility resources. Hours determine when resources are available for booking.

Last updated: 2026-01-26 Where to find it: Facilities API > Hours Who can use it: Developers, integrators Prerequisites: API credentials Help link: /facility-hours

Overview

Facility hours define weekly operating schedules. Hours can be configured at:

  • Resource type level - Default hours for all resources of a type
  • Resource level - Override for a specific resource

The availability service integrates hours into its calculations, blocking reservations outside operating hours.

Hours Properties

FieldTypeDescription
tenantIdstringRequired - Tenant scope
clubIdstringOptional - Club scope
resourceIdstringOptional - Specific resource override
resourceTypeResourceTypeOptional - Hours for a resource type
dayOfWeeknumber0-6 (Sunday=0, Monday=1, ... Saturday=6)
opensAtMinutesnumberMinutes since midnight (e.g., 360 = 6:00 AM)
closesAtMinutesnumberMinutes since midnight (e.g., 1320 = 10:00 PM)
timeZonestringIANA time zone (e.g., "Africa/Johannesburg")

REST API

List Hours

GET /facility-hours?tenantId=1&clubId=10&resourceType=TENNIS_COURT

Query Parameters:

  • tenantId (required) - Tenant scope
  • clubId (optional) - Filter by club
  • resourceType (optional) - Filter by resource type
  • resourceId (optional) - Filter by specific resource
  • dayOfWeek (optional) - Filter by day (0-6)

Create or Update Hours (Upsert)

Hours are upserted by unique combination of (tenantId, clubId, resourceType/resourceId, dayOfWeek):

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

{
"tenantId": "t-1",
"clubId": "c-1",
"resourceType": "TENNIS_COURT",
"dayOfWeek": 1,
"opensAtMinutes": 360,
"closesAtMinutes": 1320,
"timeZone": "Africa/Johannesburg"
}

Bulk Create Hours

Set hours for all days in one request:

POST /facility-hours/bulk
Content-Type: application/json

{
"tenantId": "t-1",
"clubId": "c-1",
"resourceType": "TENNIS_COURT",
"timeZone": "Africa/Johannesburg",
"hours": [
{ "dayOfWeek": 0, "opensAtMinutes": 420, "closesAtMinutes": 1200 },
{ "dayOfWeek": 1, "opensAtMinutes": 360, "closesAtMinutes": 1320 },
{ "dayOfWeek": 2, "opensAtMinutes": 360, "closesAtMinutes": 1320 },
{ "dayOfWeek": 3, "opensAtMinutes": 360, "closesAtMinutes": 1320 },
{ "dayOfWeek": 4, "opensAtMinutes": 360, "closesAtMinutes": 1320 },
{ "dayOfWeek": 5, "opensAtMinutes": 360, "closesAtMinutes": 1320 },
{ "dayOfWeek": 6, "opensAtMinutes": 420, "closesAtMinutes": 1200 }
]
}

Delete Hours

DELETE /facility-hours/:id?tenantId=1

GraphQL API

Query Hours

query FacilityHours {
facilityHours(filters: {
tenantId: "t-1"
clubId: "c-1"
resourceType: TENNIS_COURT
}) {
id
dayOfWeek
opensAtMinutes
closesAtMinutes
timeZone
}
}

Create Hours

mutation CreateFacilityHours {
createFacilityHours(data: {
tenantId: "t-1"
clubId: "c-1"
resourceType: TENNIS_COURT
dayOfWeek: 1
opensAtMinutes: 360
closesAtMinutes: 1320
timeZone: "Africa/Johannesburg"
}) {
id
dayOfWeek
}
}

Time Conversion

Convert times to minutes since midnight:

TimeMinutes
5:00 AM300
6:00 AM360
7:00 AM420
8:00 AM480
9:00 PM1260
10:00 PM1320
11:00 PM1380

Formula: hours * 60 + minutes

Example Configurations

Tennis Courts (6 AM - 10 PM weekdays, 7 AM - 8 PM weekends)

[
{ "dayOfWeek": 0, "opensAtMinutes": 420, "closesAtMinutes": 1200 },
{ "dayOfWeek": 1, "opensAtMinutes": 360, "closesAtMinutes": 1320 },
{ "dayOfWeek": 2, "opensAtMinutes": 360, "closesAtMinutes": 1320 },
{ "dayOfWeek": 3, "opensAtMinutes": 360, "closesAtMinutes": 1320 },
{ "dayOfWeek": 4, "opensAtMinutes": 360, "closesAtMinutes": 1320 },
{ "dayOfWeek": 5, "opensAtMinutes": 360, "closesAtMinutes": 1320 },
{ "dayOfWeek": 6, "opensAtMinutes": 420, "closesAtMinutes": 1200 }
]

Gym (5 AM - 10 PM weekdays, 6 AM - 8 PM weekends)

[
{ "dayOfWeek": 0, "opensAtMinutes": 360, "closesAtMinutes": 1200 },
{ "dayOfWeek": 1, "opensAtMinutes": 300, "closesAtMinutes": 1320 },
{ "dayOfWeek": 2, "opensAtMinutes": 300, "closesAtMinutes": 1320 },
{ "dayOfWeek": 3, "opensAtMinutes": 300, "closesAtMinutes": 1320 },
{ "dayOfWeek": 4, "opensAtMinutes": 300, "closesAtMinutes": 1320 },
{ "dayOfWeek": 5, "opensAtMinutes": 300, "closesAtMinutes": 1320 },
{ "dayOfWeek": 6, "opensAtMinutes": 360, "closesAtMinutes": 1200 }
]

Blackout Periods

For temporary closures (maintenance, events, holidays), use blackout periods instead of modifying hours.

Create Blackout

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

{
"tenantId": "t-1",
"clubId": "c-1",
"resourceId": "r-42",
"startTime": "2026-01-20T08:00:00Z",
"endTime": "2026-01-20T12:00:00Z",
"reason": "Scheduled maintenance - filter cleaning"
}

Blackouts can be scoped to:

  • A specific resource (resourceId)
  • All resources of a type (resourceType)
  • All resources at a club (neither resourceId nor resourceType)

List Blackouts

GET /facility-blackouts?tenantId=1&clubId=10&startFrom=2026-01-01T00:00:00Z

Delete Blackout

DELETE /facility-blackouts/:id?tenantId=1

Hours Precedence

When checking availability:

  1. Resource-specific hours (if defined for the resource)
  2. Resource type hours (if defined for the type at club level)
  3. Tenant-level type hours (if defined at tenant level)
  4. No restriction (if no hours are defined)

If hours are defined, reservations outside operating hours are rejected.

Expected outcome

  • Operating hours are configured per resource type.
  • Blackouts handle temporary closures.
  • Availability respects configured hours.