> ## 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>
  ### 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.

  ### 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.

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

  * Use `shared` as the `ownerSlug` instead of a specific user's slug.
  * 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.

  **Shared links:**
  If you have a shared scheduling link, you can use the alternative endpoint:

  ```bash theme={null}
  GET /availability-by-shared-link/{sharedLink}?startDate=2026-04-01&endDate=2026-04-14&timeZone=Europe/Berlin
  ```

  ### 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:**

  | 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`           |
  | `duration`      | Duration in minutes (must match the event type duration)         |
  | `name`          | Invitee's full name                                              |
  | `email`         | Invitee's email address                                          |
  | `timeZone`      | Invitee's time zone, e.g. `Europe/Berlin`                        |

  **Optional fields:**

  | Field               | Description                                                                                          |
  | ------------------- | ---------------------------------------------------------------------------------------------------- |
  | `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`          | Location type: `GOOGLE_MEET`, `ZOOM`, `MICROSOFT_TEAMS`, `IN_PERSON`, `PHONE_CALL`                   |
  | `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"
  }
  ```

  ### 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>
</Steps>
