Skip to main content
Before creating bookings, discover the areas you can sell and read their availability. In 1Club a bookable padel court is an area; store the mapping between your courts and 1Club area ids on your side.

List areas

Returns the organization’s bookable areas. Filter by club or sport to get just the padel courts.
Query parameters:
  • clubId (optional) - only return areas belonging to this club
  • sport (optional) - only return areas whose type lists this sport, for example padel
Response:
Use each area’s id as the areaId when creating a booking. timezone is the IANA zone the gym keeps, and the one operatingHours are expressed in. Convert a local wall time in it when you send startTime and endTime - a booking sent in the wrong zone lands an hour out twice a year, at the daylight-saving boundary, and looks correct the rest of the time. Map it once when you map the courts.

Area availability

Returns everything you need to render a court’s calendar for a window: the club timezone, operating hours, the intervals already taken (busy), and ready-made open slots with remaining capacity.
Query parameters:
  • from (required) - window start, ISO date-time
  • to (required) - window end, ISO date-time, at most 31 days after from
  • slotMinutes (optional) - slot granularity: 15, 30, 60 (default), 90, or 120
Response:
  • timezone - the IANA timezone the operatingHours are expressed in. Operating hours are per-weekday local times; slots are already resolved to absolute UTC instants for you (DST included), so prefer slots over re-deriving from operatingHours.
  • slots - open slots computed from effective bookable hours (club ∩ area) minus busy, honouring maxConcurrentBookings. remaining is how many of capacity are still free; bookable is remaining > 0 and no hard block.
  • busy and operatingHours are still returned raw if you’d rather compute slots yourself. An area with maxConcurrentBookings greater than 1 can hold that many overlapping bookings before a slot is full.
  • busy[].subject - what holds the court for that interval: member_booking, class (a scheduled class holding its court), event, or area_block (the gym closed the court for maintenance or a private hire). Same vocabulary as details.conflicts[].subject on a refused booking, so an hour you cannot sell can be explained rather than shown as unattributed busy time. A class is a booking row underneath, so subject is the only thing that separates it from a customer’s reservation. No id or name is attached - an availability read is not a read of who booked. Use List bookings for the rows you may see.
  • version - a consistency token (the highest change sequence for this area). Compare it to the sequence on an availability webhook to know whether this read already reflects that change.

Conditional requests

The response sends an ETag. Send it back as If-None-Match to get a cheap 304 Not Modified when nothing has changed - useful as a polling fallback where you don’t run webhooks.
Treat the token as opaque. It covers the area’s version, the window you asked for, the slot size, and the shape of the response itself - so it changes when we ship a new field, not only when a court’s availability moves. Store it verbatim against the request that produced it and send it back unmodified; do not parse it or rebuild it from version, or a release that adds a field will leave you on a 304 and the old body.

Club availability grid

Render a whole club’s calendar in one request instead of one call per court.
Query parameters: clubId (optional), sport (optional), from/to (required, ≤ 31 days), slotMinutes (optional).
The top-level cursor is the reconciliation cursor at read time - store it and pass it to the change feed to catch up later.

Availability change feed

Returns every availability change for your organization after a cursor, in order. Pair it with webhooks: webhooks push changes in near real time; this feed lets you catch up exactly after any missed delivery, so your calendar never drifts.
Query parameters: since (required cursor; 0 for the start of retention), limit (optional, default 100, max 500).
To reconcile: pass your last stored cursor, apply each change by re-pulling /availability for the affected area and window, then store the new cursor. Keep paging while hasMore is true.
On first sync you have no cursor - do a full grid pull and start from the cursor it returns (starting from 0 for a live club replays its whole history). The feed serves a rolling history; if your cursor predates it after a long outage, re-baseline with a full grid pull. Some changes (e.g. area.updated) carry a coarse, wide from/to window rather than a single slot - re-pull the whole window. See the webhooks guide for the full reconciliation flow.
Availability is a snapshot. 1Club remains the source of truth: booking creation re-checks availability atomically, so a slot that was open a moment ago may be rejected if it was taken in between. Always handle a booking rejection gracefully - and use webhooks plus this feed to keep the snapshot fresh.

Area blocks

A block takes an area off the bookable schedule for a period: resurfacing, a holiday, a camp. Availability already reflects blocks, so a blocked slot simply won’t appear in slots. Read blocks directly when you want the reason and the period to show in your own calendar, or when migrating a schedule into 1Club. A block with areaId: null is gym-wide: it blocks every area in its clubId. If you key your calendar by court, expand it against that gym’s areas.

List blocks

Requires the areas:read scope.
Query parameters:
  • from (required) - window start, ISO date-time
  • to (required) - window end, at most 31 days after from
  • clubId (optional) - only blocks for this club
  • areaId (optional) - only blocks affecting this area, gym-wide ones included
Any block that overlaps the window is returned, so a week-long block still appears when you ask about one day inside it. Response:

Create a block

Requires the areas:write scope. Send areaId to close one court, and its gym is derived for you. To close a whole gym, send clubId and leave areaId out - one record rather than one per court, and areas added later are covered too.
Body:
  • startTime, endTime (required) - ISO date-times with offset. endTime must be after startTime.
  • areaId (optional) - the court to block. Omit or send null for a gym-wide block.
  • clubId - required when areaId is omitted or null; otherwise derived from the area.
  • note (optional) - up to 500 characters, shown on the gym’s schedule.
Returns 201 with the created block.
A block stops new bookings. Bookings already inside the period are not cancelled, so migrate or cancel those separately if you need the period clear.

Delete a block

Requires the areas:write scope. Deleting a block reopens the period for booking.
Returns { "success": true }. A second delete of the same id returns 404.
Creating or deleting a block emits an availability change for every affected area, so the changes feed and webhooks will tell you to re-pull those courts. A gym-wide block emits one change per area in the gym.