List all available sessions (Version 2)

GET /api/availability/v2/sessions

Success: 200 OK

Overview

Lists the bookable sessions for one or more activities, day by day, together with how much space is left in each and the window during which each may be booked. This is the starting point of the booking flow: take a slotReferences value from here, price it with Retrieve pricing information for different members, then create a lease and confirm the booking.

There is no member context, so booking windows are worked out from each site's default price level rather than anyone's membership. Use List all available sessions for a specific member (Version 2) when you know who is booking, because a member's price level can open a slot earlier than the default.

Two things about the shape of the response catch people out. It is flattened by date: one array entry per activity per day, with the day in date, so the same id appears many times and days with no slots are missing rather than empty. And it is ordered by the start time of the first slot, then by name — not grouped by activity or site.

Choosing between version 1 and version 2

Version 2 is the one to build against for anything new. It differs in four ways that matter:

Slot-level data is identical between the versions.

Endpoint

GET {base_url}/api/availability/v2/sessions

{base_url} is the environment URL issued to your integration. See Authenticating with Gladstone APIs.

Query parameters

NameTypeRequiredDescription
activityIdsstringNoComma-separated activity ids to search. Optional in version 2, but at least one of activityIds, tagIds or activityGroupIds must be supplied or the request fails with 400 Either ActivityIds, TagIds, or ActivityGroupIds must be provided. Cannot be combined with tagIds. Any id that does not exist fails the whole request with 400.
tagIdsstringNoComma-separated tag ids, resolved to the activities carrying any of them. Take the ids from tagGroups[].tags[].id on an earlier response. Mutually exclusive with activityIds — sending both fails with 400 Cannot filter by both activity ID and tag ID. Please only use one. Non-numeric entries are silently discarded rather than rejected, so a typo narrows your search instead of erroring. A tag id that does not exist fails with 400.
siteIdsstringNoComma-separated site ids to restrict the search to. At most five; a sixth fails with 400 A maximum of 5 SiteIds can be specified. Omit to search every site the matched activities belong to.
webBookableOnlybooleanNoRestricts the results to activities flagged for online booking. Defaults to true, so by default you see only what a caller could book online — pass false explicitly to include activities that are bookable only at the centre.
dateFromstring (date-time)NoThe first date to return sessions for. Defaults to now (UTC) when omitted, and must not be earlier than today — a past date fails with 400 DateFrom cannot be in the past. Please enter a valid date.
dateTostring (date-time)NoThe last date to return sessions for, inclusive to end of day. New in version 2, and the only way to override the tenant's configured look-ahead period, which is used when you omit it. Must not be in the past, must not be before dateFrom, and must not equal dateFrom — asking for a single day this way fails with 400 DateFrom cannot be the same as DateTo. Please enter a valid date., so use the day after for a one-day window.
locationIdstringNoNarrows the results to one resource product — a single court, lane or room. Take the value from locations[].locationDetails[].locationId on an earlier response. An id that is not a valid resource fails with 400 Invalid location ID: {locationId}.
activityGroupIdsstringNoComma-separated activity group ids, matching activityGroupId in the response — useful for pulling a whole category such as racquet sports. New in version 2. Can be combined with activityIds or tagIds, and counts towards the requirement that at least one of the three filters is supplied.

Sample request

cURL
curl -X GET '{base_url}/api/availability/v2/sessions' \
  -H 'Authorization: Bearer {accessToken}' \
  -H 'X-Use-SSO: true'

Response fields

