List all member participation records

GET /api/participation

Success: 200 OK

Overview

Returns a paged, cross-site record of member attendance at your sites in a date range: the classes and other booked activities members were marked as attending, their entry swipes, and the sales that count as participation.

A participation record is one occurrence of a member using the operator's facilities. The endpoint merges three separate sources into a single stream, and the type field tells you which one produced each record:

Each record carries the member, the site, a timestamp and exactly one populated block inside details matching its type. This is the endpoint to poll when you are building attendance reporting, usage analytics or a data warehouse feed — it is a bulk export shaped for reading, not a per-member lookup, and there is no member filter.

Scope and paging are the two things to get right. You must name between one and five sites; each of the three sources has its own cursor, which is why the continuation token carries three ids at once. Do not construct that token yourself — take links.next from the previous response and call it verbatim. Note that links.next is returned on every response, including the last one, so it is not a signal that more data exists: stop when data comes back empty.

Watch the interaction between limit and the three sources. The limit you send is divided by three, so each source returns at most a third of it. A limit of 100 yields at most 33 bookings, 33 swipes and 33 product sales, and records are grouped by source within the page rather than sorted by time — sort client-side if order matters to you.

Endpoint

GET {base_url}/api/participation

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

Query parameters

NameTypeRequiredDescription
siteIdsstringYesComma-separated list of site ids to report on, for example siteIds=SITE1,SITE2. Despite being a query parameter it is not optional: omitting it, or naming more than five sites, fails with At least one but no more than 5 siteIds can be specified. Every id must exist or the whole call fails with 404.
fromDatestring (date-time)NoInclusive lower bound on the record time — booking start time, swipe time or invoice date depending on the record. Defaults to midnight at the start of the current UTC day when omitted, so leaving it out gives you today only, not everything.
toDatestring (date-time)NoInclusive upper bound on the record time. Defaults to 23:59:59 on the current UTC day. If you pass a value with a zero time component, it is moved to 23:59:59 on that day, so a date-only toDate always covers the whole day. Must not be earlier than fromDate.
continuation-tokenstringNoCursor for the next page. Omit it on the first call; afterwards take the whole links.next URL from the previous response rather than assembling this yourself. It carries three cursors at once in the form attendance-id:{n}_invoice-id:{n}_swipe-id:{n} — underscore-separated key:value pairs whose values must be integers. Any element that is not a key:value pair, or whose value will not convert to an integer, fails with 400. Unrecognised keys are ignored silently, which will quietly restart that source from the beginning.
limitinteger (int32)NoMaximum records per page, defaulting to 100. The value is divided by three, so each of the three sources returns at most a third of it and a page rarely holds exactly limit records. Your original value, not the divided one, is echoed into links.next.
attendedBookingsOnlybooleanNoWhether to restrict the booking source to places actually marked as attended. Defaults to true, which is why bookings a member did not turn up to are missing unless you send false. Has no effect on swipes or product sales.

Sample request

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

Response fields

