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

# Calendar Endpoints

> Reference for availability checks, bookings, updates, and cancellations in the Vapify Calendar API.

## Overview

This page documents the concrete Calendar API endpoints. Every request uses the base URL and authentication method described in the [Calendar API overview](/api-reference/introduction).

***

## Check Availability

Retrieve available time slots for a date range.

```http theme={null}
GET /calendar/availability
```

**Required permission:** `canCheckAvailability`

### Query Parameters

| Parameter     | Type            | Required | Description                                  |
| ------------- | --------------- | -------- | -------------------------------------------- |
| `startDate`   | ISO 8601 string | Yes      | Start of the availability window             |
| `endDate`     | ISO 8601 string | Yes      | End of the availability window               |
| `eventTypeId` | integer         | No       | Filter availability to a specific event type |
| `duration`    | integer         | No       | Desired slot duration in minutes             |
| `timezone`    | string          | No       | IANA timezone such as `America/New_York`     |

### Example Request

```http theme={null}
GET /calendar/availability?startDate=2024-03-20T00:00:00Z&endDate=2024-03-21T00:00:00Z&timezone=America/New_York
x-calendar-api-key: YOUR_API_KEY
```

### Response `200 OK`

Returns an array of days, each with the open `slots` for that day. `start` and `end` are ISO 8601 timestamps.

```json theme={null}
[
  {
    "date": "2024-03-20",
    "slots": [
      { "start": "2024-03-20T09:00:00Z", "end": "2024-03-20T09:30:00Z" },
      { "start": "2024-03-20T10:00:00Z", "end": "2024-03-20T10:30:00Z" }
    ]
  },
  {
    "date": "2024-03-21",
    "slots": []
  }
]
```

***

## List Bookings

Retrieve bookings with optional filters and pagination.

```http theme={null}
GET /calendar/bookings
```

**Required permission:** `canGetBookings`

### Query Parameters

| Parameter     | Type            | Required | Description                                                              |
| ------------- | --------------- | -------- | ------------------------------------------------------------------------ |
| `startDate`   | ISO 8601 string | No       | Return bookings starting on or after this time                           |
| `endDate`     | ISO 8601 string | No       | Return bookings ending on or before this time                            |
| `status`      | string          | No       | Filter by `pending`, `confirmed`, `cancelled`, `completed`, or `no_show` |
| `eventTypeId` | integer         | No       | Filter by event type                                                     |
| `email`       | string          | No       | Filter by attendee email address                                         |
| `limit`       | integer         | No       | Number of results to return. Default: `50`                               |
| `offset`      | integer         | No       | Pagination offset. Default: `0`                                          |

### Example Request

```http theme={null}
GET /calendar/bookings?status=confirmed&limit=10&offset=0
x-calendar-api-key: YOUR_API_KEY
```

### Response `200 OK`

```json theme={null}
{
  "bookings": [
    {
      "id": 123,
      "startTime": "2024-03-20T09:00:00Z",
      "endTime": "2024-03-20T09:30:00Z",
      "status": "confirmed",
      "title": "Consultation Call",
      "description": "Initial consultation",
      "location": "https://meet.google.com/abc-defg-hij",
      "timezone": "America/New_York",
      "metadata": {},
      "attendees": [
        {
          "id": 456,
          "email": "client@example.com",
          "name": "John Doe",
          "firstName": "John",
          "lastName": "Doe",
          "phone": "+1234567890",
          "timezone": "America/New_York",
          "isOrganizer": false,
          "createdAt": "2024-03-15T10:00:00Z",
          "updatedAt": "2024-03-15T10:00:00Z"
        }
      ],
      "confirmedAt": "2024-03-16T10:00:00Z",
      "cancelledAt": null,
      "completedAt": null
    }
  ],
  "total": 100,
  "limit": 10,
  "offset": 0
}
```

***

## Get Booking

Retrieve a single booking by ID.

```http theme={null}
GET /calendar/bookings/:id
```

**Required permission:** `canGetBookings`

### Path Parameters

| Parameter | Type    | Required | Description |
| --------- | ------- | -------- | ----------- |
| `id`      | integer | Yes      | Booking ID  |

### Example Request

```http theme={null}
GET /calendar/bookings/123
x-calendar-api-key: YOUR_API_KEY
```

