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

# Bookings

> Create, manage, cancel, and reschedule appointments

Bookings (appointments) represent scheduled meetings between hosts and attendees. Each booking links a meeting type to a specific time slot.

## Booking Lifecycle

```mermaid theme={null}
stateDiagram-v2
    [*] --> Created: POST /v4/booking
    Created --> Confirmed: Email confirmed (if double opt-in)
    Created --> Rescheduled: Attendee/Host reschedules
    Created --> Cancelled: Attendee/Host cancels
    Rescheduled --> Cancelled
    Confirmed --> Rescheduled
    Confirmed --> Cancelled
    Cancelled --> [*]
```

## Create a Booking

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.meetergo.com/v4/booking" \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "meetingTypeId": "770e8400-e29b-41d4-a716-446655440002",
      "start": "2024-01-15T09:00:00+01:00",
      "hostIds": ["550e8400-e29b-41d4-a716-446655440000"],
      "attendee": {
        "email": "customer@example.com",
        "firstname": "Jane",
        "lastname": "Doe",
        "receiveReminders": true,
        "notes": {}
      }
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://api.meetergo.com/v4/booking', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      meetingTypeId: '770e8400-e29b-41d4-a716-446655440002',
      start: '2024-01-15T09:00:00+01:00',
      hostIds: ['550e8400-e29b-41d4-a716-446655440000'],
      attendee: {
        email: 'customer@example.com',
        firstname: 'Jane',
        lastname: 'Doe',
        receiveReminders: true,
        notes: {}
      }
    })
  });
  ```

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

  response = requests.post(
      'https://api.meetergo.com/v4/booking',
      headers={
          'Authorization': 'Bearer YOUR_API_KEY',
          'Content-Type': 'application/json'
      },
      json={
          'meetingTypeId': '770e8400-e29b-41d4-a716-446655440002',
          'start': '2024-01-15T09:00:00+01:00',
          'hostIds': ['550e8400-e29b-41d4-a716-446655440000'],
          'attendee': {
              'email': 'customer@example.com',
              'firstname': 'Jane',
              'lastname': 'Doe',
              'receiveReminders': True,
              'notes': {}
          }
      }
  )
  ```
</CodeGroup>

### Request Body

| Field               | Type      | Required | Description                                                                                                                                  |
| ------------------- | --------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `meetingTypeId`     | string    | Yes      | Meeting type UUID                                                                                                                            |
| `start`             | string    | Yes      | Start time (ISO 8601 with timezone)                                                                                                          |
| `hostIds`           | string\[] | No\*     | Host user UUIDs                                                                                                                              |
| `queueId`           | string    | No\*     | Queue ID for round-robin (alternative to hostIds)                                                                                            |
| `attendee`          | object    | Yes      | Attendee information                                                                                                                         |
| `duration`          | number    | No       | Duration in minutes (must match an allowed duration on the meeting type)                                                                     |
| `channel`           | string    | No       | Meeting channel: `google`, `zoom`, `teamsForBusiness2`, `phone`, `phone-incoming`, `local`, `local-attendee`, `connect`, `webex`, `whatsapp` |
| `location`          | string    | No       | For `local` channel: selects from configured locations. For `local-attendee`: can also use `attendee.notes.address`                          |
| `icsTitle`          | string    | No       | Custom calendar invite title (max 200 chars), overrides meeting type default                                                                 |
| `icsDescription`    | string    | No       | Custom calendar invite description (max 2000 chars), overrides meeting type default                                                          |
| `skipNotifications` | boolean   | No       | Skip email notifications (default: false)                                                                                                    |
| `phoneOnlyBooking`  | boolean   | No       | Use phone as identifier instead of email. See [Voice AI Bot](/developer-docs/recipes/voice-ai-bot)                                           |

\*Either `hostIds` or `queueId` is required

### Attendee Object

| Field              | Type      | Required | Description                                                                     |
| ------------------ | --------- | -------- | ------------------------------------------------------------------------------- |
| `email`            | string    | Yes\*    | Attendee email                                                                  |
| `firstname`        | string    | No†      | First name (†either `fullname` or `firstname`/`lastname` required)              |
| `lastname`         | string    | No†      | Last name                                                                       |
| `fullname`         | string    | No†      | Full name (alternative to first/last)                                           |
| `phone`            | string    | No       | Phone number                                                                    |
| `receiveReminders` | boolean   | Yes      | Whether the attendee receives reminder emails                                   |
| `notes`            | object    | Yes      | Key-value object for form field responses and UTM parameters. Pass `{}` if none |
| `language`         | string    | No       | Locale for notifications (`en`, `de`, etc.)                                     |
| `timezone`         | string    | No       | Attendee timezone (e.g. `Europe/Berlin`)                                        |
| `bringalongEmails` | string\[] | No       | Additional attendee emails (max 5)                                              |

