---
title: "Search Calendar Events"
method: POST
path: "/timeoff/calendars/events/search"
tags: ["Calendar events"]
---

# Search Calendar Events

`POST /timeoff/calendars/events/search`

Calendar events are company-wide holidays and closures (and similar events)
that affect work schedules and time off. Use this API to read those events
and keep Bob's external calendars in sync.

Each event is tied to a `calendarId` and `siteId`. To see which calendars and
sites exist in your company (and their IDs), call the
[Get a specific company list by name](https://apidocs.hibob.com/reference/get_company-named-lists-listname)
endpoint with `listName = calendar` or `site`.

**Events for a specific employee**

To get the events that apply to a specific employee, you need to find out the
calendar linked to the employee. The employee uses their site's default holiday
calendar unless a calendar is set on the employment table.

Read the following fields with the
[Search employee by ID](https://apidocs.hibob.com/reference/post_people-identifier)
endpoint (`POST /v1/people/{identifier}`): `payroll.employment.calendarId` and `work.siteId`.

Then fetch the employee's assigned calendar events:
- If `payroll.employment.calendarId` is `null` — filter by `/calendarEvent/siteId` using `work.siteId`.
- If `payroll.employment.calendarId` is set — filter by `/calendarEvent/calendarId` using that value.

**Start date range span:** The mandatory `from` / `to` pair on `/calendarEvent/startDate`
must describe at most **366 calendar days inclusive** (both endpoints count). If the span
is longer, the API returns **400 Bad Request** with key
`exception.calendar.publicApi.dateRangeTooLong`. For multi-year exports, run several
searches (for example one per calendar year or successive 366-day windows) and merge
results client-side.

When a filter uses a `fieldId` that is not supported for search (for example
`/calendarEvent/visibility`), the API returns **400** with key
`exception.calendar.publicApi.unsupportedFilterField` and the rejected path(s) in `args`.

**OAuth scopes (app-user):** `timeoff.calendars:write`.

**IAM permission:** `Settings / Calendars / Manage` (company-scoped).

## Request body

- SearchCalendarEventsInput — Request body for calendar event search. `filters` is required and must always include a date range on `/calendarEvent/startDate` as a `from`/`to` pair (other filters may be added on top). `fields` is optional — omit it to return every field; `limit` and `cursor` are optional and fall back to server-defined paging (see examples for typical payloads).
  - `fields` CalendarEventFieldId[], nullable — List of field IDs to include in each result item (see `CalendarEventFieldId` for the available field IDs — they match the keys on each item in the response). When omitted, all available fields are returned.
  - `filters` SearchFilter[], required — Filters to apply to the search results. You MUST always provide a date range as exactly two filters on `/calendarEvent/startDate` — one with operator `from` and one with operator `to`. Both are mandatory; requests without this pair are rejected with `400 Bad Request`. The inclusive number of days from the `from` date through the `to` date must be between **1** and **366**; otherwise you receive **400** with `exception.calendar.publicApi.invalidDateRange` (empty or inverted range) or `exception.calendar.publicApi.dateRangeTooLong` (more than 366 days). On top of the mandatory date range you may add more optional filters. Any other `fieldId` under `filters` (for example `/calendarEvent/visibility`) is rejected with **400** and `exception.calendar.publicApi.unsupportedFilterField`. Example minimal payload: [{"fieldId":"/calendarEvent/startDate","operator":"from","values":["2024-01-01"]}, {"fieldId":"/calendarEvent/startDate","operator":"to","values":["2024-01-31"]}]
    - `fieldId` '/calendarEvent/startDate' | '/calendarEvent/calendarId' | '/calendarEvent/eventType' | '/calendarEvent/siteId', required — The filter field ID.
    - `operator` string, required — Comparison operator for this filter. The allowed values depend on the `fieldId`: - `/calendarEvent/startDate`: **only** `from` or `to` (paired to form a mandatory inclusive date range — see search operation docs). - `/calendarEvent/calendarId`, `/calendarEvent/siteId`, `/calendarEvent/employeeId`, `/calendarEvent/eventType`: either `equals` (row matches when its value appears in `values`) or `notEqual` (row matches when its value does **not** appear in `values`). Both operators accept one or multiple values and are treated symmetrically as in / not-in. Any other operator (for example `eq`, `in`, `not_equals`, `neq`, `not_in`, `gt`, `lt`) is rejected with **400 Bad Request** and key `exception.calendar.publicApi.unsupportedOperator`.
    - `values` string[], required — Filter values, always sent as JSON strings. - For date filters (`/calendarEvent/startDate` with operator `from` or `to`): provide exactly one ISO 8601 calendar date string `YYYY-MM-DD` (e.g. `"2024-01-31"`) — no time-of-day, no timezone offset. The paired mandatory `from`/`to` range on `startDate` must cover at most **366** inclusive days. - For `/calendarEvent/siteId`: provide one or more site IDs as strings. Use the company sites list endpoint to discover the valid IDs for the company. - For `/calendarEvent/calendarId`: provide one or more holiday calendar IDs as strings. Use the holiday calendars list endpoint to discover the valid IDs for the company. - For `/calendarEvent/employeeId`: provide one or more Bob employee IDs as strings. IDs must be sent as strings even when they look numeric, so that large IDs are not truncated by JSON number precision in clients. - For enum-style filters (`/calendarEvent/eventType`): provide one or more string values from the supported list (see `CalendarEventType`).
  - `limit` integer, nullable — Maximum number of results per page (allowed range 1–500). When omitted, the server applies its own default (often 50).
  - `cursor` string, nullable — Opaque cursor from a previous response's `response_metadata.next_cursor`. Omit on the first request; when present it must be a non-empty opaque token (empty string is not valid).

## Response `200`

Success

- SearchCalendarEventsOutput
  - `items` CalendarEvent[], required — Page of matching calendar events. Each item is keyed by field ID (e.g. `/calendarEvent/id`, `/calendarEvent/name`); only the fields requested in `fields` are populated. Empty when there are no matches.
    - `/calendarEvent/id` string, nullable — Unique identifier of the calendar event. Currently read-only — will be used to reference a specific event when update endpoints become available.
    - `/calendarEvent/name` string, nullable — Display name of the calendar event.
    - `/calendarEvent/startDate` string, nullable — The start date of the event as an ISO 8601 calendar date string (`YYYY-MM-DD`), aligned to the timezone of the event's site (`/calendarEvent/siteId`). No time-of-day or timezone offset is included.
    - `/calendarEvent/endDate` string, nullable — The end date of the event as an ISO 8601 calendar date string (`YYYY-MM-DD`), aligned to the timezone of the event's site (`/calendarEvent/siteId`). No time-of-day or timezone offset is included.
    - `/calendarEvent/datePortion` string, nullable — Indicates which portion of the day the event covers. Possible values: all_day, morning, afternoon.
    - `/calendarEvent/eventSource` 'public_library' | 'manual' — Closed list of supported event sources returned in `/calendarEvent/eventSource`.
    - `/calendarEvent/eventType` 'public_holiday' | 'company_closure' — Closed list of supported event types returned in `/calendarEvent/eventType` (and accepted as filter values for that field).
    - `/calendarEvent/isWorkingDay` boolean, nullable — Whether this event falls on a working day.
    - `/calendarEvent/siteId` string, nullable — The ID of the site associated with this event.
    - `/calendarEvent/calendarId` string, nullable — The ID of the calendar this event belongs to.
    - `/calendarEvent/coverImage` string, nullable — URL of the cover image for the event, if available.
    - `/calendarEvent/visibility` string, nullable — Visibility level of the event (e.g. public, private).
  - `response_metadata` ResponseMetadata, required — Pagination metadata returned on every search response.
    - `next_cursor` string, nullable — Opaque cursor that identifies the start of the next page of results. Pass this value back as `cursor` on the next request to continue paging. `null` on the last page, when there are no more results.

## Other responses

- `400` — Bad request — the request was malformed or missing required parameters
- `401` — Unauthorized — authentication credentials are missing or invalid
- `403` — Forbidden — the authenticated user does not have permission to perform this operation
- `429` — Too many requests — rate limit exceeded, retry after the indicated delay
- `500` — Internal server error — an unexpected error occurred on the server

---

[API](https://skmtc.net/hibob/apis/employee-data-api.md) · [All operations](https://skmtc.net/hibob/apis/employee-data-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/hibob/employee-data-api/revisions/0781ebbdda91/schema)