### Response `200 OK`

```json theme={null}
{
  "id": 123,
  "startTime": "2024-03-20T09:00:00Z",
  "endTime": "2024-03-20T09:30:00Z",
  "status": "confirmed",
  "title": "Consultation Call",
  "description": "Initial consultation",
  "location": "https://meet.google.com/abc-defg-hij",
  "timezone": "America/New_York",
  "metadata": {},
  "attendees": [
    {
      "id": 456,
      "email": "client@example.com",
      "name": "John Doe",
      "firstName": "John",
      "lastName": "Doe",
      "phone": "+1234567890",
      "timezone": "America/New_York",
      "isOrganizer": false,
      "createdAt": "2024-03-15T10:00:00Z",
      "updatedAt": "2024-03-15T10:00:00Z"
    }
  ],
  "confirmedAt": "2024-03-16T10:00:00Z",
  "cancelledAt": null,
  "completedAt": null
}
```

***

## Create Booking

Create a booking for a specific event type.

```http theme={null}
POST /calendar/event-types/:eventTypeId/bookings
```

**Required permission:** `canBook`

### Path Parameters

| Parameter     | Type    | Required | Description        |
| ------------- | ------- | -------- | ------------------ |
| `eventTypeId` | integer | Yes      | Event type to book |

### Request Body

```json theme={null}
{
  "idempotencyKey": "unique-key-for-this-booking",
  "startTime": "2024-03-20T09:00:00Z",
  "endTime": "2024-03-20T09:30:00Z",
  "timezone": "America/New_York",
  "title": "Consultation Call",
  "description": "Initial consultation",
  "attendees": [
    {
      "email": "client@example.com",
      "name": "John Doe",
      "firstName": "John",
      "lastName": "Doe",
      "phone": "+1234567890"
    }
  ],
  "metadata": {}
}
```

### Body Fields

| Field            | Type            | Required | Description                                      |
| ---------------- | --------------- | -------- | ------------------------------------------------ |
| `startTime`      | ISO 8601 string | Yes      | Booking start time                               |
| `endTime`        | ISO 8601 string | Yes      | Booking end time                                 |
| `attendees`      | array           | Yes      | At least one attendee with a valid `email`       |
| `timezone`       | string          | No       | IANA timezone such as `America/New_York`         |
| `title`          | string          | No       | Booking title                                    |
| `description`    | string          | No       | Booking description                              |
| `idempotencyKey` | string          | No       | Unique retry key to prevent duplicate bookings   |
| `metadata`       | object          | No       | Arbitrary key-value data attached to the booking |

<Tip>
  Use `idempotencyKey` when retrying a booking request from an AI agent or workflow. If the same key is reused, the existing booking is returned instead of creating a duplicate.
</Tip>

### Example Request

```http theme={null}
POST /calendar/event-types/42/bookings
x-calendar-api-key: YOUR_API_KEY
Content-Type: application/json

{
  "startTime": "2024-03-20T09:00:00Z",
  "endTime": "2024-03-20T09:30:00Z",
  "timezone": "America/New_York",
  "title": "Consultation Call",
  "attendees": [
    {
      "email": "client@example.com",
      "name": "John Doe"
    }
  ]
}
```

### Response `201 Created`

```json theme={null}
{
  "id": 123,
  "uid": "bk_abc123xyz",
  "startTime": "2024-03-20T09:00:00Z",
  "endTime": "2024-03-20T09:30:00Z",
  "status": "pending",
  "title": "Consultation Call",
  "description": null,
  "location": null,
  "timezone": "America/New_York",
  "metadata": {},
  "attendees": [
    {
      "id": 456,
      "email": "client@example.com",
      "name": "John Doe",
      "firstName": null,
      "lastName": null,
      "phone": null,
      "timezone": "America/New_York",
      "isOrganizer": false,
      "createdAt": "2024-03-15T10:00:00Z",
      "updatedAt": "2024-03-15T10:00:00Z"
    }
  ],
  "confirmedAt": null,
  "cancelledAt": null,
  "completedAt": null
}
```

***

## Update Booking

Update booking details or reschedule an existing booking.

```http theme={null}
PUT /calendar/event-types/:eventTypeId/bookings/:id
```

**Required permission:** `canBook`

### Path Parameters

