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

# Create Booking

> Book an appointment for a meeting type

Creates a new appointment booking with a specified host for a given meeting type and time slot.

## Endpoint

```
POST /v4/booking
```

## Request Headers

| Header          | Required | Description             |
| --------------- | -------- | ----------------------- |
| `Authorization` | Yes      | `Bearer <your-api-key>` |
| `Content-Type`  | Yes      | `application/json`      |

## Request Body

### Required Fields

| Field           | Type   | Description                                                       |
| --------------- | ------ | ----------------------------------------------------------------- |
| `meetingTypeId` | string | The ID of the meeting type to book                                |
| `start`         | string | Start time in ISO 8601 format (e.g., `2024-01-15T09:00:00+01:00`) |
| `attendee`      | object | Information about the person booking                              |

### Attendee Object

| Field              | Type      | Required | Description                                                                                                                                                               |
| ------------------ | --------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `email`            | string    | Yes\*    | Email address of the attendee                                                                                                                                             |
| `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, UTM parameters, and metadata. Keys correspond to form field identifiers on the meeting type. Pass `{}` if no fields are needed |
| `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. In this case, `phone` becomes required instead. See [Voice AI Bot](/developer-docs/recipes/voice-ai-bot) for details.

### Optional Fields

| Field               | Type      | Description                                                                                                                                                                                        |
| ------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `hostIds`           | string\[] | Host IDs for the booking. Required for one-on-one bookings. For round-robin, use `queueId` instead                                                                                                 |
| `queueId`           | string    | Queue ID for round-robin or co-host meeting types. Use instead of `hostIds` to let the system select the next available host                                                                       |
| `duration`          | number    | Duration in minutes. Must match an allowed duration configured on the meeting type. If omitted, uses the default duration                                                                          |
| `channel`           | string    | Meeting channel: `google`, `zoom`, `teamsForBusiness2`, `phone`, `phone-incoming`, `local`, `local-attendee`, `connect`, `webex`, `whatsapp`                                                       |
| `location`          | string    | For `local` (in-person at host) channel: selects from the meeting type's configured locations. For `local-attendee` channel: can also be provided via `attendee.notes.address`                     |
| `skipNotifications` | boolean   | Skip sending email notifications to the attendee (default: `false`)                                                                                                                                |
| `phoneOnlyBooking`  | boolean   | When `true`, attendee email is not required and phone becomes the identifier. The meeting type must have `allowPhoneOnlyBooking` enabled. See [Voice AI Bot](/developer-docs/recipes/voice-ai-bot) |
| `icsTitle`          | string    | Custom calendar invite title (max 200 chars). Overrides the meeting type's configured ICS title for this booking                                                                                   |
| `icsDescription`    | string    | Custom calendar invite description (max 2000 chars). Overrides the meeting type's configured ICS description for this booking                                                                      |

## Examples

