> ## Documentation Index
> Fetch the complete documentation index at: https://docs.1club.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# List bookings

> Returns bookings whose start time falls in the requested window, ordered by start time. Each bound is an ISO date-time, or a bare `YYYY-MM-DD` read as midnight UTC. When `from`/`to` are omitted the window defaults to the next 7 days, and passing one derives the other.

A single request may span at most 93 days. To cover a longer range, walk it in consecutive windows of 93 days or less, paging each window with `limit`/`offset` against the `total` it reports. Ordering is stable (`startTime`, then id), so paging is well defined for a window that is not being written to; bookings created or cancelled mid-walk can still shift rows across page boundaries.

Bookings from every channel are returned, each tagged with `source`. That is deliberate: a caller reconciling its own writes has to be able to see member- and staff-created bookings to know whether a slot was already taken. Whether the writes (cancel, add/remove participant) reach those bookings too depends on the credential: an API key may only mutate the bookings it created (`source: api`), while a staff member acting through an authorized 1club assistant may mutate any of the organization's.

A class booking carries the occurrence it attends as `classId`. Every attendee of a class holds their own booking row against the same `classId`, and `classes` rows are per-occurrence, so that is what tells two groups running in the same hour apart - filter by it, or read the roster from the class side with GET /v1/platform/classes/{id}/bookings.




## OpenAPI

