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:

Stateis_publishedpublished_atscheduled_atVisible to employees
DraftfalsenullnullNo
Scheduledfalsenullfuture timestampNo (until the scheduled time)
PublishedtruetimestampnullYes

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

GET
/api/open/v1/events

List events (published by default, paginated)

GET
/api/open/v1/events/{id}

Get a single event (including drafts and scheduled)

POST
/api/open/v1/events

Create an event (draft by default)

PUT
/api/open/v1/events/{id}

Update an event, including its publication state

DELETE
/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

FieldTypeNotes
titlestringRequired. Max 255 characters.
bodystringRequired unless article_id is sent. Description, stored as the event article. Max 50,000 characters. Cannot be combined with article_id.
article_idintegerOptional. Attach a pre-built standalone article created via POST /articles (create only). An article that already belongs to other content returns 422.
starts_atdate (YYYY-MM-DD)Required.
starts_timetime (HH:MM)Optional.
ends_atdate (YYYY-MM-DD)Optional. Must be on or after starts_at.
ends_timetime (HH:MM)Optional.
locationstringOptional. Max 255 characters.
groupsarray of integersOptional. Group IDs to target. Empty/omitted = company-wide. An unknown group ID returns 422.
cover_media_idinteger or nullOptional. An image uploaded with POST /media by the same token. See Cover image.
is_publishedbooleanOptional. true publishes the event immediately. Defaults to false (draft).
publish_atdatetime (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 returns 422)
  • 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.

  1. Upload the image with POST /media (type: image) to get its id.
  2. Pass it as cover_media_id when 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"
  }
}
FieldTypeNotes
bodystringPlain 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.
authoruser object or nullThe 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_timestring or nullRead 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_imagemedia object or nullThe event's cover image, in the same shape as GET /media/{id}. null when the event has none.
is_publishedbooleanWhether the event is published and visible to employees.
published_atdatetime or nullWhen the event was published. null for drafts and scheduled events.
scheduled_atdatetime or nullWhen 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.