### Basic 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": "client@example.com",
        "firstname": "Jane",
        "lastname": "Smith",
        "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: 'client@example.com',
        firstname: 'Jane',
        lastname: 'Smith',
        receiveReminders: true,
        notes: {}
      }
    })
  });

  const booking = await response.json();
  console.log('Booking created:', booking.appointmentId);
  ```

  ```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': 'client@example.com',
              'firstname': 'Jane',
              'lastname': 'Smith',
              'receiveReminders': True,
              'notes': {}
          }
      }
  )

  booking = response.json()
  print(f"Booking created: {booking['appointmentId']}")
  ```
</CodeGroup>

### With Form Fields and Video Conferencing

```json theme={null}
{
  "meetingTypeId": "770e8400-e29b-41d4-a716-446655440002",
  "start": "2024-01-15T09:00:00+01:00",
  "hostIds": ["550e8400-e29b-41d4-a716-446655440000"],
  "channel": "zoom",
  "attendee": {
    "email": "client@example.com",
    "firstname": "Jane",
    "lastname": "Smith",
    "phone": "+1-555-123-4567",
    "receiveReminders": true,
    "notes": {
      "company": "Acme Inc",
      "referral_source": "Website",
      "company_size": "50-200"
    }
  }
}
```

### Custom Calendar Invite

Use `icsTitle` and `icsDescription` to override the calendar invite content for a specific booking. If not provided, the meeting type's configured title and description are used.

This is useful for chatbot or AI assistant integrations where you have conversation context to include in the invite.

```json theme={null}
{
  "meetingTypeId": "770e8400-e29b-41d4-a716-446655440002",
  "start": "2024-01-15T09:00:00+01:00",
  "hostIds": ["550e8400-e29b-41d4-a716-446655440000"],
  "icsTitle": "Product Demo — Jane Smith",
  "icsDescription": "Chat summary: Customer asked about enterprise pricing and SSO. Wants to discuss data residency requirements for EU deployment.",
  "attendee": {
    "email": "client@example.com",
    "firstname": "Jane",
    "lastname": "Smith",
    "receiveReminders": true,
    "notes": {}
  }
}
```

### UTM Tracking

Pass UTM parameters in `attendee.notes` to track the source of a booking. These values are stored on the attendee and can be synced to CRM fields.

```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": "client@example.com",
    "firstname": "Jane",
    "lastname": "Smith",
    "receiveReminders": true,
    "notes": {
      "utm_source": "qualimero",
      "utm_medium": "chatbot",
      "utm_content": "enterprise_q1"
    }
  }
}
```

Supported UTM keys: `utm_source`, `utm_medium`, `utm_campaign`, `utm_content`, `utm_term`. See [Sync with CRM](/developer-docs/recipes/sync-with-crm) for configuring UTM field mappings in Salesforce.

## Response

### Success (201 Created) - Standard Booking

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

| Field           | Description                                                   |
| --------------- | ------------------------------------------------------------- |
| `appointmentId` | UUID of the created appointment                               |
| `secret`        | Secret token for managing the appointment (cancel/reschedule) |

<Warning>
  Store the `secret` securely. It's required to cancel or reschedule the appointment without authentication.
</Warning>

### Success (201 Created) - Double Opt-In

If the meeting type requires confirmation:

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

| Field                  | Description                                              |
| ---------------------- | -------------------------------------------------------- |
| `bookingType`          | `DoubleOptIn` or `RequireHostConfirmation`               |
| `provisionalBookingId` | ID of provisional booking (finalized after confirmation) |

### Error Responses

#### 400 Bad Request - Time Slot Unavailable

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

#### 400 Bad Request - Missing Host

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

#### 400 Bad Request - Invalid Duration

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

## Webhooks

When a booking is created, meetergo sends a `booking_created` webhook event:

```json theme={null}
{
  "webhookType": "booking_created",
  "id": "appt-uuid-456",
  "start": "2024-01-15T09:00:00+01:00",
  "end": "2024-01-15T09:30:00+01:00",
  "attendees": [{
    "email": "client@example.com",
    "firstname": "Jane",
    "lastname": "Smith"
  }],
  "hostIds": ["550e8400-e29b-41d4-a716-446655440000"],
  "meetingTypeId": "770e8400-e29b-41d4-a716-446655440002"
}
```

## Notes

* Use [Get Booking Availability](/api-reference/availability/get-availability) first to find available slots
* For round-robin meeting types, provide `queueId` instead of `hostIds` to let the system select the next available host
* If double opt-in is enabled, the attendee must confirm via email before the appointment is finalized

## Related Endpoints

<CardGroup cols={2}>
  <Card title="Get Booking Availability" icon="calendar" href="/api-reference/availability/get-availability">
    Find available time slots
  </Card>

  <Card title="Create User" icon="user-plus" href="/api-reference/users/create-user">
    Create a schedulable user
  </Card>
</CardGroup>
