---
updatedAt: 2026-07-21T13:41:51.000Z
---

Fetch the complete documentation index at: https://apidocs.hibob.com/llms.txt. Use this file to discover all available pages before exploring further.

# Search Employee Calendars

Resolves which holiday calendar applies to each employee in a single bulk call.

Each employee's effective calendar is computed server-side using the canonical
resolution rule (matches Bob's product behaviour):

1. **Employment override** — if `payroll.employment.calendarId` is set on the
   employee's employment record **and** that calendar currently exists in the
   company, it is returned with `source = employment`.
2. **Site default** — otherwise, the calendar assigned to the employee's site
   is returned with `source = site`.
3. **None** — if neither layer supplies a calendar (no override and the site
   has no calendar configured, or the employee has no site), the item is
   returned with `source = none` and `calendarId` / `calendarName` set to `null`.

**Missing employees:** Employee IDs that don't exist in the caller's company
are silently dropped from `items` (the request does **not** fail). Diff the
requested IDs against the returned `employeeId`s to detect unknowns.

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

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

# OpenAPI definition

```json
{
  "openapi": "3.1.1",
  "info": {
    "title": "Time Off API",
    "contact": {
      "name": "Hi Bob, Inc."
    },
    "description": "Public API for the Calendar Events API.",
    "license": {
      "name": "Proprietary",
      "url": "https://apidocs.hibob.com/docs/api-terms-of-use"
    },
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "https://api.hibob.com/v1",
      "description": "Production"
    },
    {
      "url": "https://api.sandbox.hibob.com/v1",
      "description": "Sandbox"
    }
  ],
  "x-readme": {
    "metrics-enabled": false
  },
  "tags": [
    {
      "name": "Calendar events",
      "description": "Operations for managing Calendar events"
    }
  ],
  "security": [
    {
      "basic": []
    },
    {
      "bearer": []
    }
  ],
  "paths": {
    "/timeoff/calendars/employees/search": {
      "post": {
        "operationId": "post_timeoff-calendars-employees-search",
        "tags": [
          "Calendar events"
        ],
        "summary": "Search Employee Calendars",
        "description": "Resolves which holiday calendar applies to each employee in a single bulk call.\n\nEach employee's effective calendar is computed server-side using the canonical\nresolution rule (matches Bob's product behaviour):\n\n1. **Employment override** — if `payroll.employment.calendarId` is set on the\n   employee's employment record **and** that calendar currently exists in the\n   company, it is returned with `source = employment`.\n2. **Site default** — otherwise, the calendar assigned to the employee's site\n   is returned with `source = site`.\n3. **None** — if neither layer supplies a calendar (no override and the site\n   has no calendar configured, or the employee has no site), the item is\n   returned with `source = none` and `calendarId` / `calendarName` set to `null`.\n\n**Missing employees:** Employee IDs that don't exist in the caller's company\nare silently dropped from `items` (the request does **not** fail). Diff the\nrequested IDs against the returned `employeeId`s to detect unknowns.\n\n**OAuth scopes (app-user):** `timeoff.calendars:write` AND `employee_data:read`.\n\n**IAM permission:** `Settings / Calendars / Manage` (company-scoped).",
        "requestBody": {
          "required": true,
          "description": "Request body for employee-calendar search. `filters` is required and must\nalways include at least one filter on `/employeeCalendar/employeeId` (the\nbatch of employees to resolve). `fields` is optional — omit it to return\nevery field; `limit` and `cursor` are optional and fall back to server\ndefaults (see examples for typical payloads).",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SearchEmployeeCalendarsInput"
              },
              "examples": {
                "singleEmployee": {
                  "summary": "Resolve the calendar for one employee",
                  "description": "Minimal valid request — a single filter on `/employeeCalendar/employeeId`. Returns one item with the resolved `calendarId` and `source`.",
                  "value": {
                    "fields": [
                      "/employeeCalendar/employeeId",
                      "/employeeCalendar/calendarId",
                      "/employeeCalendar/source"
                    ],
                    "filters": [
                      {
                        "fieldId": "/employeeCalendar/employeeId",
                        "operator": "equals",
                        "values": [
                          "3001234567890123456"
                        ]
                      }
                    ],
                    "limit": 100
                  }
                },
                "bulkEmployees": {
                  "summary": "Resolve calendars for a batch of employees",
                  "description": "Bulk lookup — one filter listing every employee to resolve. The endpoint runs the same three DB lookups regardless of batch size, so this scales to thousands of employees in a single request (up to 5000 IDs per request).",
                  "value": {
                    "fields": [
                      "/employeeCalendar/employeeId",
                      "/employeeCalendar/calendarId",
                      "/employeeCalendar/calendarName",
                      "/employeeCalendar/source",
                      "/employeeCalendar/siteId"
                    ],
                    "filters": [
                      {
                        "fieldId": "/employeeCalendar/employeeId",
                        "operator": "equals",
                        "values": [
                          "3001234567890123456",
                          "3001234567890123457",
                          "3001234567890123458"
                        ]
                      }
                    ],
                    "limit": 100
                  }
                },
                "employeesWithOverrideOnly": {
                  "summary": "Only employees with an employment-level override",
                  "description": "Combine the mandatory `employeeId` filter with a `source` filter to keep only employees whose calendar comes from their employment record (not the site default). Useful for auditing explicit overrides.",
                  "value": {
                    "fields": [
                      "/employeeCalendar/employeeId",
                      "/employeeCalendar/calendarId",
                      "/employeeCalendar/source"
                    ],
                    "filters": [
                      {
                        "fieldId": "/employeeCalendar/employeeId",
                        "operator": "equals",
                        "values": [
                          "3001234567890123456",
                          "3001234567890123457"
                        ]
                      },
                      {
                        "fieldId": "/employeeCalendar/source",
                        "operator": "equals",
                        "values": [
                          "employment"
                        ]
                      }
                    ],
                    "limit": 100
                  }
                },
                "nextPageWithCursor": {
                  "summary": "Next page using cursor",
                  "description": "Pass `next_cursor` from a previous response's `response_metadata` to continue pagination. The cursor value is opaque; this string is illustrative. The mandatory `/employeeCalendar/employeeId` filter must still be present on every page.",
                  "value": {
                    "fields": [
                      "/employeeCalendar/employeeId",
                      "/employeeCalendar/calendarId"
                    ],
                    "filters": [
                      {
                        "fieldId": "/employeeCalendar/employeeId",
                        "operator": "equals",
                        "values": [
                          "3001234567890123456",
                          "3001234567890123457",
                          "3001234567890123458",
                          "3001234567890123459"
                        ]
                      }
                    ],
                    "limit": 2,
                    "cursor": "eyJjIjoiZXhhbXBsZS1jdXJzb3IifQ=="
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchEmployeeCalendarsOutput"
                }
              }
            }
          },
          "400": {
            "description": "Bad request — the request was malformed or missing required parameters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized — authentication credentials are missing or invalid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden — the authenticated user does not have permission to perform this operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests — rate limit exceeded, retry after the indicated delay",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error — an unexpected error occurred on the server",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorResponse"
                }
              }
            }
          }
        },
        "x-internal": false
      }
    }
  },
  "components": {
    "securitySchemes": {
      "basic": {
        "type": "http",
        "scheme": "basic"
      },
      "bearer": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "OAuth 2.0",
        "description": "OAuth 2.0 access token issued by HiBob's Authorization Code flow. Approved Marketplace and technology partners install their app from the HiBob Developer Portal, complete the Authorization Code flow against their app's install URL, and exchange the authorization code (with `client_id` + `client_secret`) for an `access_token` (and `refresh_token`). Paste the resulting `access_token` here to call this endpoint from Try It!. <a href=\"https://apidocs.hibob.com/reference/oauth-20\" target=\"_blank\">Learn more about OAuth 2.0 in HiBob</a>"
      }
    },
    "schemas": {
      "ApiErrorResponse": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Stable machine-readable error code"
          },
          "message": {
            "type": "string",
            "description": "Human-readable error message"
          },
          "details": {
            "type": "object",
            "additionalProperties": true,
            "description": "Structured error context keyed by field or domain identifier"
          },
          "request_id": {
            "type": "string",
            "description": "Request identifier for support and tracing"
          }
        }
      },
      "EmployeeCalendar": {
        "type": "object",
        "properties": {
          "/employeeCalendar/employeeId": {
            "type": [
              "string",
              "null"
            ],
            "description": "Identifier of the employee this row resolves the calendar for. Echoed\nback from the requested `employeeId` filter values."
          },
          "/employeeCalendar/calendarId": {
            "type": [
              "string",
              "null"
            ],
            "description": "Identifier of the holiday calendar that applies to this employee, after\nresolution. Sent as a string for consistency with `/calendarEvent/calendarId`\nand to avoid JSON-number precision loss for snowflake-style IDs.\n`null` when `source = none` (no calendar configured)."
          },
          "/employeeCalendar/calendarName": {
            "type": [
              "string",
              "null"
            ],
            "description": "Display name of the resolved calendar. `null` when `calendarId` is `null`."
          },
          "/employeeCalendar/source": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/EmployeeCalendarSource"
              },
              {
                "type": "null"
              }
            ],
            "description": "Where the resolved calendar came from. See `EmployeeCalendarSource` for\nthe full list of supported values (`employment`, `site`, `none`)."
          },
          "/employeeCalendar/siteId": {
            "type": [
              "string",
              "null"
            ],
            "description": "Identifier of the employee's site (independent of which source supplied\nthe calendar). Sent as a string for consistency with `/calendarEvent/siteId`\nand to avoid JSON-number precision loss for snowflake-style IDs.\n`null` when the employee has no site assigned."
          }
        }
      },
      "EmployeeCalendarFieldId": {
        "description": "Field IDs that can be requested in `fields` on the employee-calendar search\nrequest and that appear as keys on each result item. Use these IDs to\nproject a subset of the response and to discover the available\nemployee-calendar fields.",
        "type": "string",
        "enum": [
          "/employeeCalendar/employeeId",
          "/employeeCalendar/calendarId",
          "/employeeCalendar/calendarName",
          "/employeeCalendar/source",
          "/employeeCalendar/siteId"
        ]
      },
      "EmployeeCalendarFilterFieldId": {
        "description": "Field IDs that can be used as `fieldId` on an employee-calendar search filter.\nOnly these paths are applied by the search implementation; other\n`EmployeeCalendarFieldId` values are available in `fields` but must not be\nused as filters.\n\n`EMPLOYEE_ID` is mandatory — every request must include at least one filter\non `/employeeCalendar/employeeId` listing the employees to resolve.",
        "type": "string",
        "enum": [
          "/employeeCalendar/employeeId",
          "/employeeCalendar/calendarId",
          "/employeeCalendar/siteId",
          "/employeeCalendar/source"
        ]
      },
      "EmployeeCalendarSearchFilter": {
        "type": "object",
        "properties": {
          "fieldId": {
            "$ref": "#/components/schemas/EmployeeCalendarFilterFieldId",
            "description": "Field ID to filter by. Must be one of the supported filter field IDs\n(see `EmployeeCalendarFilterFieldId`)."
          },
          "operator": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64,
            "description": "Comparison operator for this filter. Only `equals` is supported for\nevery filter field in this operation."
          },
          "values": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter values, always sent as JSON strings.\n\n**Important:** Some API consoles (including ReadMe \"Try It\") rebuild the request from YAML\nexamples and may drop quotes around large numeric-looking strings, which turns them into\nJSON numbers and breaks this API (and can truncate snowflake-style ids past\n`Number.MAX_SAFE_INTEGER`). If that happens, edit the JSON body so every id is a **string**\n(e.g. `\"3332883884017713938\"`).\n\n- For `/employeeCalendar/employeeId`: provide one or more employee IDs as strings.\n- For `/employeeCalendar/calendarId` and `/employeeCalendar/siteId`: provide one or more\n  IDs as strings, even when they look numeric, so that large IDs are not truncated by\n  JSON number precision in clients.\n- For `/employeeCalendar/source`: provide one or more values from `EmployeeCalendarSource`\n  (`employment`, `site`, `none`)."
          }
        },
        "required": [
          "fieldId",
          "operator",
          "values"
        ]
      },
      "EmployeeCalendarSource": {
        "description": "Closed list of supported sources returned in `/employeeCalendar/source`\n(and accepted as filter values for that field).\n\nReflects the calendar-resolution rule applied per employee:\n`employment` (explicit override on the employment record) takes precedence\nover `site` (inherited from the employee's site); `none` means no calendar\nis configured for the employee.",
        "type": "string",
        "enum": [
          "employment",
          "site",
          "none"
        ]
      },
      "ResponseMetadata": {
        "type": "object",
        "properties": {
          "next_cursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Opaque cursor that identifies the start of the next page of results.\nPass this value back as `cursor` on the next request to continue paging.\n`null` (or absent) when there are no more results."
          }
        }
      },
      "SearchEmployeeCalendarsInput": {
        "description": "Request body for employee-calendar search. `filters` is required and must\nalways include at least one filter on `/employeeCalendar/employeeId` (the\nbatch of employees to resolve). `fields` is optional — omit it to return\nevery field; `limit` and `cursor` are optional and fall back to server\ndefaults (see examples for typical payloads).",
        "type": "object",
        "properties": {
          "fields": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "$ref": "#/components/schemas/EmployeeCalendarFieldId"
            },
            "description": "List of field IDs to include in each result item (see\n`EmployeeCalendarFieldId` for the available field IDs — they match the\nkeys on each item in the response). When omitted, all available fields\nare returned."
          },
          "filters": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmployeeCalendarSearchFilter"
            },
            "minItems": 1,
            "description": "Filters to apply to the search.\n\nYou MUST always provide exactly one filter on `/employeeCalendar/employeeId`\nlisting the employees to resolve. The list of values is deduplicated\nserver-side and may contain at most **5000** employee IDs per request;\notherwise the API returns **400** with key\n`exception.employeeCalendar.publicApi.tooManyEmployeeIds`. Only the\n`equals` operator is supported for this filter.\n\nOn top of the mandatory `employeeId` filter you may add optional filters\nto narrow the results. Supported filter field IDs (see\n`EmployeeCalendarFilterFieldId`):\n`/employeeCalendar/employeeId`, `/employeeCalendar/calendarId`,\n`/employeeCalendar/siteId`, `/employeeCalendar/source`.\n\nAny other `fieldId` under `filters` is rejected with **400** and key\n`exception.employeeCalendar.publicApi.unsupportedFilterField`.\n\nExample minimal payload:\n`[{\"fieldId\":\"/employeeCalendar/employeeId\",\"operator\":\"equals\",\"values\":[\"3001234567890123456\"]}]`"
          },
          "limit": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 1,
            "maximum": 1000,
            "default": 100,
            "description": "Maximum number of results per page (allowed range 1–1000). When omitted,\nthe server applies its own default (100)."
          },
          "cursor": {
            "type": [
              "string",
              "null"
            ],
            "minLength": 1,
            "maxLength": 8192,
            "description": "Opaque cursor from a previous response's `response_metadata.next_cursor`.\nOmit on the first request; when present it must be a non-empty opaque\ntoken (empty string is not valid)."
          }
        },
        "required": [
          "filters"
        ],
        "default": {
          "fields": [
            "/employeeCalendar/employeeId",
            "/employeeCalendar/calendarId",
            "/employeeCalendar/calendarName",
            "/employeeCalendar/source",
            "/employeeCalendar/siteId"
          ],
          "filters": [
            {
              "fieldId": "/employeeCalendar/employeeId",
              "operator": "equals",
              "values": [
                "3001234567890123456"
              ]
            }
          ],
          "limit": 100
        }
      },
      "SearchEmployeeCalendarsOutput": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmployeeCalendar"
            },
            "description": "Page of resolved employee calendars. Each item is keyed by field ID\n(e.g. `/employeeCalendar/employeeId`, `/employeeCalendar/calendarId`);\nonly the fields requested in `fields` are populated.\n\nItems for employees that don't exist in the caller's company are\nsilently omitted (no error). Diff the requested employee IDs against\nthe returned `employeeId`s to detect unknowns."
          },
          "response_metadata": {
            "$ref": "#/components/schemas/ResponseMetadata",
            "description": "Pagination metadata for this page (e.g. cursor for the next page).\nUse the `next_cursor` value to fetch subsequent pages."
          }
        },
        "required": [
          "items",
          "response_metadata"
        ]
      }
    }
  }
}
```