Events
Events are company calendar events with date, time, location, and optional group targeting.
Required scope: read:events, write:events.
Publication state
Events have a publication lifecycle so you can stage content for review before it goes live — useful when an automated process (e.g. an AI assistant) drafts events that a human approves later.
An event is always in one of three states:
| State | is_published | published_at | scheduled_at | Visible to employees |
|---|---|---|---|---|
| Draft | false | null | null | No |
| Scheduled | false | null | future timestamp | No (until the scheduled time) |
| Published | true | timestamp | null | Yes |
By default, GET /events lists only published events. Pass ?status=draft to list drafts and scheduled events, or ?status=all for everything (an unrecognised value returns 422). Any event can also be fetched directly with GET /events/{id} regardless of state.
The list is sorted by starts_at, latest first, and takes the standard page, per_page (max 50) and since parameters (see Pagination).
Endpoints
/api/open/v1/eventsList events (published by default, paginated)
/api/open/v1/events/{id}Get a single event (including drafts and scheduled)
/api/open/v1/eventsCreate an event (draft by default)
/api/open/v1/events/{id}Update an event, including its publication state
/api/open/v1/events/{id}Delete an event (returns 204)
Create
By default the event is created as a draft:
curl -X POST https://customer.monotree.com/api/open/v1/events \
-H "Authorization: Bearer mono_your_token_here" \
-H "Content-Type: application/json" \
-d '{
"title": "Team Building Day",
"body": "Join us for a fun day of activities.",
"starts_at": "2026-05-01",
"starts_time": "09:00",
"ends_at": "2026-05-01",
"ends_time": "17:00",
"location": "Main Office",
"groups": [1, 3]
}'Instead of body, pass article_id to attach a pre-built standalone article (see Articles) — the two are mutually exclusive.
To give the event a cover image, upload the image with POST /media and pass its id as cover_media_id (see Cover image).
To publish straight away, add "is_published": true. To schedule publication for a future time, add "publish_at": "2026-04-28T08:00:00+02:00".
Request body
| Field | Type | Notes |
|---|---|---|
title | string | Required. Max 255 characters. |
body | string | Required unless article_id is sent. Description, stored as the event 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. |
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. |
location | string | Optional. Max 255 characters. |
groups | array of integers | Optional. Group IDs to target. Empty/omitted = company-wide. An unknown group ID returns 422. |
cover_media_id | integer or null | Optional. An image uploaded with POST /media by the same token. See Cover image. |
is_published | boolean | Optional. true publishes the event immediately. Defaults to false (draft). |
publish_at | datetime (ISO 8601) | Optional. Schedules publication for a future time. Must be in the future. A time without an offset is read as Copenhagen time. Takes precedence over is_published. |
Returns 201 with the event.
Update
PUT accepts the same fields as create (minus article_id, which only attaches an article at create — an update ignores it). All fields are optional — only what you send is changed.
Use the publication fields to move an event between states:
- Publish a draft now:
{ "is_published": true } - Unpublish (back to draft):
{ "is_published": false } - Schedule a draft:
{ "publish_at": "2026-04-28T08:00:00+02:00" }(the event must be a draft — scheduling an already-published event returns422) - Cancel a pending schedule:
{ "publish_at": null }(keeps the event a draft)
When publish_at is in the request, even as null, is_published is ignored.
An update that sends only starts_at or only ends_at is checked against the event's stored other date. An end before the start returns 422 with The end date must be on or after the start date. under errors.ends_at, or under errors.starts_at when only starts_at was sent.
Once an event's article carries rich content (anything beyond a single paragraph), body writes are rejected (422, error on body) — use PUT /articles/{id}/elements instead.
curl -X PUT https://customer.monotree.com/api/open/v1/events/789 \
-H "Authorization: Bearer mono_your_token_here" \
-H "Content-Type: application/json" \
-d '{ "is_published": true }'Cover image
An event has at most one cover image, shown on the event in the app.
- Upload the image with
POST /media(type: image) to get itsid. - Pass it as
cover_media_idwhen you create or update the event.
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:events (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 PUT https://customer.monotree.com/api/open/v1/events/789 \
-H "Authorization: Bearer mono_your_token_here" \
-H "Content-Type: application/json" \
-d '{ "cover_media_id": 42 }'Response
{
"data": {
"id": 789,
"article_id": 92,
"title": "Team Building Day",
"body": "Join us for a fun day of activities.",
"starts_at": "2026-05-01",
"starts_time": "09:00",
"ends_at": "2026-05-01",
"ends_time": "17:00",
"location": "Main Office",
"cover_image": {
"id": 42,
"type": "image",
"mime_type": "image/jpeg",
"filename": "team-day.jpg",
"size": 123456,
"url": "https://cdn.monotree.dk/.../team-day.jpg",
"width": 1920,
"height": 1080,
"tag": "media",
"created_at": "2026-04-20T09:58:00+02: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-04-20T08:05:12.000000Z",
"registered_at": "2025-06-01T09:00:00+02:00",
"created_at": "2025-06-01T09:00:00+02:00"
},
"groups": [
{ "id": 1, "name": "All Staff", "type": "custom", "created_at": "2026-01-15T10:00:00+01:00" }
],
"is_published": false,
"comments_count": 0,
"completions_count": 0,
"published_at": null,
"scheduled_at": null,
"created_at": "2026-04-20T10:00:00+02:00",
"updated_at": "2026-04-20T10:00:00+02:00"
}
}| Field | Type | Notes |
|---|---|---|
body | string | Plain text from the article's first three headers and paragraphs, "" when the article is empty. Not the full content: read that with GET /articles/{article_id} or GET /articles/{article_id}/markdown. |
author | user object or null | The same user object served by /users. For an event created through the API, the token's user, or the system user if the token is configured that way. |
starts_time, ends_time | string or null | 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). |
cover_image | media object or null | The event's cover image, in the same shape as GET /media/{id}. null when the event has none. |
is_published | boolean | Whether the event is published and visible to employees. |
published_at | datetime or null | When the event was published. null for drafts and scheduled events. |
scheduled_at | datetime or null | When a scheduled draft will be published. null unless a publication is scheduled. |
article_id links the entry's rich content — manage it through the articles endpoints.