> ## Documentation Index
> Fetch the complete documentation index at: https://developer.zeeg.me/llms.txt
> Use this file to discover all available pages before exploring further.

# Booking Flow

> End-to-end guide for programmatically creating bookings via the Zeeg API — fetch scheduling pages, query available time slots, and create the event.

This guide walks you through the end-to-end flow for programmatically booking an event via the Zeeg API.

<Info>
  The availability and booking endpoints require a **paid Zeeg subscription**. Requests on free plans will be rejected.
</Info>

<Warning>
  **Always verify availability before creating an event.** Attempting to book a slot that is no longer available will result in an error. Check available time slots immediately before creating the event to avoid race conditions.
</Warning>

## End-to-end booking flow

<Steps titleSize="h3">
  <Step title="Get your scheduling page details">
    Retrieve the scheduling page (event type) you want to book against. You need its slug, the owner's slug, any custom invitee questions, and whether a phone number is required.

    List all your scheduling pages:

    ```bash theme={null}
    GET /event-types
    ```

    Or fetch a specific one by UUID:

    ```bash theme={null}
    GET /event-types/{uuid}
    ```

    **Example response** (key fields highlighted):

    ```json theme={null}
    {
      "resource": {
        "uri": "https://api.zeeg.me/v2/event-types/80f46bf5-eb01-4c07-960e-a9a3e18aae5e",
        "uuid": "80f46bf5-eb01-4c07-960e-a9a3e18aae5e",
        "title": "30-Minute Discovery Call",
        "type": "ONE_ON_ONE",
        "slug": "30min-discovery-call",
        "schedulingUrl": "https://zeeg.me/lena-meier/30min-discovery-call",
        "isActive": true,
        "duration": 30,
        "profile": {
          "type": "User",
          "firstName": "Lena",
          "lastName": "Meier",
          "slug": "lena-meier",
          "email": "lena.meier@horizondigital.de"
        },
        "inviteePhoneNumber": false,
        "inviteeQuestions": [
          {
            "id": 1,
            "order": 1,
            "question": "What would you like to discuss?",
            "isActive": true,
            "isRequired": true,
            "type": "TEXT_INPUT",
            "options": null
          }
        ]
      }
    }
    ```

    Take note of:

    * **`slug`** — identifies the event type in subsequent requests (e.g., `30min-discovery-call`).
    * **`profile.slug`** — the owner's slug, used as `ownerSlug` (e.g., `lena-meier`).
    * **`inviteeQuestions`** — custom questions with their numeric `id`s. You will pass answers in step 3 using `question_id`.
    * **`inviteePhoneNumber`** — `true` if a phone number is required, `false` otherwise.
  </Step>

  <Step title="Check available time slots">
    Query the availability endpoint to find open slots for the scheduling page.

    <CodeGroup>
      ```bash cURL theme={null}
      curl -X GET "https://api.zeeg.me/v2/availability/lena-meier/event-types/30min-discovery-call?startDate=2026-04-01&endDate=2026-04-14&timeZone=Europe/Berlin" \
        -H "Authorization: Bearer YOUR_TOKEN" \
        -H "Accept: application/json"
      ```

      ```javascript JavaScript theme={null}
      const response = await fetch(
        "https://api.zeeg.me/v2/availability/lena-meier/event-types/30min-discovery-call?" +
          new URLSearchParams({
            startDate: "2026-04-01",
            endDate: "2026-04-14",
            timeZone: "Europe/Berlin",
          }),
        {
          headers: {
            Authorization: "Bearer YOUR_TOKEN",
            Accept: "application/json",
          },
        }
      );

      const data = await response.json();
      ```

      ```python Python theme={null}
      import requests

      response = requests.get(
          "https://api.zeeg.me/v2/availability/lena-meier/event-types/30min-discovery-call",
          params={
              "startDate": "2026-04-01",
              "endDate": "2026-04-14",
              "timeZone": "Europe/Berlin",
          },
          headers={
              "Authorization": "Bearer YOUR_TOKEN",
              "Accept": "application/json",
          },
      )

      data = response.json()
      ```
    </CodeGroup>

    **Example response:**

    ```json theme={null}
    {
      "ownerSlug": "lena-meier",
      "eventTypeSlug": "30min-discovery-call",
      "schedulingUrl": "https://zeeg.me/lena-meier/30min-discovery-call",
      "duration": 30,
      "firstAvailableDate": "2026-04-01",
      "lastAvailableDate": "2026-04-14",
      "timeZone": "Europe/Berlin",
      "timeZoneOffset": "+02:00",
      "isNotAvailable": false,
      "availability": [
        {
          "date": "2026-04-01",
          "slots": ["09:00", "09:30", "10:00", "10:30", "14:00", "14:30", "15:00"]
        },
        {
          "date": "2026-04-02",
          "slots": ["09:00", "09:30", "10:00", "11:00", "14:00", "15:00"]
        },
        {
          "date": "2026-04-03",
          "slots": []
        }
      ],
      "currentTime": "2026-03-20T12:00:00+00:00"
    }
    ```

    This endpoint requires the **`admin:full`** or **`timetable`** scope.

    <Tip>
      Holding the scheduling page's `uuid` from `GET /event-types`? Call `GET /event-types/{uuid}/availability` with the same query parameters instead. It returns the same response, and it works the same for personal, team and shared scheduling pages.
    </Tip>

    **Shared event types (Round Robin, Flexi, Collective):**

    * Use `shared` as the `ownerSlug` instead of a specific user's slug.
    * A shared scheduling link is addressed the same way: its token is the `eventTypeSlug`.
    * For **Round Robin** events, add `withHostsCount=1` to the query to see how many hosts are available per slot.

    **Additional query parameters:**

    * Add `duration=45` to override the default meeting duration (useful when the scheduling page supports multiple durations).
    * Add `seats=3` to check availability for group event types that support multiple attendees.
  </Step>

  <Step title="Create the event">
    Book a slot by sending a `POST` request to `/event` with the slot details and invitee information.

    <CodeGroup>
      ```bash cURL theme={null}
      curl -X POST "https://api.zeeg.me/v2/event" \
        -H "Authorization: Bearer YOUR_TOKEN" \
        -H "Content-Type: application/json" \
        -H "Accept: application/json" \
        -d '{
          "ownerSlug": "lena-meier",
          "eventTypeSlug": "30min-discovery-call",
          "date": "2026-04-15",
          "start": "09:00",
          "duration": 30,
          "name": "Sophie Laurent",
          "email": "sophie.laurent@northwind.io",
          "timeZone": "Europe/Paris",
          "guests": ["alex.chen@northwind.io"],
          "location": "GOOGLE_MEET",
          "question_answers": [
            { "question_id": 1, "answer": "Product demo and pricing options" }
          ]
        }'
      ```

      ```javascript JavaScript theme={null}
      const response = await fetch("https://api.zeeg.me/v2/event", {
        method: "POST",
        headers: {
          Authorization: "Bearer YOUR_TOKEN",
          "Content-Type": "application/json",
          Accept: "application/json",
        },
        body: JSON.stringify({
          ownerSlug: "lena-meier",
          eventTypeSlug: "30min-discovery-call",
          date: "2026-04-15",
          start: "09:00",
          duration: 30,
          name: "Sophie Laurent",
          email: "sophie.laurent@northwind.io",
          timeZone: "Europe/Paris",
          guests: ["alex.chen@northwind.io"],
          location: "GOOGLE_MEET",
          question_answers: [
            { question_id: 1, answer: "Product demo and pricing options" },
          ],
        }),
      });

      const event = await response.json();
      ```

      ```python Python theme={null}
      import requests

      response = requests.post(
          "https://api.zeeg.me/v2/event",
          headers={
              "Authorization": "Bearer YOUR_TOKEN",
              "Content-Type": "application/json",
              "Accept": "application/json",
          },
          json={
              "ownerSlug": "lena-meier",
              "eventTypeSlug": "30min-discovery-call",
              "date": "2026-04-15",
              "start": "09:00",
              "duration": 30,
              "name": "Sophie Laurent",
              "email": "sophie.laurent@northwind.io",
              "timeZone": "Europe/Paris",
              "guests": ["alex.chen@northwind.io"],
              "location": "GOOGLE_MEET",
              "question_answers": [
                  {"question_id": 1, "answer": "Product demo and pricing options"},
              ],
          },
      )

      event = response.json()
      ```
    </CodeGroup>

    This endpoint requires the **`admin:full`** or **`booking`** scope.

    **Required fields:**

    Send `eventTypeId` (the scheduling page's `uuid` from step 1) in place of `ownerSlug` and `eventTypeSlug` if you prefer. It cannot be combined with them.

    | Field | Description |
    | - | - |
    | `ownerSlug` | The scheduling page owner's slug (from `profile.slug` in step 1) |
    | `eventTypeSlug` | The scheduling page slug (from step 1) |
    | `date` | The date of the slot (from step 2), e.g. `2026-04-01` |
    | `start` | The start time of the slot (from step 2), e.g. `09:00` |
    | `name` | Invitee's full name |
    | `email` | Invitee's email address |
    | `timeZone` | Invitee's time zone, e.g. `Europe/Berlin` |

    **Optional fields:**

    | Field | Description |
    | - | - |
    | `duration` | Duration in minutes, one of the durations the scheduling page offers. Omitted, the booking takes the page's default duration |
    | `phone` | Invitee's phone number (required if `inviteePhoneNumber` is `true` on the scheduling page) |
    | `question_answers` | Array of `{ question_id, answer }` objects matching the `inviteeQuestions` from step 1 |
    | `guests` | Array of additional guest email addresses |
    | `location` | A location type the scheduling page offers, e.g. `ZOOM`, `IN_PERSON`, `PHONE_CALL` or `CUSTOM`. Required when the page offers any location; the API reference lists every type |
    | `locationOptions` | Additional location details (see below) |
    | `utm` | UTM tracking object with keys: `utm_campaign`, `utm_source`, `utm_medium`, `utm_content`, `utm_term` |
    | `customQueryParams` | Custom URL query parameters to attach to the event. Keys must start with `c__` (max 10 fields) |
    | `sharedLink` | Required for shared event types (Round Robin, Flexi, Collective) |

    **Location options:**

    For **`IN_PERSON`** locations, include `locationOptions` with the meeting address:

    ```json theme={null}
    {
      "location": "IN_PERSON",
      "locationOptions": {
        "address": "123 Main St, Berlin, Germany",
        "details": "3rd floor, room 301"
      }
    }
    ```

    For **`PHONE_CALL`** locations, include `locationOptions` with the call type and a phone number:

    ```json theme={null}
    {
      "location": "PHONE_CALL",
      "locationOptions": {
        "callType": "I_WILL_CALL"
      },
      "phone": "+49 170 1234567"
    }
    ```
  </Step>

  <Step title="Verify the booking">
    The response from step 3 contains the created event with all its details.

    **Example response:**

    ```json theme={null}
    {
      "uri": "https://api.zeeg.me/v2/scheduled-events/zg-O69bac566950c6",
      "uuid": "zg-O69bac566950c6",
      "title": "30-Minute Discovery Call",
      "type": "ONE_ON_ONE",
      "startTime": "2026-04-15T07:00:00.000000Z",
      "endTime": "2026-04-15T07:30:00.000000Z",
      "duration": 30,
      "status": "confirmed",
      "eventTypeUri": "https://api.zeeg.me/v2/event-types/80f46bf5-eb01-4c07-960e-a9a3e18aae5e",
      "location": {
        "type": "Google Meet",
        "joinUrl": "https://meet.google.com/abc-defg-hij"
      },
      "invitees": [
        {
          "uuid": "zg-O69bad4047abf0",
          "fullName": "Sophie Laurent",
          "email": "sophie.laurent@northwind.io",
          "timeZone": "Europe/Paris",
          "guests": ["alex.chen@northwind.io"]
        }
      ],
      "hosts": [
        {
          "firstName": "Lena",
          "lastName": "Meier",
          "email": "lena.meier@horizondigital.de",
          "slug": "lena-meier"
        }
      ]
    }
    ```

    To verify the booking at any later point, fetch it by UUID:

    <CodeGroup>
      ```bash cURL theme={null}
      curl -X GET "https://api.zeeg.me/v2/scheduled-events/zg-O69bac566950c6" \
        -H "Authorization: Bearer YOUR_TOKEN" \
        -H "Accept: application/json"
      ```

      ```javascript JavaScript theme={null}
      const response = await fetch(
        "https://api.zeeg.me/v2/scheduled-events/zg-O69bac566950c6",
        {
          headers: {
            Authorization: "Bearer YOUR_TOKEN",
            Accept: "application/json",
          },
        }
      );

      const event = await response.json();
      ```

      ```python Python theme={null}
      import requests

      response = requests.get(
          "https://api.zeeg.me/v2/scheduled-events/zg-O69bac566950c6",
          headers={
              "Authorization": "Bearer YOUR_TOKEN",
              "Accept": "application/json",
          },
      )

      event = response.json()
      ```
    </CodeGroup>
  </Step>
</Steps>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.