````yaml /openapi-platform.json get /v1/platform/bookings
openapi: 3.0.0
info:
  title: 1club Platform API
  version: 1.0.0
  description: >-
    The 1club Platform API lets you programmatically access and manage your
    organization's data.


    ## Official API Contract


    This documentation is the official source of truth for the 1club Platform
    API.

    If an integration relies on undocumented endpoints, fields, response shapes,
    or internal behavior outside this spec, we can't guarantee backward
    compatibility.

    Build against what's documented here to stay stable as the platform evolves.


    ## Authentication


    All requests require a customer API key passed as a Bearer token:


    ```

    Authorization: Bearer 1club_sk_live_...

    ```


    Generate API keys from the admin portal under **Settings > API Tokens**.

    The key is tied to your organization - all responses are scoped to your
    org's data.


    ## Rate Limiting


    - **100 requests per minute** per API key

    - When exceeded, the API returns `429 Too Many Requests` with a
    `Retry-After` header

    - Rate limit headers are included in every response:
      - `X-RateLimit-Limit` - max requests per window
      - `X-RateLimit-Remaining` - requests remaining
      - `X-RateLimit-Reset` - seconds until the window resets

    ## Errors


    | Status | Meaning |

    |--------|---------|

    | `400` | Invalid request parameters |

    | `401` | Missing or invalid API key |

    | `404` | Resource not found (or doesn't belong to your organization) |

    | `429` | Rate limit exceeded |

    | `500` | Internal server error |
  contact:
    name: 1club API Support
    email: support@1club.ai
servers:
  - url: https://api.1club.ai
    description: Production API
security:
  - customerApiAuth: []
tags: []
paths:
  /v1/platform/bookings:
    get:
      tags:
        - Bookings
      summary: List bookings
      description: >
        Returns bookings whose start time falls in the requested window, ordered
        by start time. Each bound is an ISO date-time, or a bare `YYYY-MM-DD`
        read as midnight UTC. When `from`/`to` are omitted the window defaults
        to the next 7 days, and passing one derives the other.


        A single request may span at most 93 days. To cover a longer range, walk
        it in consecutive windows of 93 days or less, paging each window with
        `limit`/`offset` against the `total` it reports. Ordering is stable
        (`startTime`, then id), so paging is well defined for a window that is
        not being written to; bookings created or cancelled mid-walk can still
        shift rows across page boundaries.


        Bookings from every channel are returned, each tagged with `source`.
        That is deliberate: a caller reconciling its own writes has to be able
        to see member- and staff-created bookings to know whether a slot was
        already taken. Whether the writes (cancel, add/remove participant) reach
        those bookings too depends on the credential: an API key may only mutate
        the bookings it created (`source: api`), while a staff member acting
        through an authorized 1club assistant may mutate any of the
        organization's.


        A class booking carries the occurrence it attends as `classId`. Every
        attendee of a class holds their own booking row against the same
        `classId`, and `classes` rows are per-occurrence, so that is what tells
        two groups running in the same hour apart - filter by it, or read the
        roster from the class side with GET /v1/platform/classes/{id}/bookings.
      parameters:
        - in: query
          name: from
          schema:
            type: string
          description: >-
            Inclusive lower bound on booking start time, as an ISO date-time or
            `YYYY-MM-DD`. Defaults to `to - 7d`, or now.
        - in: query
          name: to
          schema:
            type: string
          description: >-
            Exclusive upper bound on booking start time, as an ISO date-time or
            `YYYY-MM-DD`. Defaults to `from + 7d`.
        - in: query
          name: clubId
          schema:
            type: integer
          description: Only bookings at this club
        - in: query
          name: areaId
          schema:
            type: integer
          description: Only bookings on this area
        - in: query
          name: classId
          schema:
            type: integer
          description: >
            Only the attendees of this class occurrence. Equivalent to GET
            /v1/platform/classes/{id}/bookings, which additionally resolves each
            attendee's name and check-in.
        - in: query
          name: eventId
          schema:
            type: integer
          description: Only bookings for this event
        - in: query
          name: instructorId
          schema:
            type: integer
          description: Only bookings led by this instructor
        - in: query
          name: contactId
          schema:
            type: integer
          description: Only bookings for this contact
        - in: query
          name: status
          schema:
            type: string
          description: Only bookings with this status (e.g. confirmed, pending, cancelled)
        - in: query
          name: include
          schema:
            type: string
            enum:
              - customer
          description: >
            Embed each booking's customer as `customer`, identical to what GET
            /v1/platform/contacts/{id} returns - one request instead of a
            contact lookup per booking. Requires the `contacts:read` scope in
            addition to `bookings:read`, and is refused with 403 without it.
        - in: query
          name: limit
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 50
          description: Maximum number of bookings to return
        - in: query
          name: offset
          schema:
            type: integer
            minimum: 0
            default: 0
          description: Number of bookings to skip
      responses:
        '200':
          description: Page of bookings
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlatformBookingPage'
        '400':
          $ref: '#/components/responses/PlatformBadRequest'
        '401':
          $ref: '#/components/responses/PlatformUnauthorized'
        '403':
          description: >-
            API key is missing the required `bookings:read` scope, or
            `include=customer` was sent without `contacts:read`
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlatformError'
        '429':
          $ref: '#/components/responses/PlatformRateLimited'
      security:
        - customerApiAuth: []
components:
  schemas:
    PlatformBookingPage:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/PlatformBookingListItem'
        total:
          type: integer
          description: Total bookings matching the filters, ignoring pagination
        limit:
          type: integer
        offset:
          type: integer
    PlatformError:
      type: object
      properties:
        error:
          type: string
    PlatformBookingListItem:
      allOf:
        - $ref: '#/components/schemas/PlatformBooking'
        - type: object
          properties:
            clubId:
              type: integer
              nullable: true
            source:
              type: string
              nullable: true
              description: >-
                Channel that created the booking (api, admin, portal, app,
                kiosk, network, website, integration).
            notes:
              type: string
              nullable: true
            createdAt:
              type: string
              format: date-time
    PlatformBooking:
      type: object
      description: >-
        A booking created through the platform API. Recorded with a booking
        transaction so it counts for revenue, marked paid (settled against the
        External / API payment method) or unpaid (outstanding) per the caller.
        Refunds and collection stay with the caller.
      properties:
        bookingId:
          type: integer
          description: 1club booking id
        bookingUuid:
          type: string
          format: uuid
          description: >-
            Stable unguessable identifier. Prefer this over `bookingId` when
            storing a reference.
        status:
          type: string
          description: Booking status (e.g. confirmed, cancelled)
        areaId:
          type: integer
          nullable: true
          description: Area id
        classId:
          type: integer
          nullable: true
          description: >-
            The class occurrence this booking attends, when it is a class
            booking. Every attendee holds their own booking row against the same
            `classId`, and `classes` rows are per-occurrence - so this is what
            tells two classes running in the same hour apart. Join it against
            GET /v1/platform/classes, or read the roster with GET
            /v1/platform/classes/{id}/bookings.
        eventId:
          type: integer
          nullable: true
          description: The event this booking attends, when it is an event booking
        instructorId:
          type: integer
          nullable: true
          description: Instructor leading the session, when one is attached
        contactId:
          type: integer
          nullable: true
          description: Contact the booking is for
        startTime:
          type: string
          format: date-time
        endTime:
          type: string
          format: date-time
        customer:
          allOf:
            - $ref: '#/components/schemas/PlatformContact'
          nullable: true
          description: >-
            The booking's customer, identical to what GET
            /v1/platform/contacts/{id} returns. Present only when the request
            passes `include=customer`, which additionally requires the
            `contacts:read` scope; `null` when the booking has no contact. Use
            it to import a window of bookings without a contact lookup per row.
        payment:
          type: object
          properties:
            status:
              type: string
              enum:
                - paid
                - unpaid
                - no_charge
              description: >-
                `no_charge` means there is nothing to collect: either nothing
                was ever owed (a free area, an amount of 0) or an entitlement
                covers it - a membership or external program the attendee
                already holds, which is why a covered booking can carry a price
                and still owe nothing. `paid` counts every financially closed
                transaction status (`paid`, `settled`, `refunded`), and every
                charge type, not only the one this API records.
            amount:
              type: number
              nullable: true
              description: >-
                The booking's recorded price in the organization's currency;
                `status` is what says whether anything was collectable. Where
                the price is 0 but a real charge exists - an external program's
                per-visit fee lives entirely in its transaction - the ledger
                total is reported instead.
    PlatformContact:
      type: object
      description: >-
        A contact (customer) in the organization. Reference the `id` as
        `contactId` when creating a booking.
      properties:
        id:
          type: integer
        uuid:
          type: string
          format: uuid
          description: >-
            Stable unguessable identifier. Prefer this over `id` when storing a
            reference.
        name:
          type: string
        firstName:
          type: string
        lastName:
          type: string
          nullable: true
        email:
          type: string
          nullable: true
        phone:
          type: string
          nullable: true
        type:
          type: string
          nullable: true
          description: Derived contact type (e.g. contact, member, lead).
        createdAt:
          type: string
          format: date-time
  responses:
    PlatformBadRequest:
      description: Invalid request (bad parameters, or a body that fails validation)
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/PlatformError'
    PlatformUnauthorized:
      description: Invalid or missing API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/PlatformError'
    PlatformRateLimited:
      description: Rate limit exceeded
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/PlatformError'
  securitySchemes:
    customerApiAuth:
      type: http
      scheme: bearer
      description: >-
        Organization-scoped bearer credential: a customer API key
        (1club_sk_live_...) or an MCP OAuth access token.

````