| Parameter     | Type    | Required | Description                            |
| ------------- | ------- | -------- | -------------------------------------- |
| `eventTypeId` | integer | Yes      | Event type associated with the booking |
| `id`          | integer | Yes      | Booking ID                             |

### Request Body

All fields are optional. Only send the fields you want to change.

```json theme={null}
{
  "startTime": "2024-03-20T10:00:00Z",
  "endTime": "2024-03-20T10:30:00Z",
  "timezone": "America/Chicago",
  "title": "Rescheduled Consultation",
  "description": "Rescheduled from earlier slot",
  "attendees": [
    {
      "email": "client@example.com",
      "name": "John Doe"
    }
  ],
  "metadata": {}
}
```

### Example Request

```http theme={null}
PUT /calendar/event-types/42/bookings/123
x-calendar-api-key: YOUR_API_KEY
Content-Type: application/json

{
  "startTime": "2024-03-20T10:00:00Z",
  "endTime": "2024-03-20T10:30:00Z"
}
```

### Response `200 OK`

```json theme={null}
{
  "id": 123,
  "startTime": "2024-03-20T10:00:00Z",
  "endTime": "2024-03-20T10:30:00Z",
  "status": "pending",
  "title": "Rescheduled Consultation",
  "description": "Rescheduled from earlier slot",
  "timezone": "America/Chicago",
  "attendees": [
    {
      "id": 456,
      "email": "client@example.com",
      "name": "John Doe",
      "createdAt": "2024-03-15T10:00:00Z",
      "updatedAt": "2024-03-20T08:00:00Z"
    }
  ]
}
```

***

## Cancel Booking

Cancel an existing booking.

```http theme={null}
DELETE /calendar/bookings/:id
```

**Required permission:** `canCancel`

### Path Parameters

| Parameter | Type    | Required | Description |
| --------- | ------- | -------- | ----------- |
| `id`      | integer | Yes      | Booking ID  |

### Request Body

```json theme={null}
{
  "reason": "Client requested reschedule"
}
```

| Field    | Type   | Required | Description                      |
| -------- | ------ | -------- | -------------------------------- |
| `reason` | string | No       | Optional reason for cancellation |

### Example Request

```http theme={null}
DELETE /calendar/bookings/123
x-calendar-api-key: YOUR_API_KEY
Content-Type: application/json

{
  "reason": "Client requested reschedule"
}
```

### Response `200 OK`

```json theme={null}
{
  "id": 123,
  "status": "cancelled",
  "cancelledAt": "2024-03-15T15:00:00Z",
  "cancellationReason": "Client requested reschedule"
}
```

***

## Error Responses

All error responses follow the same structure:

```json theme={null}
{
  "statusCode": 401,
  "message": "Invalid or inactive API key"
}
```

### Error Codes

| Status Code             | Meaning               | Common Causes                                                                                     |
| ----------------------- | --------------------- | ------------------------------------------------------------------------------------------------- |
| `400 Bad Request`       | Invalid request       | Missing required fields, invalid date formats, duplicate `idempotencyKey`, or time slot conflicts |
| `401 Unauthorized`      | Authentication failed | Missing, invalid, expired, or inactive API key                                                    |
| `403 Forbidden`         | Permission denied     | API key does not have the required permission for the operation                                   |
| `404 Not Found`         | Resource not found    | Booking or event type does not exist                                                              |
| `429 Too Many Requests` | Rate limit exceeded   | More than 60 requests per minute from one API key                                                 |

### Common `401` Messages

| Message                                      | Description                                           |
| -------------------------------------------- | ----------------------------------------------------- |
| `"Invalid or inactive API key"`              | The key does not exist or has been deactivated        |
| `"API key has expired"`                      | The configured expiry date has passed                 |
| `"API key not associated with a subaccount"` | The key is not linked to a usable subaccount calendar |

### Common `403` Messages

| Message                                                     | Description                          |
| ----------------------------------------------------------- | ------------------------------------ |
| `"API key does not have 'canCheckAvailability' permission"` | Key cannot check availability        |
| `"API key does not have 'canGetBookings' permission"`       | Key cannot read bookings             |
| `"API key does not have 'canBook' permission"`              | Key cannot create or update bookings |
| `"API key does not have 'canCancel' permission"`            | Key cannot cancel bookings           |