FieldTypeDescription
dataarray of objectThe page of participation records, mixed across all three sources. Records are grouped by source — product sales, then swipes, then bookings — not sorted by time. An empty array means you have reached the end of the range.
data[].memberIdinteger (int32)The member this record belongs to — the member whose attendance, swipe or sale line this is. There is no way to filter the feed by member; filter client-side.
data[].siteIdstringThe site the participation happened at — one of the ids you passed in siteIds. For bookings this is the site of the booked activity; for swipes, the site of the entry point; for product sales, the site the sale was recorded against.
data[].timestring (date-time)When the participation happened. The meaning follows type: the booking's start time for Booking, the swipe timestamp for Swipe, and the date the invoice was raised for ProductSale. Records are not returned in time order.
data[].typestringWhich source produced this record, and therefore which block of details is populated. One of Booking, Swipe or ProductSale.
data[].detailsobjectHolds the source-specific payload. Exactly one of swipe, booking and productSale is populated, matching type; the other two are absent. Switch on type rather than probing for whichever key is present.
data[].details.swipeobjectPopulated when type is Swipe. A swipe carries no activity or price information — it records only that the member passed through an entry point at time.
data[].details.swipe.entryPointIdstringThe id of the entry point — the turnstile, door or reader — the member was admitted through, as configured in access control.
data[].details.bookingobjectPopulated when type is Booking. Describes the member's place on a booked activity, plus the activity's own configuration at the time of reading.
data[].details.booking.activityIdstringThe id of the booked activity. Records sharing an activityId describe the same activity, so this is the key to group or join on.
data[].details.booking.activityNamestringThe activity's description in the system's base language. Use translations for other languages.
data[].details.booking.attendedbooleanWhether the member was marked as having attended. This is always true unless you called with attendedBookingsOnly=false, which is the only way unattended places enter the feed.
data[].details.booking.locationGroupIdstringThe id of the activity group the activity belongs to — the operator's grouping of related activities, not a physical place. For the physical resources see locations.
data[].details.booking.startTimestring (date-time)The booked activity's start time. Identical to the record's time for booking records.
data[].details.booking.endTimestring (date-time)The booked activity's end time.
data[].details.booking.locationsarray of objectThe resources the activity is made up of — courts, rooms, lanes and similar. These come from the activity's configuration, so every booking of the same activity reports the same list; it is not a per-booking allocation. Empty when the activity has no resources configured.
data[].details.booking.locations[].idstringThe id of the resource.
data[].details.booking.locations[].namestringThe resource's description in the system's base language.
data[].details.booking.locations[].translationsarray of objectTranslated forms of the resource's name, one entry per configured culture. Empty when none are configured.
data[].details.booking.locations[].translations[].typestring
data[].details.booking.locations[].translations[].culturestringThe culture code this translation is for, matching the codes configured for the operator — for example en-GB or cy-GB.
data[].details.booking.locations[].translations[].textstringThe translated resource name for that culture.
data[].details.booking.capacityobjectThe activity's maximum places, split by delivery mode. This is capacity, not how many were taken.
data[].details.booking.capacity.inCentreinteger (int32)Maximum in-centre places: the booking's own limit where one is set, otherwise the activity's. 0 when the activity is virtual-only, in which case there are no in-centre places at all.
data[].details.booking.capacity.virtualinteger (int32)Maximum virtual places. 0 when the activity is in-centre only.
data[].details.booking.inCentrebooleanWhether the activity can be attended in person. true for in-centre and mixed activities, false only for virtual-only ones. Mixed activities report true for both inCentre and virtual.
data[].details.booking.virtualbooleanWhether the activity can be attended remotely. true for virtual and mixed activities, false only for in-centre-only ones.
data[].details.booking.bookingIdinteger (int32)The id of the booking this place belongs to. Several participation records can share one bookingId when a booking covers more than one member.
data[].details.booking.usageinteger (int32)How many people this single record should count as when you total participation. Normally 1, but for activities configured as party bookings it is the party size, so one record can represent a whole group. Sum this rather than counting records.
data[].details.booking.translationsarray of objectTranslated forms of activityName, one entry per configured culture. Empty when none are configured.
data[].details.booking.translations[].typestring
data[].details.booking.translations[].culturestringThe culture code this translation is for, matching the codes configured for the operator — for example en-GB or cy-GB.
data[].details.booking.translations[].textstringThe translated activity name for that culture — display this in place of activityName.
data[].details.productSaleobjectPopulated when type is ProductSale. Describes a sold line that counts as participation — typically a casual entry or an item sold against a booking — taken from the invoice raised for the member.
data[].details.productSale.productIdstringThe id of the product sold.
data[].details.productSale.productNamestringThe product's description in the system's base language.
data[].details.productSale.quantitynumber (double)How many units were sold on this line. Decimal, so fractional quantities are possible. This is a sales quantity, not a participation count — for participation use usage.
data[].details.productSale.usageinteger (int32)How many people this sale should count as when totalling participation. Falls back to 1 when the product has no usage configured against it.
data[].details.productSale.translationsarray of objectTranslated forms of productName, one entry per configured culture. Empty when none are configured.
data[].details.productSale.translations[].typestring
data[].details.productSale.translations[].culturestringThe culture code this translation is for, matching the codes configured for the operator — for example en-GB or cy-GB.
data[].details.productSale.translations[].textstringThe translated product name for that culture.
linksobjectPaging links for this response.
links.nextstringA ready-made absolute URL for the next page, with your siteIds, dates, attendedBookingsOnly, original limit and the advanced continuation token already applied. Call it as-is. Two traps: it is present on every response, including the last, so it does not mean more data exists — stop when data is empty; and the dates in it are rewritten as yyyy-MM-dd, so any time component you originally sent is dropped from page two onwards.

Sample response

200 OK
{
  "data": [
    {
      "memberId": 12345,
      "siteId": "string",
      "time": "2026-08-14T19:00:00Z",
      "type": "string",
      "details": {
        "swipe": {
          "entryPointId": "string"
        },
        "booking": {
          "activityId": "string",
          "activityName": "string",
          "attended": true,
          "locationGroupId": "string",
          "startTime": "2026-08-14T19:00:00Z",
          "endTime": "2026-08-14T19:00:00Z",
          "locations": [
            {
              "id": "string",
              "name": "string",
              "translations": [
                {
                  "type": "string",
                  "culture": "string",
                  "text": "string"
                }
              ]
            }
          ],
          "capacity": {
            "inCentre": 1,
            "virtual": 1
          },
          "inCentre": true,
          "virtual": true,
          "bookingId": 12345,
          "usage": 1,
          "translations": [
            {
              "type": "string",
              "culture": "string",
              "text": "string"
            }
          ]
        },
        "productSale": {
          "productId": "string",
          "productName": "string",
          "quantity": 10.5,
          "usage": 1,
          "translations": [
            {
              "type": "string",
              "culture": "string",
              "text": "string"
            }
          ]
        }
      }
    }
  ],
  "links": {
    "next": "string"
  }
}

Errors

StatusMeaningWhen
400Bad requestOne of: The from date can not be after the to date; At least one but no more than 5 siteIds can be specified (also raised when siteIds is missing entirely); Invalid element "{element}" in token "{token}" when a continuation token segment is not a key:value pair; or Invalid value "{value}" for token value "{key}" when a token value is not an integer.
404Not foundOne or more site Ids do not exist: {siteIds} — every id in siteIds is checked before any records are returned, and one unknown id fails the whole call rather than being skipped. The message lists the ids you sent, not the offending one.
500Internal server errorAn unexpected server-side failure. Also returned, with an empty body, when the request does not arrive through your issued base URL — the endpoint needs that route to build links.next, so calling it by any other address produces this.

This page as markdown · All pages · llms.txt