\*Not required when `phoneOnlyBooking` is `true` and the meeting type has `allowPhoneOnlyBooking` enabled. See [Voice AI Bot](/developer-docs/recipes/voice-ai-bot) for details.

See [Create Booking API Reference](/api-reference/bookings/create-booking) for full field documentation, examples with custom ICS content, and UTM tracking.

### Response (Standard)

```json theme={null}
{
  "appointmentId": "appt-uuid-12345",
  "secret": "secret-token-xyz"
}
```

<Info>
  Store the `secret` to cancel or reschedule without authentication.
</Info>

### Response (Double Opt-In)

If the meeting type requires email confirmation:

```json theme={null}
{
  "bookingType": "DoubleOptIn",
  "provisionalBookingId": "provisional-uuid-123"
}
```

The booking is finalized after the attendee confirms via email.

## Get Appointments

### Get Paginated Appointments

```bash theme={null}
curl -X GET "https://api.meetergo.com/v4/appointment/paginated/?page=1&limit=20" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "x-meetergo-api-user-id: {userId}"
```

### Get Single Appointment

```bash theme={null}
curl -X GET "https://api.meetergo.com/v4/appointment/{appointmentId}" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "x-meetergo-api-user-id: {userId}"
```

### Response

```json theme={null}
{
  "id": "appt-uuid-12345",
  "start": "2024-01-15T09:00:00+01:00",
  "end": "2024-01-15T09:30:00+01:00",
  "isCancelled": false,
  "meetingType": {
    "id": "770e8400-e29b-41d4-a716-446655440002",
    "name": "Discovery Call",
    "duration": 30
  },
  "attendees": [
    {
      "id": "att-uuid-789",
      "email": "customer@example.com",
      "firstname": "Jane",
      "lastname": "Doe"
    }
  ],
  "hosts": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "email": "john@example.com",
      "givenName": "John",
      "familyName": "Smith"
    }
  ]
}
```

## Cancel an Appointment

### As Host (Authenticated)

```bash theme={null}
curl -X POST "https://api.meetergo.com/v4/appointment/{appointmentId}/cancel" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "x-meetergo-api-user-id: {userId}" \
  -H "Content-Type: application/json" \
  -d '{
    "reason": "Unable to attend"
  }'
```

### With Secret (Unauthenticated)

For self-service cancellation by attendees:

```bash theme={null}
curl -X POST "https://api.meetergo.com/booking/confirm/cancel/{appointmentId}/{secret}" \
  -H "Content-Type: application/json" \
  -d '{
    "cancellationReason": "Schedule conflict"
  }'
```

Both methods trigger:

* Cancellation emails to all parties
* `booking_cancelled` webhook event
* Calendar event removal (if integrated)

## Reschedule an Appointment

### With Secret (Unauthenticated)

```bash theme={null}
curl -X POST "https://api.meetergo.com/booking/confirm/reschedule/" \
  -H "Content-Type: application/json" \
  -d '{
    "appointmentId": "appt-uuid-12345",
    "secret": "secret-token-xyz",
    "start": "2024-01-16T10:00:00+01:00"
  }'
```

### As Host (Authenticated)

```bash theme={null}
curl -X POST "https://api.meetergo.com/v4/appointment/{appointmentId}/reschedule" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "x-meetergo-api-user-id: {userId}" \
  -H "Content-Type: application/json" \
  -d '{
    "start": "2024-01-16T10:00:00+01:00"
  }'
```

### Response

```json theme={null}
{
  "appointmentId": "appt-uuid-12345",
  "secret": "secret-token-xyz"
}
```

Rescheduling triggers:

* Updated calendar invites
* Notification emails
* `booking_rescheduled` webhook event

## Meeting Transcription & Summary

After a meeting takes place, you can attach a transcription and/or an AI-generated summary. Both fields accept **markdown-formatted text**, making them ideal for structured meeting records.

This is designed for integrations with transcription services (e.g. Otter.ai, Fireflies, Whisper), AI meeting assistants, or any tool that produces meeting records.

### Update Transcription