FieldTypeDescription
[].activityGroupIdstringThe activity group the activity belongs to — the category tenants use to organise their timetable, such as racquet sports. Null when the activity is not in a group.
[].activityGroupDescriptionstringThe display name of that activity group.
[].idstringThe activity these sessions belong to. Because the response is split by date, the same id appears once for every date that has slots — id alone does not identify an array entry, id plus date does.
[].namestringThe activity's short name, suitable for a timetable row.
[].descriptionstringThe activity's long description, for a detail page.
[].datestringThe calendar date the slots in this entry fall on, as yyyy-MM-dd. One entry is produced per activity per date, and dates with no slots are dropped entirely rather than returned empty.
[].imageUrlstringImage for the activity, ready to use as-is. A relative image reference is expanded to a full public CDN URL; a value already beginning http is returned unchanged. Null when the activity has no image.
[].inCentrebooleanWhether the activity can be attended in person. Both this and virtual are true for an activity configured as mixed, so they are not mutually exclusive — check both before deciding which of slotReferences.inCentre and slotReferences.virtual to use.
[].virtualbooleanWhether the activity can be attended remotely. See inCentre — a mixed activity sets both.
[].siteIdstringThe site the activity runs at. Useful when you queried several sites at once, since the array interleaves them.
[].webBookablebooleanWhether the activity is flagged for online booking. With the default webBookableOnly=true this is always true, since anything else has already been filtered out; it is only informative when you pass webBookableOnly=false.
[].webCommentsstringFree-text note the tenant configured for online display against this activity — kit to bring, entry instructions, and so on. Null when none is set.
[].capacityobjectThe activity's configured maximum party sizes. This is the ceiling, not what is left — for remaining space use locations[].slots[].availability.
[].capacity.maxInCentreBookeesinteger (int32)The activity's configured maximum number of in-centre bookees — except when the entry has exactly one slot, in which case it is replaced by that slot's own capacity. Reservations can carry a per-booking capacity, and this is how version 2 surfaces it.
[].capacity.maxVirtualBookeesinteger (int32)The activity's configured maximum number of virtual bookees — except when the entry has exactly one slot, in which case it is replaced by that slot's availability.virtual, which is always 0. Single-slot entries therefore report 0 here regardless of configuration.
[].typeIndstringWhat kind of activity this is, which governs how you book it. One of partyactivity (extra bookees allowed), hostedreservation, activity (a standard bookable resource such as a court), course (a class where all sessions are booked together) or class. Evaluated in that order, so a party activity reports partyactivity regardless of its other flags.
[].slotCountinteger (int32)How many slots this entry contains, counted across every location. Always at least 1: entries that would have no slots on the date are not returned.
[].groupActivityDetailsobjectWhether extra people can be added to a booking of this activity.
[].groupActivityDetails.isGroupActivitybooleantrue when the activity is a party activity, meaning a booking may include additional bookees beyond the member. Only then will Retrieve pricing information for different members accept an additionalBookees list; it rejects them otherwise.
[].groupActivityDetails.priceLevelsarray of objectAlways empty, so do not use this endpoint to discover which price levels a party activity offers — price the slot instead.
[].groupActivityDetails.priceLevels[].idstringNever returned, as the containing array is always empty.
[].groupActivityDetails.priceLevels[].descriptionstringNever returned, as the containing array is always empty.
[].bookingDiscountTypesarray of objectBooking discounts that could apply to this activity on this date. Populated only when the booking discounts feature is enabled for the tenant and a discount's validity period covers the date; null rather than empty otherwise. This tells you a discount exists, not what it is worth — the amount comes from Retrieve pricing information for different members. Not present in version 1.
[].bookingDiscountTypes[].discountTypestringThe name of the configured discount. Values are tenant configuration, so treat this as a label rather than a fixed set. Duplicates are removed.
[].locationsarray of objectWhere the sessions take place. Version 2 groups resources: one entry per combination of resource products that makes up a bookable place, rather than version 1's one entry per individual product. An activity requiring two courts together is one location here with two locationDetails, where version 1 would have shown two locations repeating the same slots.
[].locations[].locationNameToDisplaystringThe name to show for the location. Where several resource products are combined, this is the description of the first of them, not a concatenation — use locationDetails if you need to list them all.
[].locations[].locationDetailsarray of objectThe individual resource products making up this location. A single entry when one product is enough to book the slot; several when the activity requires them together.
[].locations[].locationDetails[].locationIdstringThe resource product identifier. This is the value to pass as the locationId query parameter to narrow a later query to one court or room.
[].locations[].locationDetails[].locationNamestringThe resource product's description, for display.
[].locations[].slotsarray of objectThe bookable occurrences at this location on date, ordered by start time. For a standard activity these are theoretical slots generated from the timetable; for a class they are the class's existing bookings.
[].locations[].slots[].startTimestring (date-time)When the session starts, in UTC. Every slot in an entry starts on the entry's date.
[].locations[].slots[].endTimestring (date-time)When the session ends, in UTC. For a generated activity slot this is one second before the next slot would begin, so expect times such as 10:59:59.
[].locations[].slots[].bookableFromstring (date-time)The earliest moment this slot may be booked, in UTC, seconds trimmed. It comes from the advance booking period that applies to the caller — which for a member query depends on their price level, so the same slot can open earlier for one member than another. With no advance booking period it is simply today. Null is not expected.
[].locations[].slots[].bookableUntilstring (date-time)The latest moment this slot may be booked, in UTC, seconds trimmed, derived from the tenant's booking cut-off configuration relative to the session's start or end. If misconfiguration would put it before bookableFrom, it is clamped to bookableFrom, leaving effectively no booking window.
[].locations[].slots[].isBeforeTimetableSlotBookablePeriodbooleantrue when bookableFrom is still in the future at the moment the response was built — the slot exists and has space, but is not open for booking yet. Show it as "available from" rather than bookable. Note that status can still read Available, so check this flag as well as status.
[].locations[].slots[].availabilityobjectSpaces left on this slot, as opposed to the activity's configured maximum in capacity.
[].locations[].slots[].availability.inCentreinteger (int32)Spaces still free, calculated as the maximum bookees less those already booked. Unexpired booking leases held by other members count as taken, so this can fall without any booking being completed. Forced to 0 when an overlapping booking blocks the slot or the booking cut-off has passed.
[].locations[].slots[].availability.virtualinteger (int32)Always 0. Remaining virtual capacity is not calculated by this endpoint, for either generated or booking-derived slots. Do not read a fully-booked virtual session into this value.
[].locations[].slots[].alertListEnabledbooleanWhether members may join an alert list for this slot when it is full. Only ever true for slots derived from existing bookings — that is, classes and courses. Slots generated from an activity's timetable always report false, even where the activity has a waiting list configured.
[].locations[].slots[].alertListCountinteger (int32)How many members are already queuing on the alert list. 0 on generated activity slots, which never carry alert-list data.
[].locations[].slots[].statusstring (enum)One of: Available, Unavailable.
[].locations[].slots[].slotReferencesobjectThe slot references to quote back when pricing and booking this slot. Pick the member the field matching how they will attend.
[].locations[].slots[].slotReferences.inCentrestringThe reference for attending in person. Null when the activity is virtual-only, so check before using it. It is an opaque JSON string — pass it to pricing and lease creation exactly as received; do not parse or rebuild it.
[].locations[].slots[].slotReferences.virtualstringThe reference for attending remotely. Null when the activity is in-centre only. Treat it as opaque, as with inCentre.
[].locations[].translationsarray of objectTranslated forms of the location name, for tenants running more than one language. Empty when the location has no translations configured.
[].locations[].translations[].typestring
[].locations[].translations[].culturestringThe culture the text belongs to, used to select the variant matching the member's language.
[].locations[].translations[].textstringThe translated text — display this instead of the untranslated name when it matches the member's culture.
[].translationsarray of objectTranslated forms of the activity's own text. Empty when none are configured.
[].translations[].typestring
[].translations[].culturestringThe culture the text belongs to.
[].translations[].textstringThe translated text.
[].activityGroupTranslationsarray of objectTranslated forms of the activity group's text, separate from the activity's own. Empty when none are configured, or when the activity is not in a group.
[].activityGroupTranslations[].typestring
[].activityGroupTranslations[].culturestringThe culture the text belongs to.
[].activityGroupTranslations[].textstringThe translated text.
[].tagGroupsarray of objectThe tags attached to this activity, arranged by the group they belong to — the metadata tenants use to categorise their timetable, such as intensity or suitability. Only in version 2, and the source of the ids you pass to the tagIds query parameter.
[].tagGroups[].idinteger (int32)The tag group's identifier. Note that tagIds filters on tags, not tag groups, so this value cannot be used as a filter.
[].tagGroups[].namestringThe tag group's name, suitable as a heading above its tags.
[].tagGroups[].tagsarray of objectThe tags in this group that are attached to the activity.
[].tagGroups[].tags[].idinteger (int32)The tag's identifier. Pass these, comma-separated, as tagIds to find every activity carrying any of them.
[].tagGroups[].tags[].namestringThe tag's name, for display.
[].tagGroups[].tags[].translationsarray of objectTranslated forms of the tag's name. Empty when none are configured.
[].tagGroups[].tags[].translations[].typestring
[].tagGroups[].tags[].translations[].culturestringThe culture the text belongs to.
[].tagGroups[].tags[].translations[].textstringThe translated text.
[].tagGroups[].translationsarray of objectTranslated forms of the tag group's name, separate from its tags'. Empty when none are configured.
[].tagGroups[].translations[].typestring
[].tagGroups[].translations[].culturestringThe culture the text belongs to.
[].tagGroups[].translations[].textstringThe translated text.

