Calendar Entries
Simple date/time entries that appear in the employee calendar. Published and added to the calendar on creation unless you send is_published: false. The body is optional. Entries can be targeted at groups; an entry can also be targeted at individually chosen people in the CMS, and the API does not return those, so "groups": [] means company-wide only when no people were chosen. Entries can be categorized with an event type via calendar_event_type_id. When omitted, the published event type named "Default" is used — if that type has been renamed or unpublished, calendar_event_type_id is required (422 otherwise).
Required scope: read:calendar_entries, write:calendar_entries.
Endpoints
/api/open/v1/calendar-entriesList calendar entries (published by default, paginated)
/api/open/v1/calendar-entries/{id}Get a single calendar entry
/api/open/v1/calendar-entriesCreate a calendar entry
/api/open/v1/calendar-entries/{id}Update a calendar entry (partial update)
/api/open/v1/calendar-entries/{id}Delete a calendar entry (returns 204)
Filtering by status
By default, the list returns only published entries. Use the status query parameter to retrieve drafts:
status | Returns |
|---|---|
published (default) | Currently-live content only (published, with a publish time in the past). |
draft | Unpublished content only — drafts, plus items awaiting a scheduled publish. |
all | Every item, regardless of state. |
curl "https://customer.monotree.com/api/open/v1/calendar-entries?status=draft" \
-H "Authorization: Bearer mono_your_token_here"An unrecognised value returns 422. Fetching a single entry by id (GET /calendar-entries/{id}) always works regardless of state. The response has no publication field, so in an all list drafts and published entries look the same.
The list is sorted by starts_at, latest first, and takes the standard page, per_page (max 50) and since parameters (see Pagination).
Create
curl -X POST https://customer.monotree.com/api/open/v1/calendar-entries \
-H "Authorization: Bearer mono_your_token_here" \
-H "Content-Type: application/json" \
-d '{
"title": "Company Holiday",
"starts_at": "2026-06-01",
"starts_time": "09:00",
"ends_at": "2026-06-01",
"ends_time": "17:00",
"body": "Optional description",
"groups": [1, 3],
"calendar_event_type_id": 2,
"mute_notifications": false
}'Instead of body, pass article_id to attach a pre-built standalone article (see Articles) — the two are mutually exclusive.
Published by default — pass is_published: false to create a draft, then publish later via the update endpoint.
calendar_event_type_id must reference an event type from GET /calendar-event-types (422 otherwise). Omitting it is allowed only while a published event type named "Default" exists; otherwise it is required.
Request body
| Field | Type | Notes |
|---|---|---|
title | string | Required. Max 255 characters. |
starts_at | date (YYYY-MM-DD) | Required. |
starts_time | time (HH:MM) | Optional. |
ends_at | date (YYYY-MM-DD) | Optional. Must be on or after starts_at. |
ends_time | time (HH:MM) | Optional. |
body | string or null | Optional. Stored as the entry's article. Max 50,000 characters. Cannot be combined with article_id. |
article_id | integer | Optional. Attach a pre-built standalone article created via POST /articles (create only). An article that already belongs to other content returns 422. |
groups | array of integers | Optional. Group IDs to target. An unknown group ID returns 422. |
calendar_event_type_id | integer | A published event type. Required only when there is no published "Default" type. |
is_published | boolean | Optional. Defaults to true. false creates a draft. |
mute_notifications | boolean | Optional. Defaults to false. See Silent entries. |
cover_media_id | integer or null | Optional. An image uploaded with POST /media by the same token. See Cover image. |
Returns 201 with the entry.
Silent entries
Targeted employees get a notification on the day an entry starts (at 09:00 Copenhagen time unless the entry has its own notification time). Pass "mute_notifications": true to create an entry without that notification, for example when you import many bookings from another system. It only skips the day-of notification for this entry; employees still see it in their calendar. Defaults to false, and you can change it later with PATCH.
Cover image
A calendar entry has at most one cover image. Upload the image with POST /media (type: image) and pass its id as cover_media_id when you create or update the entry.
On update, a new cover_media_id replaces the current cover and "cover_media_id": null removes it. Leaving the field out keeps the cover as it is.
Attaching a cover needs the write:media scope as well as write:calendar_entries (403 otherwise). The media must be an image uploaded by the same token; anything else returns 422 with an error on cover_media_id. Sending the id of the cover the item already has is always accepted, so you can write back what you read.
curl -X PATCH https://customer.monotree.com/api/open/v1/calendar-entries/101 \
-H "Authorization: Bearer mono_your_token_here" \
-H "Content-Type: application/json" \
-d '{ "cover_media_id": 42 }'Update
PATCH accepts the same fields as create (minus article_id, which only attaches an article at create — an update ignores it) — all optional; only the fields you send are changed. PUT is accepted as an alias for backwards compatibility and behaves identically.
calendar_event_type_idcan't be set tonullon update.- An update that sends only
starts_ator onlyends_atis checked against the entry's stored other date. An end before the start returns422withThe end date must be on or after the start date.undererrors.ends_at, or undererrors.starts_atwhen onlystarts_atwas sent. "body": null(or"") clears the body.groupsreplaces the targeted groups;[]removes them all.is_publishedpublishes a draft (true) or takes the entry back to draft (false).- Once the entry's article carries rich content (anything beyond a single paragraph),
bodywrites are rejected (422, error onbody) — usePUT /articles/{id}/elementsinstead.
curl -X PATCH https://customer.monotree.com/api/open/v1/calendar-entries/101 \
-H "Authorization: Bearer mono_your_token_here" \
-H "Content-Type: application/json" \
-d '{ "starts_time": "10:00", "calendar_event_type_id": 2 }'Response
{
"data": {
"id": 101,
"article_id": 93,
"title": "Company Holiday",
"body": null,
"starts_at": "2026-06-01",
"starts_time": "09:00",
"ends_at": "2026-06-01",
"ends_time": "17:00",
"cover_image": null,
"calendar_event_type": { "id": 2, "name": "Kunde information", "translations": { "da": "Kunde information", "en": "Customer information" }, "created_at": "2026-01-10T08:00:00+01:00", "updated_at": "2026-01-10T08:00:00+01:00" },
"author": {
"id": 1,
"name": "John Doe",
"first_name": "John",
"last_name": "Doe",
"title": "HR Manager",
"email": "john@example.com",
"type": "default",
"avatar_url": "https://images.monotree.com/avatars/john-doe.jpg",
"is_manager": false,
"groups": [],
"hired_at": "2025-06-01",
"date_of_birth": "1994-08-12",
"is_away": false,
"last_active_on": "2026-06-01T08:05:12.000000Z",
"registered_at": "2025-06-01T09:00:00+02:00",
"created_at": "2025-06-01T09:00:00+02:00"
},
"groups": [],
"mute_notifications": false,
"created_at": "2026-06-01T10:00:00+02:00",
"updated_at": "2026-06-01T10:00:00+02:00"
}
}starts_time and ends_time are read back with seconds (09:00:00). The create and update responses return a time sent in that request as it was sent (09:00).
calendar_event_type is the same object served by /calendar-event-types, or null when the entry has none.
cover_image is the entry's cover image, in the same shape as GET /media/{id}, or null when it has none.
author is the same user object served by /users. For an entry created through the API it is the token's user, or the system user if the token is configured that way.
body is plain text from the article's first three headers and paragraphs, null when the entry has no article or the article is empty. It is not the full content: read that with GET /articles/{article_id} or GET /articles/{article_id}/markdown.
article_id links the entry's rich content — manage it through the articles endpoints.