<CodeGroup>
  ```bash cURL theme={null}
  curl -X PATCH "https://api.meetergo.com/v4/appointment/{appointmentId}/transcription" \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "x-meetergo-api-user-id: {userId}" \
    -H "Content-Type: application/json" \
    -d '{
      "transcription": "## Meeting Transcript\n\n**John (00:00):** Welcome to the call...\n\n**Jane (00:15):** Thanks for having me...",
      "summary": "## Summary\n\n- Discussed Q2 roadmap priorities\n- Agreed on next steps for the partnership\n- Follow-up scheduled for next week"
    }'
  ```

  ```javascript JavaScript theme={null}
  await fetch(`https://api.meetergo.com/v4/appointment/${appointmentId}/transcription`, {
    method: 'PATCH',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'x-meetergo-api-user-id': userId,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      transcription: '## Meeting Transcript\n\n**John (00:00):** Welcome to the call...',
      summary: '## Summary\n\n- Discussed Q2 roadmap priorities\n- Agreed on next steps'
    })
  });
  ```

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

  requests.patch(
      f'https://api.meetergo.com/v4/appointment/{appointment_id}/transcription',
      headers={
          'Authorization': 'Bearer YOUR_API_KEY',
          'x-meetergo-api-user-id': user_id,
          'Content-Type': 'application/json'
      },
      json={
          'transcription': '## Meeting Transcript\n\n**John (00:00):** Welcome to the call...',
          'summary': '## Summary\n\n- Discussed Q2 roadmap priorities\n- Agreed on next steps'
      }
  )
  ```
</CodeGroup>

### Request Body

| Field           | Type           | Required | Description                                                                                |
| --------------- | -------------- | -------- | ------------------------------------------------------------------------------------------ |
| `transcription` | string \| null | No       | Full meeting transcription in markdown. Set to `null` to clear. Omit to leave unchanged.   |
| `summary`       | string \| null | No       | AI-generated meeting summary in markdown. Set to `null` to clear. Omit to leave unchanged. |

### Reading Transcription Data

The `transcription` and `summary` fields are included in the appointment response when you fetch an appointment:

```bash theme={null}
curl -X GET "https://api.meetergo.com/v4/appointment/{appointmentId}" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "x-meetergo-api-user-id: {userId}"
```

```json theme={null}
{
  "id": "appt-uuid-12345",
  "start": "2024-01-15T09:00:00+01:00",
  "end": "2024-01-15T09:30:00+01:00",
  "transcription": "## Meeting Transcript\n\n**John (00:00):** Welcome...",
  "summary": "## Summary\n\n- Discussed Q2 roadmap priorities...",
  "...": "other fields"
}
```

<Info>
  Both fields are `null` by default until populated. They are returned in all authenticated appointment endpoints (single, paginated, today, current).
</Info>

## Form Fields and UTM Parameters

Pass form field responses and UTM tracking data via `attendee.notes`:

```json theme={null}
{
  "meetingTypeId": "770e8400-e29b-41d4-a716-446655440002",
  "start": "2024-01-15T09:00:00+01:00",
  "hostIds": ["550e8400-e29b-41d4-a716-446655440000"],
  "attendee": {
    "email": "customer@example.com",
    "firstname": "Jane",
    "receiveReminders": true,
    "notes": {
      "company_size": "50-200",
      "referral_source": "Google",
      "utm_source": "website",
      "utm_content": "demo_cta"
    }
  }
}
```

Notes values are:

* Included in webhook payloads
* Visible in the dashboard
* Synced to CRM integrations (UTM parameters can be mapped to Salesforce fields via **Integrations → Salesforce → Settings**)

## Round-Robin Bookings

For team meeting types, use `queueId` instead of `hostIds`:

```json theme={null}
{
  "meetingTypeId": "770e8400-e29b-41d4-a716-446655440002",
  "start": "2024-01-15T09:00:00+01:00",
  "queueId": "queue-uuid-123",
  "attendee": {
    "email": "customer@example.com",
    "receiveReminders": true,
    "notes": {}
  }
}
```

The system automatically selects the next available team member based on:

* Round-robin rotation
* Current availability
* Existing bookings

## Error Handling

### Time Slot Unavailable

```json theme={null}
{
  "statusCode": 400,
  "message": "The selected time slot is no longer available",
  "error": "Bad Request"
}
```

**Solution:** Query fresh availability and select another slot.

### Invalid Duration

```json theme={null}
{
  "statusCode": 400,
  "message": "Duration must match one of the allowed durations for this meeting type",
  "error": "Bad Request"
}
```

**Solution:** Check the meeting type's allowed durations.

### Missing Host

```json theme={null}
{
  "statusCode": 400,
  "message": "hostIds or queueId is required",
  "error": "Bad Request"
}
```

**Solution:** Provide either `hostIds` array or `queueId`.

## Best Practices

<Check>
  **Always query availability first** - Don't book without checking available slots
</Check>

<Check>
  **Store the secret** - You'll need it for self-service cancel/reschedule
</Check>

<Check>
  **Handle race conditions** - Slots can be booked between availability query and booking
</Check>

<Check>
  **Use webhooks** - Get real-time notifications instead of polling
</Check>

<Warning>
  **Time format** - Always include timezone offset in ISO 8601 format (e.g., `+01:00`)
</Warning>