Sample response

200 OK
[
  {
    "activityGroupId": "string",
    "activityGroupDescription": "string",
    "id": "string",
    "name": "string",
    "description": "string",
    "date": "string",
    "imageUrl": "string",
    "inCentre": true,
    "virtual": true,
    "siteId": "string",
    "webBookable": true,
    "webComments": "string",
    "capacity": {
      "maxInCentreBookees": 1,
      "maxVirtualBookees": 1
    },
    "typeInd": "string",
    "slotCount": 1,
    "groupActivityDetails": {
      "isGroupActivity": true,
      "priceLevels": [
        {
          "id": "string",
          "description": "string"
        }
      ]
    },
    "bookingDiscountTypes": [
      {
        "discountType": "string"
      }
    ],
    "locations": [
      {
        "locationNameToDisplay": "string",
        "locationDetails": [
          {
            "locationId": "string",
            "locationName": "string"
          }
        ],
        "slots": [
          {
            "startTime": "2026-08-14T19:00:00Z",
            "endTime": "2026-08-14T19:00:00Z",
            "bookableFrom": "2026-08-14T19:00:00Z",
            "bookableUntil": "2026-08-14T19:00:00Z",
            "isBeforeTimetableSlotBookablePeriod": true,
            "availability": {
              "inCentre": 1,
              "virtual": 1
            },
            "alertListEnabled": true,
            "alertListCount": 1,
            "status": "Available",
            "slotReferences": {
              "inCentre": "string",
              "virtual": "string"
            }
          }
        ],
        "translations": [
          {
            "type": "string",
            "culture": "string",
            "text": "string"
          }
        ]
      }
    ],
    "translations": [
      {
        "type": "string",
        "culture": "string",
        "text": "string"
      }
    ],
    "activityGroupTranslations": [
      {
        "type": "string",
        "culture": "string",
        "text": "string"
      }
    ],
    "tagGroups": [
      {
        "id": 12345,
        "name": "string",
        "tags": [
          {
            "id": 12345,
            "name": "string",
            "translations": [
              {
                "type": "string",
                "culture": "string",
                "text": "string"
              }
            ]
          }
        ],
        "translations": [
          {
            "type": "string",
            "culture": "string",
            "text": "string"
          }
        ]
      }
    ]
  }
]

Errors

StatusMeaningWhen
400Bad requestNone of activityIds, tagIds or activityGroupIds was supplied (Either ActivityIds, TagIds, or ActivityGroupIds must be provided.); both activityIds and tagIds were supplied (Cannot filter by both activity ID and tag ID. Please only use one.); dateFrom is in the past, dateTo is in the past, dateTo is before dateFrom, or dateTo equals dateFrom; locationId is not a valid resource (Invalid location ID: {locationId}); more than five site ids were given (A maximum of 5 SiteIds can be specified); a tag id does not exist (One or more TagIds in the list […] doesn't exist.); or one of the sites or activities you named does not exist.
500Internal server errorAny failure that is not a validation error. The response is a bare 500 with no body, so there is nothing in the response to act on.

This page as markdown · All pages · llms.txt