> For the complete documentation index, see [llms.txt](https://docs.api.intratool.de/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.api.intratool.de/api-reference/calendar/calendar-events.md).

# CalendarEvents

## Introduction

`CalendarEvents` are appointments owned by a [User](/api-reference/users.md), categorized by a [Calendar](/api-reference/calendar/calendars.md), and optionally shared with [Departments](/api-reference/departments.md).

Recurring events are expanded into occurrences by the list endpoint. Individual dates can be excluded through [DeletedRepeatingCalendarEvents](/api-reference/calendar/deleted-repeating-calendar-events.md).

The `description` field uses the shared [Rich Text](/introduction/rich-text.md) HTML format.

## Model Definition

**Alias**

`calendarEvent`

**Relations**

| Key           | Relation                                         | Type            | Relation Field(s)           |
| ------------- | ------------------------------------------------ | --------------- | --------------------------- |
| `user`        | [User](/api-reference/users.md)                  | Belongs to      | `user_id`                   |
| `calendar`    | [Calendar](/api-reference/calendar/calendars.md) | Belongs to      | `calendar_id`               |
| `departments` | [Departments](/api-reference/departments.md)     | Belongs to many | `department_calendar_event` |

**Computed Properties**

* `hash` - Hashed representation of the event `id` used in stable event URLs.
* `color` - Color of the related Calendar, or an empty string when no calendar is loaded.
* `url` and `static_url` - Link to the calendar event page.

**Capabilities**

* [URL Context](/introduction/resource-capabilities/url-context.md) - Event URLs resolve to access-checked context containing dates, location, a description teaser, and an optional image.
* [Notifications](/introduction/resource-capabilities/notifications.md) - Creation and relevant updates can notify eligible users in assigned departments according to calendar notification settings; deleting the event also removes its notifications.

## Interval Syntax

| Interval      | Variant          | Syntax              | Description                                                |
| ------------- | ---------------- | ------------------- | ---------------------------------------------------------- |
| Daily         | Every day        | `d:::1`             | Repeat every day.                                          |
| Weekly        | Every week       | `w:::1`             | Repeat every week.                                         |
| Weekly        | Weekdays         | `w:::1d::1,2,3,4,5` | Repeat on Monday through Friday every week.                |
| Monthly       | Day of month     | `m:::1d::15`        | Repeat on the 15th day every month.                        |
| Monthly       | Week and weekday | `m:::1w::1d::1`     | Repeat on the first Monday every month.                    |
| Yearly        | Day              | `y:::1d::1`         | Repeat yearly on the configured day.                       |
| Yearly        | Week and weekday | `y:::1w::1d::1`     | Repeat yearly by week and weekday.                         |
| End condition | Occurrence count | `r:::5`             | End after five occurrences. Only valid for `interval_end`. |
| End condition | Date             | `d:::2027-12-31`    | End on a date. Only valid for `interval_end`.              |

## List

List events visible to the authenticated user. Recurring events are expanded within the requested period.

**Definition**

<mark style="color:green;">`GET`</mark> `/api/calendar-events`

**Request Keys**

| Key               | Type                    | Default                           | Description                                                                   |
| ----------------- | ----------------------- | --------------------------------- | ----------------------------------------------------------------------------- |
| `department_ids`  | `integer[]` \| `string` | All visible                       | Department IDs as an array or comma-separated string.                         |
| `calendar_ids`    | `integer[]` \| `string` | All calendars                     | Calendar IDs as an array or comma-separated string.                           |
| `period_start`    | `date`                  | No lower bound                    | Beginning of the occurrence period.                                           |
| `period_end`      | `date`                  | No upper bound                    | End of the occurrence period.                                                 |
| `search`          | `string`                | No search                         | Search `title` and `description`.                                             |
| `selects`         | `string`                | All fields                        | Comma-separated fields to return for persisted events.                        |
| `relations`       | `string`                | `user`, `calendar`, `departments` | Pipe-separated relations. An empty value suppresses defaults.                 |
| `limit`           | `integer`               | No limit                          | Maximum results after persisted and recurring events are merged. Minimum `1`. |
| `order_field`     | `string`                | `created_at`                      | Field used to order persisted events.                                         |
| `order_direction` | `string`                | `desc`                            | `asc` or `desc`.                                                              |

**Behavior**

* Results are limited by calendar permissions, event ownership, and shared departments.
* Persisted events contain `repeat_date: false`; generated recurring occurrences contain `repeat_date: true` and occurrence-specific `start` and `end` values.

**Example Request**

{% tabs %}
{% tab title="PHP" %}

```php
$client = new GuzzleHttp\Client(['base_uri' => 'https://{tenant}.intratool.de']);
$response = $client->request('GET', '/api/calendar-events', [
    'headers' => ['Authorization' => "Bearer {accessToken}"],
    'query' => [
        'period_start' => '2026-08-10',
        'period_end' => '2026-08-14',
        'calendar_ids' => '1,2',
        'limit' => 2
    ]
]);
```

{% endtab %}
{% endtabs %}

**Example Response**

```json
[
  {
    "id": 41,
    "user_id": 8,
    "calendar_id": 1,
    "title": "Daily Production Briefing",
    "all_day": false,
    "start": "2026-08-10 09:00:00",
    "end": "2026-08-10 09:30:00",
    "interval": {
      "type": "daily",
      "each_days": 1
    },
    "interval_end": {
      "type": "repeats",
      "repeats": 5
    },
    "location": "Production Hall",
    "description": "<p>Daily handover.</p>",
    "repeat_date": true,
    "hash": "6o8m0kz5yw10xx1pr9e4vxj2",
    "color": "#2196F3"
  },
  {
    "id": 42,
    "user_id": 9,
    "calendar_id": 2,
    "title": "Company Holiday",
    "all_day": true,
    "start": "2026-08-12 00:00:00",
    "end": "2026-08-13 00:00:00",
    "interval": null,
    "interval_end": null,
    "location": null,
    "description": null,
    "repeat_date": false,
    "hash": "7p9n1layzx21yyrqs0f5wyk3",
    "color": "#8BC34A"
  }
]
```

## Show

Show one event by numeric ID or hash.

**Definition**

<mark style="color:green;">`GET`</mark> `/api/calendar-events/{calendarEvent}`

**Route Parameters**

| Parameter       | Type                  | Description       |
| --------------- | --------------------- | ----------------- |
| `calendarEvent` | `integer` \| `string` | Event ID or hash. |

**Request Keys**

| Key         | Type     | Default                           | Description                       |
| ----------- | -------- | --------------------------------- | --------------------------------- |
| `selects`   | `string` | All fields                        | Comma-separated fields to return. |
| `relations` | `string` | `user`, `calendar`, `departments` | Pipe-separated relations.         |

**Example Request**

{% tabs %}
{% tab title="PHP" %}

```php
$client = new GuzzleHttp\Client(['base_uri' => 'https://{tenant}.intratool.de']);
$response = $client->request('GET', '/api/calendar-events/41', [
    'headers' => ['Authorization' => "Bearer {accessToken}"]
]);
```

{% endtab %}
{% endtabs %}

**Example Response**

```json
{
  "id": 41,
  "user_id": 8,
  "calendar_id": 1,
  "title": "Daily Production Briefing",
  "all_day": false,
  "start": "2026-08-10 09:00:00",
  "end": "2026-08-10 09:30:00",
  "interval": {
    "type": "daily",
    "each_days": 1
  },
  "interval_end": {
    "type": "repeats",
    "repeats": 5
  },
  "location": "Production Hall",
  "description": "<p>Daily handover.</p>",
  "hash": "6o8m0kz5yw10xx1pr9e4vxj2",
  "color": "#2196F3"
}
```

## Parse ICS

Parse an uploaded iCalendar file into event request data without persisting events.

**Definition**

<mark style="color:yellow;">`POST`</mark> `/api/calendar-events/ics`

**Request Keys**

| Key                     | Type   | Description              |
| ----------------------- | ------ | ------------------------ |
| `calendar_events_ics`\* | `file` | iCalendar file to parse. |

Keys with `*` are required.

**Behavior**

* UTC timestamps are converted to the application timezone and normalized to whole seconds.
* Text descriptions are converted into HTML paragraphs. Invalid recurrence rules produce `null` interval values instead of failing the complete import.

**Example Request**

{% tabs %}
{% tab title="PHP" %}

```php
$ics = "BEGIN:VCALENDAR\r\n"
    . "VERSION:2.0\r\n"
    . "BEGIN:VEVENT\r\n"
    . "UID:safety-training@example.com\r\n"
    . "DTSTART:20260818T070000Z\r\n"
    . "DTEND:20260818T090000Z\r\n"
    . "SUMMARY:Safety Training\r\n"
    . "LOCATION:Training Room\r\n"
    . "END:VEVENT\r\n"
    . "END:VCALENDAR\r\n";

$client = new GuzzleHttp\Client(['base_uri' => 'https://{tenant}.intratool.de']);
$response = $client->request('POST', '/api/calendar-events/ics', [
    'headers' => ['Authorization' => "Bearer {accessToken}"],
    'multipart' => [[
        'name' => 'calendar_events_ics',
        'contents' => $ics,
        'filename' => 'calendar-events.ics'
    ]]
]);
```

{% endtab %}
{% endtabs %}

**Example Response**

```json
{
  "status": "success",
  "data": {
    "datas": [
      {
        "title": "Safety Training",
        "all_day": false,
        "start": "2026-08-18 09:00:00",
        "end": "2026-08-18 11:00:00",
        "interval": null,
        "interval_end": null,
        "location": "Training Room",
        "description": null
      }
    ]
  }
}
```

## Create

Create an event.

**Definition**

<mark style="color:yellow;">`POST`</mark> `/api/calendar-events`

**Request Keys**

| Key              | Type                    | Default | Description                                                  |
| ---------------- | ----------------------- | ------- | ------------------------------------------------------------ |
| `calendar_id`\*  | `integer`               | -       | Related [Calendar](/api-reference/calendar/calendars.md) ID. |
| `title`\*        | `string`                | -       | Event title.                                                 |
| `all_day`        | `boolean`               | `false` | Whether the event spans complete calendar days.              |
| `start`\*        | `datetime`              | -       | Start date and time.                                         |
| `end`\*          | `datetime`              | -       | End date and time.                                           |
| `interval`       | `string` \| `null`      | `null`  | Recurrence value from [Interval Syntax](#interval-syntax).   |
| `interval_end`   | `string` \| `null`      | `null`  | Recurrence end condition.                                    |
| `location`       | `string` \| `null`      | `null`  | Event location.                                              |
| `description`    | `string` \| `null`      | `null`  | Event description, usually HTML.                             |
| `department_ids` | `integer[]` \| `string` | `[]`    | Visible departments as an array or comma-separated string.   |

Keys with `*` are required.

**Behavior**

* `user_id` is always set to the authenticated user.
* Department IDs are attached after event creation. Depending on notification settings, eligible users in these departments can receive a creation notification.

**Example Request**

{% tabs %}
{% tab title="PHP" %}

```php
$client = new GuzzleHttp\Client(['base_uri' => 'https://{tenant}.intratool.de']);
$response = $client->request('POST', '/api/calendar-events', [
    'headers' => ['Authorization' => "Bearer {accessToken}"],
    'json' => [
        'calendar_id' => 1,
        'title' => 'Weekly Safety Training',
        'all_day' => false,
        'start' => '2026-08-18 09:00:00',
        'end' => '2026-08-18 11:00:00',
        'interval' => 'w:::1d::2',
        'interval_end' => 'r:::5',
        'location' => 'Training Room',
        'description' => '<p>Bring your protective equipment.</p>',
        'department_ids' => [2, 3]
    ]
]);
```

{% endtab %}
{% endtabs %}

**Example Response**

```json
{
  "status": "success",
  "data": {
    "id": 43,
    "user_id": 8,
    "calendar_id": 1,
    "title": "Weekly Safety Training",
    "all_day": false,
    "start": "2026-08-18 09:00:00",
    "end": "2026-08-18 11:00:00",
    "interval": {
      "type": "weekly",
      "each_weeks": 1,
      "days_in_week": [2]
    },
    "interval_end": {
      "type": "repeats",
      "repeats": 5
    },
    "location": "Training Room",
    "description": "<p>Bring your protective equipment.</p>",
    "hash": "8q0o2mbzay32zzsrt1g6xzl4",
    "color": "#2196F3"
  }
}
```

## Update

Update an event.

**Definition**

<mark style="color:blue;">`PUT`</mark> `/api/calendar-events/{calendarEvent}`

**Route Parameters**

| Parameter       | Type                  | Description       |
| --------------- | --------------------- | ----------------- |
| `calendarEvent` | `integer` \| `string` | Event ID or hash. |

**Request Keys**

| Key              | Type                    | Description                   |
| ---------------- | ----------------------- | ----------------------------- |
| `calendar_id`    | `integer`               | New Calendar ID.              |
| `title`          | `string`                | New event title.              |
| `all_day`        | `boolean`               | New all-day state.            |
| `start`          | `datetime`              | New start.                    |
| `end`            | `datetime`              | New end.                      |
| `interval`       | `string` \| `null`      | New recurrence value.         |
| `interval_end`   | `string` \| `null`      | New recurrence end condition. |
| `location`       | `string` \| `null`      | New location.                 |
| `description`    | `string` \| `null`      | New description.              |
| `department_ids` | `integer[]` \| `string` | Replacement department IDs.   |

**Behavior**

* `user_id` cannot be changed.
* Departments are synchronized only when `department_ids` is non-empty. Send all desired IDs when replacing the assignment.
* Changes to title, description, location, dates, or all-day state can trigger update notifications.

**Example Request**

{% tabs %}
{% tab title="PHP" %}

```php
$client = new GuzzleHttp\Client(['base_uri' => 'https://{tenant}.intratool.de']);
$response = $client->request('PUT', '/api/calendar-events/43', [
    'headers' => ['Authorization' => "Bearer {accessToken}"],
    'json' => [
        'title' => 'Weekly Safety Training - Hall B',
        'location' => 'Hall B',
        'department_ids' => [2, 4]
    ]
]);
```

{% endtab %}
{% endtabs %}

**Example Response**

```json
{
  "status": "success",
  "data": {
    "id": 43,
    "user_id": 8,
    "calendar_id": 1,
    "title": "Weekly Safety Training - Hall B",
    "all_day": false,
    "start": "2026-08-18 09:00:00",
    "end": "2026-08-18 11:00:00",
    "interval": {
      "type": "weekly",
      "each_weeks": 1,
      "days_in_week": [2]
    },
    "interval_end": {
      "type": "repeats",
      "repeats": 5
    },
    "location": "Hall B",
    "description": "<p>Bring your protective equipment.</p>",
    "hash": "8q0o2mbzay32zzsrt1g6xzl4",
    "color": "#2196F3"
  }
}
```

## Delete

Delete an event permanently and remove its related notifications.

**Definition**

<mark style="color:red;">`DELETE`</mark> `/api/calendar-events/{calendarEvent}`

**Route Parameters**

| Parameter       | Type                  | Description       |
| --------------- | --------------------- | ----------------- |
| `calendarEvent` | `integer` \| `string` | Event ID or hash. |

**Example Request**

{% tabs %}
{% tab title="PHP" %}

```php
$client = new GuzzleHttp\Client(['base_uri' => 'https://{tenant}.intratool.de']);
$response = $client->request('DELETE', '/api/calendar-events/43', [
    'headers' => ['Authorization' => "Bearer {accessToken}"]
]);
```

{% endtab %}
{% endtabs %}

**Example Response**

```json
{
  "status": "success",
  "data": []
}
```
