{"openapi":"3.0.3","info":{"title":"Officely API","version":"1.1.0","description":"Workspace-scoped API for Officely integrations. Every request acts on the workspace that owns the API token.\n\n## Authentication\n\nSend the workspace API token as `Authorization: Bearer <token>`. Account admins create and revoke it under Settings → Account & Billing in Officely for Slack or Microsoft Teams. A workspace has one active token at a time, and the full token is shown only once, when it is created.\n\n## Rate limits\n\nLimits apply per token: 10 requests a minute in total, of which at most 5 a minute can go to data endpoints such as `/v1/work-statuses`. Each client IP address is also limited to 120 requests a minute. The CSV exports at `/v1/insights/people` and `/v1/insights/work-statuses` share a limit of 1 request a minute per token. Limits are local to each Cloudflare location, rather than exact global quotas. Requests over a limit get HTTP 429 with a `Retry-After` header giving the seconds to wait.\n\n## Pagination\n\nThe preview work-status endpoint returns `nextCursor` at the top level. Insights and directory lists return it in `meta.page.nextCursor`. Send it back as `cursor`, with the same other parameters, until it is `null`.\n\n## Errors\n\nAPI errors return `{ \"error\": { \"code\": \"...\", \"message\": \"...\" } }`. Branch on `code`, not `message`, and fall back on the HTTP status for a code you don't recognise. Every API response includes an `X-Request-Id` header: quote it when contacting support.\n\n| Code | HTTP status | Meaning |\n| --- | --- | --- |\n| `INVALID_QUERY` | 400 | A report query parameter is invalid. |\n| `INVALID_CURSOR` | 400 | The report cursor is invalid or does not match the query. |\n| `DATE_RANGE_TOO_LARGE` | 422 | The report date range exceeds the supported window. |\n| `EXPORT_TOO_LARGE` | 422 | The CSV exceeds 10,000 rows; narrow the filters or date range. |\n| `INCOMPATIBLE_OFFICE_WEEKDAYS` | 422 | Selected offices must have identical operating weekdays. |\n| `INVALID_REQUEST` | 400 | A query parameter or the cursor is invalid. The message says which. |\n| `UNAUTHORIZED` | 401 | The API token is missing, invalid, or revoked. |\n| `FORBIDDEN` | 403 | The request is not allowed, for example from a browser origin without CORS access. |\n| `NOT_FOUND` | 404 | The endpoint does not exist. |\n| `METHOD_NOT_ALLOWED` | 405 | The endpoint only supports GET. |\n| `RATE_LIMITED` | 429 | Too many requests. Wait for the number of seconds in Retry-After. |\n| `INTERNAL_ERROR` | 500 | An unexpected error. Retry later, and quote X-Request-Id if it persists. |\n| `BAD_GATEWAY` | 502 | The API could not reach its backend. Retry later. |\n| `SERVICE_UNAVAILABLE` | 503 | The API is temporarily disabled. Retry later. |\n\n## Preview endpoints\n\nEndpoints marked *preview* are in early release. Their fields and behaviour may change before they are marked stable."},"tags":[{"name":"Offices","description":"Offices in the workspace."},{"name":"Work statuses","description":"Detailed status rows and bookings exports."},{"name":"Insights","description":"Calculated office and people reports."},{"name":"Directory","description":"People and team lookup data."}],"servers":[{"url":"https://api.getofficely.com","description":"Production"},{"url":"https://api.development.getofficely.com","description":"Staging"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Workspace-owned API token with workspace-wide reporting access. The workspace is derived from the verified token. Office, team, and person filters narrow results; they are not delegated authorization scopes."}},"headers":{"RequestId":{"description":"Unique identifier for this request. Quote it when contacting support.","schema":{"type":"string","example":"62685d9b-fc09-419b-b254-7710a652d66f"}}},"schemas":{"DateRange":{"type":"object","additionalProperties":false,"required":["from","to","days"],"properties":{"from":{"type":"string","description":"Calendar date in YYYY-MM-DD form.","format":"date"},"to":{"type":"string","description":"Calendar date in YYYY-MM-DD form.","format":"date"},"days":{"type":"integer","minimum":1,"description":"Inclusive number of calendar days.","maximum":366}}},"Selection":{"type":"object","additionalProperties":false,"required":["officeIds","teamIds","userIds"],"properties":{"officeIds":{"type":"array","items":{"type":"string","description":"Opaque identifier within the authenticated workspace.","minLength":1,"maxLength":150}},"teamIds":{"type":"array","items":{"type":"string","description":"Opaque identifier within the authenticated workspace.","minLength":1,"maxLength":150}},"userIds":{"type":"array","items":{"type":"string","description":"Opaque identifier within the authenticated workspace.","minLength":1,"maxLength":150}}},"description":"Normalized requested filters. An empty array means that filter was not supplied. Arrays contain IDs, not expanded membership. Team membership is evaluated when generated; it is not historical membership."},"Meta":{"type":"object","additionalProperties":false,"required":["generatedAt","referenceDate","selection"],"properties":{"generatedAt":{"type":"string","format":"date-time"},"referenceDate":{"type":"string","description":"Calendar date in YYYY-MM-DD form.","format":"date"},"selection":{"$ref":"#/components/schemas/Selection"}},"description":"All dates and relative metrics are anchored to referenceDate. generatedAt is response generation time, not a guarantee about source-data freshness."},"Page":{"type":"object","additionalProperties":false,"required":["limit","nextCursor","totalCount"],"properties":{"limit":{"type":"integer","minimum":1,"maximum":500},"nextCursor":{"type":"string","nullable":true},"totalCount":{"type":"integer","minimum":0}},"description":"totalCount counts all rows matching this JSON query. nextCursor is null on the final page. Stable sort always uses an opaque ID tie-breaker; work-status rows use date, userId, type, officeId."},"ListMeta":{"type":"object","additionalProperties":false,"required":["generatedAt","referenceDate","selection","page"],"properties":{"generatedAt":{"type":"string","format":"date-time"},"referenceDate":{"type":"string","description":"Calendar date in YYYY-MM-DD form.","format":"date"},"selection":{"$ref":"#/components/schemas/Selection"},"page":{"$ref":"#/components/schemas/Page"}}},"OfficeReportMeta":{"type":"object","additionalProperties":false,"required":["generatedAt","referenceDate","selection","range","comparisonRange","workingWeekdays"],"properties":{"generatedAt":{"type":"string","format":"date-time"},"referenceDate":{"type":"string","description":"Calendar date in YYYY-MM-DD form.","format":"date"},"selection":{"$ref":"#/components/schemas/Selection"},"range":{"$ref":"#/components/schemas/DateRange"},"comparisonRange":{"$ref":"#/components/schemas/DateRange"},"workingWeekdays":{"type":"array","items":{"type":"string","enum":["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"]},"uniqueItems":true}},"description":"The comparison is the immediately preceding period of equal inclusive length. workingWeekdays is the common operating-weekday set used as denominator across the selected offices."},"WorkStatusMeta":{"type":"object","additionalProperties":false,"required":["generatedAt","referenceDate","selection","page","range","types","includeArchived"],"properties":{"generatedAt":{"type":"string","format":"date-time"},"referenceDate":{"type":"string","description":"Calendar date in YYYY-MM-DD form.","format":"date"},"selection":{"$ref":"#/components/schemas/Selection"},"page":{"$ref":"#/components/schemas/Page"},"range":{"$ref":"#/components/schemas/DateRange"},"types":{"type":"array","items":{"type":"string"}},"includeArchived":{"type":"boolean"}}},"AttendanceMeta":{"type":"object","additionalProperties":false,"required":["generatedAt","referenceDate","selection","fromMonth","toMonth"],"properties":{"generatedAt":{"type":"string","format":"date-time"},"referenceDate":{"type":"string","description":"Calendar date in YYYY-MM-DD form.","format":"date"},"selection":{"$ref":"#/components/schemas/Selection"},"fromMonth":{"type":"string","description":"Calendar date in YYYY-MM-DD form.","format":"date"},"toMonth":{"type":"string","description":"Calendar date in YYYY-MM-DD form.","format":"date"}}},"IdName":{"type":"object","additionalProperties":false,"required":["id","name"],"properties":{"id":{"type":"string","description":"Opaque identifier within the authenticated workspace.","minLength":1,"maxLength":150},"name":{"type":"string"}}},"PersonReference":{"type":"object","additionalProperties":false,"required":["id","name","email"],"properties":{"id":{"type":"string","description":"Opaque identifier within the authenticated workspace.","minLength":1,"maxLength":150},"name":{"type":"string"},"email":{"type":"string","format":"email","nullable":true}}},"User":{"type":"object","additionalProperties":false,"required":["id","platform","platformUserId","name","email","avatarUrl","homeOfficeId","teamIds","isOfficelyUser","state","invitedAt","onboardedAt"],"properties":{"id":{"type":"string","description":"Opaque identifier within the authenticated workspace.","minLength":1,"maxLength":150},"platform":{"type":"string","enum":["slack","ms_teams"]},"platformUserId":{"type":"string","description":"Underlying Slack or Microsoft user ID. Older records can have a different public id; use id in API paths and filters."},"name":{"type":"string"},"email":{"type":"string","format":"email","nullable":true},"avatarUrl":{"type":"string","format":"uri","nullable":true},"homeOfficeId":{"type":"string","nullable":true},"teamIds":{"type":"array","items":{"type":"string","description":"Opaque identifier within the authenticated workspace.","minLength":1,"maxLength":150}},"isOfficelyUser":{"type":"boolean"},"state":{"type":"string","enum":["active","archived","deactivated"]},"invitedAt":{"type":"string","format":"date-time","nullable":true},"onboardedAt":{"type":"string","format":"date-time","nullable":true}},"description":"homeOfficeId is the first configured office, matching the current people-table population filter. Non-onboarded Slack directory users may appear only when explicitly requested. Teams can return only known users. Unavailable profile values are null."},"Team":{"type":"object","additionalProperties":false,"required":["id","name","memberIds","managerIds"],"properties":{"id":{"type":"string","description":"Opaque identifier within the authenticated workspace.","minLength":1,"maxLength":150},"name":{"type":"string"},"memberIds":{"type":"array","items":{"type":"string","description":"Opaque identifier within the authenticated workspace.","minLength":1,"maxLength":150}},"managerIds":{"type":"array","items":{"type":"string","description":"Opaque identifier within the authenticated workspace.","minLength":1,"maxLength":150}}},"description":"Current membership. Lists of teams are paginated; one team record contains its full membership."},"CountComparison":{"type":"object","additionalProperties":false,"required":["value","previousValue","changePercent"],"properties":{"value":{"type":"integer","minimum":0},"previousValue":{"type":"integer","minimum":0},"changePercent":{"type":"number","nullable":true}},"description":"changePercent = ceil((value - previousValue) / previousValue * 1000) / 10, matching current office-report upward rounding. Both zero gives 0; a positive value with a zero baseline gives null."},"AverageComparison":{"type":"object","additionalProperties":false,"required":["value","previousValue","changePercent"],"properties":{"value":{"type":"number","minimum":0},"previousValue":{"type":"number","minimum":0},"changePercent":{"type":"number","nullable":true}},"description":"Values are people/day, rounded upward to one decimal using the selected working weekdays in the corresponding range. changePercent compares current and previous total booking counts, not the rounded averages, matching the existing card; it is rounded upward to one decimal. Both zero gives 0; a positive value with a zero baseline gives null."},"DailyBookings":{"type":"object","additionalProperties":false,"required":["date","bookedCount"],"properties":{"date":{"type":"string","description":"Calendar date in YYYY-MM-DD form.","format":"date"},"bookedCount":{"type":"integer","minimum":0}},"description":"One row for every date in the requested range, including zero-booking days."},"WeekdayAverage":{"type":"object","additionalProperties":false,"required":["weekday","bookedCount","workingDayCount","averageBookedCount"],"properties":{"weekday":{"type":"string","enum":["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"]},"bookedCount":{"type":"integer","minimum":0},"workingDayCount":{"type":"integer","minimum":0},"averageBookedCount":{"type":"number","minimum":0}},"description":"One row per configured operating weekday, Monday to Sunday. averageBookedCount is ceil(bookedCount / workingDayCount * 10) / 10, or 0 when workingDayCount is zero."},"OfficeInsights":{"type":"object","additionalProperties":false,"required":["totalOfficeUsers","totalBookings","averageDailyUsage","mostPopularDay","attendance","averageNumberOfPeoplePerDay"],"properties":{"totalOfficeUsers":{"$ref":"#/components/schemas/CountComparison"},"totalBookings":{"$ref":"#/components/schemas/CountComparison"},"averageDailyUsage":{"$ref":"#/components/schemas/AverageComparison"},"mostPopularDay":{"type":"string","enum":["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"],"nullable":true},"attendance":{"type":"array","items":{"$ref":"#/components/schemas/DailyBookings"}},"averageNumberOfPeoplePerDay":{"type":"array","items":{"$ref":"#/components/schemas/WeekdayAverage"}}},"description":"Booking-based metrics, independent of check-in confirmation. totalOfficeUsers counts distinct people across selected offices; totalBookings counts person/office/date rows. mostPopularDay uses weekday averages and the earliest weekday to break ties, or null when there are no bookings. totalBookings.changePercent carries the dashboard Office attendance card."},"WeeklyTotal":{"type":"object","additionalProperties":false,"required":["weekStarting","bookedDays"],"properties":{"weekStarting":{"type":"string","description":"Calendar date in YYYY-MM-DD form.","format":"date"},"bookedDays":{"type":"integer","minimum":0}},"description":"weekStarting is Monday. Includes the current ISO week and up to 26 preceding ISO weeks, with zero rows after the person joined. Days at different offices on the same date count once."},"TrendPoint":{"type":"object","additionalProperties":false,"required":["from","to","bookedDays"],"properties":{"from":{"type":"string","description":"Calendar date in YYYY-MM-DD form.","format":"date"},"to":{"type":"string","description":"Calendar date in YYYY-MM-DD form.","format":"date"},"bookedDays":{"type":"integer","minimum":0}},"description":"One of six rolling 30-day trend windows matching the current mini chart: each end date is referenceDate minus n calendar months, n=5..0; each start is end minus 30 days. Sum weekly totals whose Monday falls in that inclusive window. These are not calendar-month totals."},"UserAttendanceStats":{"type":"object","additionalProperties":false,"required":["daysInThisWeek","currentWeekOfficeDays","fourWeekRolling","fourWeekAverage","fourWeekPercentageChanged","regularWeekdays","weeklyTotals","sixMonthTrend"],"properties":{"daysInThisWeek":{"type":"integer","minimum":0},"currentWeekOfficeDays":{"type":"array","items":{"type":"string","enum":["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"]}},"fourWeekRolling":{"type":"integer","minimum":0},"fourWeekAverage":{"type":"number","minimum":0},"fourWeekPercentageChanged":{"type":"number"},"regularWeekdays":{"type":"array","items":{"type":"string","enum":["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"]},"uniqueItems":true},"weeklyTotals":{"type":"array","items":{"$ref":"#/components/schemas/WeeklyTotal"}},"sixMonthTrend":{"type":"array","items":{"$ref":"#/components/schemas/TrendPoint"},"minItems":6,"maxItems":6}},"description":"fourWeekRolling counts the four completed ISO weeks before referenceDate, excluding the current week. fourWeekAverage is the average of completed weekly totals over up to 26 weeks since joining, projected to four weeks and rounded to two decimals; fewer than four completed weeks gives 0. fourWeekPercentageChanged is rounded to one decimal and is 0 when the average is 0, matching the people report. Current-week fields include scheduled days through Sunday, including future days in that week. regularWeekdays is the mode of known office-booking weekdays; ties are Monday to Sunday. Empty data returns zero metrics and empty arrays, with six zero-valued trend points."},"PersonInsights":{"type":"object","additionalProperties":false,"required":["user","attendanceStats"],"properties":{"user":{"$ref":"#/components/schemas/User"},"attendanceStats":{"$ref":"#/components/schemas/UserAttendanceStats"}}},"MonthOfficeAttendance":{"type":"object","additionalProperties":false,"required":["office","dates","bookedDays"],"properties":{"office":{"$ref":"#/components/schemas/IdName"},"dates":{"type":"array","items":{"type":"string","description":"Calendar date in YYYY-MM-DD form.","format":"date"},"uniqueItems":true},"bookedDays":{"type":"integer","minimum":0}},"description":"Dates are sorted ascending and use the office-local date. Missing or renamed resources retain their ID; name uses the current label, or the ID when unavailable."},"MonthlyAttendance":{"type":"object","additionalProperties":false,"required":["monthStarting","bookedDays","offices"],"properties":{"monthStarting":{"type":"string","description":"Calendar date in YYYY-MM-DD form.","format":"date"},"bookedDays":{"type":"integer","minimum":0},"offices":{"type":"array","items":{"$ref":"#/components/schemas/MonthOfficeAttendance"}}},"description":"monthStarting is the first day of the month. bookedDays counts distinct dates across offices; summing office counts can count a date twice if source data contains multiple offices. Includes zero months."},"UserAttendance":{"type":"object","additionalProperties":false,"required":["userId","months"],"properties":{"userId":{"type":"string","description":"Opaque identifier within the authenticated workspace.","minLength":1,"maxLength":150},"months":{"type":"array","items":{"$ref":"#/components/schemas/MonthlyAttendance"}}}},"WorkStatusType":{"type":"string","description":"Stable built-in status key. Display labels can be customized per workspace. noStatus is omitted from this resource.","enum":["office","remote","nonWorkingDay","offSick","annualLeave","otherAbsence","workTravel","clientOffice"]},"Neighbourhood":{"type":"object","additionalProperties":false,"required":["id","name","category"],"properties":{"id":{"type":"string","description":"Opaque identifier within the authenticated workspace.","minLength":1,"maxLength":150},"name":{"type":"string"},"category":{"type":"string","nullable":true}}},"InsightsWorkStatus":{"description":"Discriminated office or non-office work-status row. Conditions on office resources and check-ins are enforced by the schema.","oneOf":[{"$ref":"#/components/schemas/OfficeWorkStatus"},{"$ref":"#/components/schemas/NonOfficeWorkStatus"}],"discriminator":{"propertyName":"type","mapping":{"office":"#/components/schemas/OfficeWorkStatus","remote":"#/components/schemas/NonOfficeWorkStatus","nonWorkingDay":"#/components/schemas/NonOfficeWorkStatus","offSick":"#/components/schemas/NonOfficeWorkStatus","annualLeave":"#/components/schemas/NonOfficeWorkStatus","otherAbsence":"#/components/schemas/NonOfficeWorkStatus","workTravel":"#/components/schemas/NonOfficeWorkStatus","clientOffice":"#/components/schemas/NonOfficeWorkStatus"}}},"OfficeWorkStatus":{"type":"object","additionalProperties":false,"required":["date","weekday","user","type","typeName","office","neighbourhood","extras","guestEmails","note","checkIn"],"properties":{"date":{"type":"string","description":"Calendar date in YYYY-MM-DD form.","format":"date"},"weekday":{"type":"string","enum":["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"]},"user":{"$ref":"#/components/schemas/PersonReference"},"type":{"type":"string","enum":["office"]},"typeName":{"type":"string","description":"Current workspace-configured status label, used in the CSV Type column."},"office":{"$ref":"#/components/schemas/IdName"},"neighbourhood":{"oneOf":[{"$ref":"#/components/schemas/Neighbourhood"},{"type":"object","nullable":true,"enum":[null]}]},"extras":{"type":"array","items":{"$ref":"#/components/schemas/IdName"}},"guestEmails":{"type":"array","items":{"type":"string","format":"email"}},"note":{"type":"string"},"checkIn":{"type":"string","enum":["checked_in","not_checked_in","not_enabled"]}},"description":"One current derived work-status row per person/date, not a change log. Key is date + user.id; no invented standalone booking ID. Office status has an office; other statuses have null office and neighbourhood, empty extras and guestEmails, and not_applicable checkIn. Office check-ins disabled gives not_enabled, otherwise checked_in/not_checked_in. Notes and guest emails match export visibility. Resource names reflect current configuration; unavailable labels fall back to IDs. No absence-reason detail or survey answers are included."},"NonOfficeWorkStatus":{"type":"object","additionalProperties":false,"required":["date","weekday","user","type","typeName","office","neighbourhood","extras","guestEmails","note","checkIn"],"properties":{"date":{"type":"string","description":"Calendar date in YYYY-MM-DD form.","format":"date"},"weekday":{"type":"string","enum":["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"]},"user":{"$ref":"#/components/schemas/PersonReference"},"type":{"type":"string","enum":["remote","nonWorkingDay","offSick","annualLeave","otherAbsence","workTravel","clientOffice"]},"typeName":{"type":"string","description":"Current workspace-configured status label, used in the CSV Type column."},"office":{"type":"object","nullable":true,"enum":[null]},"neighbourhood":{"type":"object","nullable":true,"enum":[null]},"extras":{"type":"array","items":{"$ref":"#/components/schemas/IdName"},"maxItems":0},"guestEmails":{"type":"array","items":{"type":"string","format":"email"},"maxItems":0},"note":{"type":"string"},"checkIn":{"type":"string","enum":["not_applicable"]}},"description":"One current derived work-status row per person/date, not a change log. Key is date + user.id; no invented standalone booking ID. Office status has an office; other statuses have null office and neighbourhood, empty extras and guestEmails, and not_applicable checkIn. Office check-ins disabled gives not_enabled, otherwise checked_in/not_checked_in. Notes and guest emails match export visibility. Resource names reflect current configuration; unavailable labels fall back to IDs. No absence-reason detail or survey answers are included."},"ApiError":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","description":"Stable machine-readable error code; branch on this rather than message. Currently one of INVALID_QUERY, INVALID_CURSOR, DATE_RANGE_TOO_LARGE, EXPORT_TOO_LARGE, INCOMPATIBLE_OFFICE_WEEKDAYS, INVALID_REQUEST, UNAUTHORIZED, FORBIDDEN, NOT_FOUND, METHOD_NOT_ALLOWED, RATE_LIMITED, INTERNAL_ERROR, BAD_GATEWAY, SERVICE_UNAVAILABLE. New codes may be added, so fall back on the HTTP status for any you don't recognise."},"message":{"type":"string","description":"Human-readable explanation of the error."}},"required":["code","message"],"description":"What went wrong."}},"required":["error"],"additionalProperties":false},"OfficeInsightsResponse":{"type":"object","additionalProperties":false,"required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/OfficeInsights"},"meta":{"$ref":"#/components/schemas/OfficeReportMeta"}}},"PeopleInsightsResponse":{"type":"object","additionalProperties":false,"required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PersonInsights"}},"meta":{"$ref":"#/components/schemas/ListMeta"}}},"PersonInsightsResponse":{"type":"object","additionalProperties":false,"required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/PersonInsights"},"meta":{"$ref":"#/components/schemas/Meta"}}},"UserAttendanceResponse":{"type":"object","additionalProperties":false,"required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/UserAttendance"},"meta":{"$ref":"#/components/schemas/AttendanceMeta"}}},"WorkStatusesResponse":{"type":"object","additionalProperties":false,"required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/InsightsWorkStatus"}},"meta":{"$ref":"#/components/schemas/WorkStatusMeta"}}},"UsersResponse":{"type":"object","additionalProperties":false,"required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/User"}},"meta":{"$ref":"#/components/schemas/ListMeta"}}},"TeamsResponse":{"type":"object","additionalProperties":false,"required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Team"}},"meta":{"$ref":"#/components/schemas/ListMeta"}}},"ListOfficesResponse":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Stable identifier of the office within this workspace."},"name":{"type":"string","description":"Display name of the office."},"emoji":{"type":"string","description":"Emoji used to represent the office."},"timezone":{"type":"string","description":"IANA time zone used by the office."},"country":{"type":"string","description":"Country of the office."}},"required":["id","name","emoji","timezone","country"],"additionalProperties":false,"description":"An office visible to the workspace that owns the API token."},"description":"Offices in the authenticated workspace."}},"required":["data"],"additionalProperties":false},"WorkStatus":{"type":"object","properties":{"date":{"type":"string","description":"Calendar date the status applies to (YYYY-MM-DD)."},"user":{"type":"object","properties":{"id":{"type":"string","description":"Stable identifier of the user within this workspace."},"name":{"type":"string","nullable":true,"description":"Display name, or null if the user no longer exists."},"email":{"type":"string","nullable":true,"description":"Email address, or null if unknown or the user no longer exists."}},"required":["id","name","email"],"additionalProperties":false,"description":"The person the status belongs to."},"status":{"type":"string","enum":["office","remote","nonWorkingDay","offSick","annualLeave","otherAbsence","workTravel","clientOffice"],"description":"Stable status value. Use statusLabel for the name this workspace displays."},"statusLabel":{"type":"string","description":"Name this workspace displays for the status. Workspaces can rename statuses."},"office":{"type":"object","nullable":true,"properties":{"id":{"type":"string","description":"Stable identifier of the office."},"name":{"type":"string","nullable":true,"description":"Office name, or null if the office has since been deleted."}},"required":["id","name"],"additionalProperties":false,"description":"The booked office. Null unless status is office."},"neighbourhood":{"type":"object","nullable":true,"properties":{"id":{"type":"string","description":"Stable identifier of the neighbourhood."},"name":{"type":"string","nullable":true,"description":"Neighbourhood name, or null if it has since been deleted."},"category":{"type":"string","nullable":true,"description":"Neighbourhood category, or null if it has none."}},"required":["id","name","category"],"additionalProperties":false,"description":"The booked neighbourhood, or null if none was booked."},"extras":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Stable identifier of the extra."},"name":{"type":"string","nullable":true,"description":"Extra name, or null if it has since been deleted."}},"required":["id","name"],"additionalProperties":false},"description":"Extras booked for the day, such as parking."},"guests":{"type":"array","items":{"type":"string"},"description":"Email addresses of guests the user invited for the day."},"note":{"type":"string","nullable":true,"description":"The user's note for the day."},"checkedIn":{"type":"boolean","nullable":true,"description":"Whether the user checked in. Null unless status is office and the office has check-ins enabled."},"waitlisted":{"type":"boolean","description":"True when the user is on the office waitlist for the day rather than holding a confirmed booking."}},"required":["date","user","status","statusLabel","office","neighbourhood","extras","guests","note","checkedIn","waitlisted"],"additionalProperties":false,"description":"One user's status on one day."},"ListWorkStatusesResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WorkStatus"},"description":"Records ordered by date, then user ID."},"nextCursor":{"type":"string","nullable":true,"description":"Pass as cursor to fetch the next page. Null on the last page."}},"required":["data","nextCursor"],"additionalProperties":false}},"parameters":{"OfficeIds":{"name":"officeIds","in":"query","required":false,"description":"OR within the list. Office reports use bookings in these offices. People reports filter population by homeOfficeId AND metrics by these offices. Work statuses filter office rows only; non-office rows remain. Omitted means all eligible workspace offices.","schema":{"type":"array","items":{"type":"string","description":"Opaque identifier within the authenticated workspace.","minLength":1,"maxLength":150},"minItems":1,"maxItems":20,"uniqueItems":true},"style":"form","explode":false},"TeamIds":{"name":"teamIds","in":"query","required":false,"description":"OR within the list, using current membership. Intersects with userIds when both are supplied. Unknown or cross-workspace IDs return 404.","schema":{"type":"array","items":{"type":"string","description":"Opaque identifier within the authenticated workspace.","minLength":1,"maxLength":150},"minItems":1,"maxItems":20,"uniqueItems":true},"style":"form","explode":false},"UserIds":{"name":"userIds","in":"query","required":false,"description":"OR within the list. Intersects with current team membership when teamIds is supplied. Unknown or cross-workspace IDs return 404.","schema":{"type":"array","items":{"type":"string","description":"Opaque identifier within the authenticated workspace.","minLength":1,"maxLength":150},"minItems":1,"maxItems":100,"uniqueItems":true},"style":"form","explode":false},"ReferenceDate":{"name":"referenceDate","in":"query","required":false,"description":"Defaults to the current UTC calendar date. Anchors preset periods, completed-week metrics and monthly defaults. Future dates are rejected. Echoed in meta; repeat it on subsequent cursor requests.","schema":{"type":"string","description":"Calendar date in YYYY-MM-DD form.","format":"date"}},"Period":{"name":"period","in":"query","required":false,"description":"Preset windows end on referenceDate and include it. from/to are required together for custom and forbidden with a preset. Maximum 366 calendar days inclusive.","schema":{"type":"string","enum":["7_days","30_days","90_days","custom"],"default":"30_days"}},"From":{"name":"from","in":"query","required":false,"description":"Inclusive office-local date label. Required with to when period=custom; otherwise forbidden.","schema":{"type":"string","description":"Calendar date in YYYY-MM-DD form.","format":"date"}},"To":{"name":"to","in":"query","required":false,"description":"Inclusive office-local date label. Required with from when period=custom; otherwise forbidden. Must be >= from.","schema":{"type":"string","description":"Calendar date in YYYY-MM-DD form.","format":"date"}},"StatusFrom":{"name":"from","in":"query","required":true,"description":"Inclusive date label. Required with to; ranges cannot exceed 366 calendar days.","schema":{"type":"string","description":"Calendar date in YYYY-MM-DD form.","format":"date"}},"StatusTo":{"name":"to","in":"query","required":true,"description":"Inclusive date label. Must be >= from. Future bookings may be requested, up to 366 days after referenceDate.","schema":{"type":"string","description":"Calendar date in YYYY-MM-DD form.","format":"date"}},"FromMonth":{"name":"fromMonth","in":"query","required":false,"description":"First day of a calendar month. Defaults to referenceDate minus 11 months, at month start. Must be paired with toMonth when supplied.","schema":{"type":"string","description":"Calendar date in YYYY-MM-DD form.","format":"date"}},"ToMonth":{"name":"toMonth","in":"query","required":false,"description":"First day of a calendar month. Defaults to referenceDate month start. Up to 12 months inclusive. Contains no dates after the Sunday of referenceDate ISO week, matching current monthly detail; explicit future months are rejected.","schema":{"type":"string","description":"Calendar date in YYYY-MM-DD form.","format":"date"}},"Limit":{"name":"limit","in":"query","required":false,"description":"JSON page size. Forbidden for CSV, which returns the complete filtered export within the export cap.","schema":{"type":"integer","minimum":1,"maximum":500,"default":100}},"Cursor":{"name":"cursor","in":"query","required":false,"description":"Opaque JSON continuation token. Bound to workspace, endpoint, normalized filters, sorting and referenceDate. Invalid/mismatched cursors return 400 INVALID_CURSOR. Forbidden for CSV. Changes in source data may affect later pages; this is not an immutable snapshot.","schema":{"type":"string","minLength":1,"maxLength":4096}},"SortBy":{"name":"sortBy","in":"query","required":false,"description":"People sort key; ties use user.id ascending. Nulls sort last in either direction.","schema":{"type":"string","enum":["name","daysInThisWeek","fourWeekRolling","fourWeekPercentageChanged"],"default":"name"}},"SortOrder":{"name":"sortOrder","in":"query","required":false,"description":"Sort direction; ID tie-breakers stay ascending.","schema":{"type":"string","enum":["asc","desc"],"default":"asc"}},"Format":{"name":"format","in":"query","required":false,"description":"CSV exports the full filtered result, with no cursor or limit parameters. Maximum 10,000 rows and 366 days; an oversized export returns 422 EXPORT_TOO_LARGE before any CSV bytes. Errors always use application/json. CSV sort uses the same sort controls as JSON.","schema":{"type":"string","enum":["json","csv"],"default":"json"}},"IncludeNonOfficely":{"name":"includeNonOfficelyUsers","in":"query","required":false,"description":"Include eligible directory users who have not onboarded to Officely. Slack can use directory data; Teams includes only users known to Officely. Cannot be true for people CSV, matching the current export.","schema":{"type":"boolean","default":false}},"IncludeArchived":{"name":"includeArchived","in":"query","required":false,"description":"Include known archived or platform-deactivated people in directory and work-status results. false matches current report population. Cannot be true for people CSV.","schema":{"type":"boolean","default":false}},"Search":{"name":"q","in":"query","required":false,"description":"Case-insensitive substring search across name and email, after other filters. Whitespace is trimmed.","schema":{"type":"string","minLength":1,"maxLength":100}},"Types":{"name":"types","in":"query","required":false,"description":"Optional status keys. OR within this list, AND with person filters. noStatus cannot be requested.","schema":{"type":"array","items":{"$ref":"#/components/schemas/WorkStatusType"},"minItems":1,"maxItems":8,"uniqueItems":true},"style":"form","explode":false},"UserPath":{"name":"userId","in":"path","required":true,"description":"Opaque person ID in the authenticated workspace.","schema":{"type":"string","description":"Opaque identifier within the authenticated workspace.","minLength":1,"maxLength":150}}},"responses":{"400":{"description":"Malformed query; invalid calendar date, unknown query parameter, conflicting range selectors, oversized filter lists, or invalid/mismatched cursor. Codes: INVALID_QUERY, INVALID_CURSOR.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":{"code":"INVALID_QUERY","message":"The query parameters are invalid."}}}}},"401":{"description":"A valid API token is required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":{"code":"UNAUTHORIZED","message":"A valid API token is required."}}}}},"403":{"description":"The token cannot access this report.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":{"code":"FORBIDDEN","message":"The token cannot access this report."}}}}},"404":{"description":"The resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":{"code":"NOT_FOUND","message":"The resource was not found."}}}}},"405":{"description":"Only GET requests are supported.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":{"code":"METHOD_NOT_ALLOWED","message":"Only GET requests are supported."}}}}},"422":{"description":"Well-formed query cannot be fulfilled: EXPORT_TOO_LARGE; DATE_RANGE_TOO_LARGE; INCOMPATIBLE_OFFICE_WEEKDAYS. JSON error is returned before writing CSV bytes.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":{"code":"EXPORT_TOO_LARGE","message":"The export exceeds the synchronous row limit. Narrow the date range or person filters."}}}}},"429":{"description":"Too many requests. Try again later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests. Try again later."}}}},"headers":{"Retry-After":{"description":"Seconds until retry.","schema":{"type":"integer","minimum":1}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":{"code":"INTERNAL_ERROR","message":"Internal server error."}}}}},"502":{"description":"API origin is unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":{"code":"BAD_GATEWAY","message":"API origin is unavailable."}}}}},"503":{"description":"API is unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":{"code":"SERVICE_UNAVAILABLE","message":"API is unavailable."}}}}}},"examples":{"OfficeInsightsExample":{"summary":"Synthetic example; no customer data.","value":{"data":{"totalOfficeUsers":{"value":1,"previousValue":1,"changePercent":0},"totalBookings":{"value":2,"previousValue":2,"changePercent":0},"averageDailyUsage":{"value":0.4,"previousValue":0.4,"changePercent":0},"mostPopularDay":"Monday","attendance":[{"date":"2026-10-09","bookedCount":0},{"date":"2026-10-10","bookedCount":0},{"date":"2026-10-11","bookedCount":0},{"date":"2026-10-12","bookedCount":1},{"date":"2026-10-13","bookedCount":0},{"date":"2026-10-14","bookedCount":0},{"date":"2026-10-15","bookedCount":1}],"averageNumberOfPeoplePerDay":[{"weekday":"Monday","bookedCount":1,"workingDayCount":1,"averageBookedCount":1},{"weekday":"Tuesday","bookedCount":0,"workingDayCount":1,"averageBookedCount":0},{"weekday":"Wednesday","bookedCount":0,"workingDayCount":1,"averageBookedCount":0},{"weekday":"Thursday","bookedCount":1,"workingDayCount":1,"averageBookedCount":1},{"weekday":"Friday","bookedCount":0,"workingDayCount":1,"averageBookedCount":0}]},"meta":{"generatedAt":"2026-10-15T12:00:00Z","referenceDate":"2026-10-15","selection":{"officeIds":["office_london"],"teamIds":[],"userIds":[]},"range":{"from":"2026-10-09","to":"2026-10-15","days":7},"comparisonRange":{"from":"2026-10-02","to":"2026-10-08","days":7},"workingWeekdays":["Monday","Tuesday","Wednesday","Thursday","Friday"]}}},"PeopleInsightsExample":{"summary":"Synthetic example; no customer data.","value":{"data":[{"user":{"id":"usr_alex","platform":"slack","platformUserId":"usr_alex","name":"Alex Morgan","email":"alex@example.com","avatarUrl":null,"homeOfficeId":"office_london","teamIds":["team_product"],"isOfficelyUser":true,"state":"active","invitedAt":"2026-09-13T10:00:00Z","onboardedAt":"2026-09-14T09:00:00Z"},"attendanceStats":{"daysInThisWeek":2,"currentWeekOfficeDays":["Monday","Thursday"],"fourWeekRolling":8,"fourWeekAverage":8,"fourWeekPercentageChanged":0,"regularWeekdays":["Monday","Thursday"],"weeklyTotals":[{"weekStarting":"2026-09-14","bookedDays":2},{"weekStarting":"2026-09-21","bookedDays":2},{"weekStarting":"2026-09-28","bookedDays":2},{"weekStarting":"2026-10-05","bookedDays":2},{"weekStarting":"2026-10-12","bookedDays":2}],"sixMonthTrend":[{"from":"2026-04-15","to":"2026-05-15","bookedDays":0},{"from":"2026-05-16","to":"2026-06-15","bookedDays":0},{"from":"2026-06-15","to":"2026-07-15","bookedDays":0},{"from":"2026-07-16","to":"2026-08-15","bookedDays":0},{"from":"2026-08-16","to":"2026-09-15","bookedDays":2},{"from":"2026-09-15","to":"2026-10-15","bookedDays":8}]}}],"meta":{"generatedAt":"2026-10-15T12:00:00Z","referenceDate":"2026-10-15","selection":{"officeIds":[],"teamIds":[],"userIds":[]},"page":{"limit":100,"nextCursor":null,"totalCount":1}}}},"PersonInsightsExample":{"summary":"Synthetic example; no customer data.","value":{"data":{"user":{"id":"usr_alex","platform":"slack","platformUserId":"usr_alex","name":"Alex Morgan","email":"alex@example.com","avatarUrl":null,"homeOfficeId":"office_london","teamIds":["team_product"],"isOfficelyUser":true,"state":"active","invitedAt":"2026-09-13T10:00:00Z","onboardedAt":"2026-09-14T09:00:00Z"},"attendanceStats":{"daysInThisWeek":2,"currentWeekOfficeDays":["Monday","Thursday"],"fourWeekRolling":8,"fourWeekAverage":8,"fourWeekPercentageChanged":0,"regularWeekdays":["Monday","Thursday"],"weeklyTotals":[{"weekStarting":"2026-09-14","bookedDays":2},{"weekStarting":"2026-09-21","bookedDays":2},{"weekStarting":"2026-09-28","bookedDays":2},{"weekStarting":"2026-10-05","bookedDays":2},{"weekStarting":"2026-10-12","bookedDays":2}],"sixMonthTrend":[{"from":"2026-04-15","to":"2026-05-15","bookedDays":0},{"from":"2026-05-16","to":"2026-06-15","bookedDays":0},{"from":"2026-06-15","to":"2026-07-15","bookedDays":0},{"from":"2026-07-16","to":"2026-08-15","bookedDays":0},{"from":"2026-08-16","to":"2026-09-15","bookedDays":2},{"from":"2026-09-15","to":"2026-10-15","bookedDays":8}]}},"meta":{"generatedAt":"2026-10-15T12:00:00Z","referenceDate":"2026-10-15","selection":{"officeIds":[],"teamIds":[],"userIds":[]}}}},"UserAttendanceExample":{"summary":"Synthetic example; no customer data.","value":{"data":{"userId":"usr_alex","months":[{"monthStarting":"2026-10-01","bookedDays":5,"offices":[{"office":{"id":"office_london","name":"London"},"dates":["2026-10-01","2026-10-05","2026-10-08","2026-10-12","2026-10-15"],"bookedDays":5}]}]},"meta":{"generatedAt":"2026-10-15T12:00:00Z","referenceDate":"2026-10-15","selection":{"officeIds":["office_london"],"teamIds":[],"userIds":[]},"fromMonth":"2026-10-01","toMonth":"2026-10-01"}}},"WorkStatusesExample":{"summary":"Synthetic example; no customer data.","value":{"data":[{"date":"2026-10-14","weekday":"Wednesday","user":{"id":"usr_alex","name":"Alex Morgan","email":"alex@example.com"},"type":"remote","typeName":"Working remotely","office":null,"neighbourhood":null,"extras":[],"guestEmails":[],"note":"","checkIn":"not_applicable"},{"date":"2026-10-15","weekday":"Thursday","user":{"id":"usr_alex","name":"Alex Morgan","email":"alex@example.com"},"type":"office","typeName":"Office","office":{"id":"office_london","name":"London"},"neighbourhood":{"id":"nbh_product","name":"Product","category":"Teams"},"extras":[{"id":"extra_monitor","name":"Monitor"}],"guestEmails":["guest@example.com"],"note":"Customer workshop","checkIn":"checked_in"}],"meta":{"generatedAt":"2026-10-15T12:00:00Z","referenceDate":"2026-10-15","selection":{"officeIds":["office_london"],"teamIds":[],"userIds":[]},"page":{"limit":100,"nextCursor":null,"totalCount":2},"range":{"from":"2026-10-14","to":"2026-10-15","days":2},"types":[],"includeArchived":false}}},"UsersExample":{"summary":"Synthetic example; no customer data.","value":{"data":[{"id":"usr_alex","platform":"slack","platformUserId":"usr_alex","name":"Alex Morgan","email":"alex@example.com","avatarUrl":null,"homeOfficeId":"office_london","teamIds":["team_product"],"isOfficelyUser":true,"state":"active","invitedAt":"2026-09-13T10:00:00Z","onboardedAt":"2026-09-14T09:00:00Z"}],"meta":{"generatedAt":"2026-10-15T12:00:00Z","referenceDate":"2026-10-15","selection":{"officeIds":[],"teamIds":[],"userIds":[]},"page":{"limit":100,"nextCursor":null,"totalCount":1}}}},"TeamsExample":{"summary":"Synthetic example; no customer data.","value":{"data":[{"id":"team_product","name":"Product","memberIds":["usr_alex"],"managerIds":["usr_alex"]}],"meta":{"generatedAt":"2026-10-15T12:00:00Z","referenceDate":"2026-10-15","selection":{"officeIds":[],"teamIds":[],"userIds":[]},"page":{"limit":100,"nextCursor":null,"totalCount":1}}}}}},"paths":{"/v1/offices":{"get":{"operationId":"listOffices","tags":["Offices"],"summary":"List offices","description":"Returns offices belonging to the workspace that owns the API token.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"The workspace offices.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListOfficesResponse"},"example":{"data":[{"id":"k7Qe2vXbN9pL4tRw8sYcZ","name":"London HQ","emoji":"🏢","timezone":"Europe/London","country":"United Kingdom"}]}}}},"401":{"description":"The API token is missing, invalid, or revoked.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":{"code":"UNAUTHORIZED","message":"A valid API token is required."}}}}},"429":{"description":"The request rate limit was exceeded.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"Retry-After":{"description":"Seconds to wait before retrying the request.","schema":{"type":"integer","minimum":0}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests. Try again later."}}}}},"default":{"description":"Any other error. The error code says which; see Errors in the API description.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":{"code":"INTERNAL_ERROR","message":"Internal server error."}}}}}}}},"/v1/work-statuses":{"get":{"operationId":"listWorkStatuses","tags":["Work statuses"],"summary":"List work statuses (preview)","description":"**Preview:** this endpoint is in early release, and its fields and behaviour may change before it is marked stable.\n\nReturns each user's status per day in the workspace that owns the API token: office bookings, remote days, leave and other statuses, matching the Insights bookings export. Days without a status are omitted. Records are ordered by date, then user ID; follow nextCursor until it is null. Records have no change timestamp, so to stay in sync re-fetch a rolling window (for example the last 7 days and the next 30) and upsert on date and user.id.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"First date to include (YYYY-MM-DD)."},"required":true,"description":"First date to include (YYYY-MM-DD).","example":"2026-10-01","name":"from","in":"query"},{"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"Last date to include (YYYY-MM-DD). The range may cover at most 31 days."},"required":true,"description":"Last date to include (YYYY-MM-DD). The range may cover at most 31 days.","example":"2026-10-31","name":"to","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1},"maxItems":30,"description":"Only return office records at these offices; other statuses are excluded. Repeat the parameter for more than one office."},"required":false,"description":"Only return office records at these offices; other statuses are excluded. Repeat the parameter for more than one office.","name":"officeId","in":"query"},{"schema":{"type":"array","items":{"type":"string","enum":["office","remote","nonWorkingDay","offSick","annualLeave","otherAbsence","workTravel","clientOffice"],"description":"Stable status value. Use statusLabel for the name this workspace displays."},"description":"Only return these statuses. Repeat the parameter for more than one status."},"required":false,"description":"Only return these statuses. Repeat the parameter for more than one status.","name":"status","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":1000,"default":500,"description":"Maximum number of records to return."},"required":false,"description":"Maximum number of records to return.","example":500,"name":"limit","in":"query"},{"schema":{"type":"string","minLength":1,"description":"The nextCursor from the previous page. Send it with the same other parameters."},"required":false,"description":"The nextCursor from the previous page. Send it with the same other parameters.","name":"cursor","in":"query"}],"responses":{"200":{"description":"A page of work statuses.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListWorkStatusesResponse"},"example":{"data":[{"date":"2026-10-01","user":{"id":"U04QX7M2K9P","name":"Ada Lovelace","email":"ada@example.com"},"status":"office","statusLabel":"Office","office":{"id":"k7Qe2vXbN9pL4tRw8sYcZ","name":"London HQ"},"neighbourhood":{"id":"Hn3T8wQy1mVb6RkZp0LdA","name":"Engineering","category":"Floor 2"},"extras":[{"id":"PARKING","name":"Parking"}],"guests":["visitor@partner.example"],"note":"Desk 12, near the window","checkedIn":true,"waitlisted":false},{"date":"2026-10-01","user":{"id":"U05BN3R8T1W","name":"Grace Hopper","email":"grace@example.com"},"status":"remote","statusLabel":"Home","office":null,"neighbourhood":null,"extras":[],"guests":[],"note":null,"checkedIn":null,"waitlisted":false}],"nextCursor":"eyJkIjoiMjAyNi0xMC0wMSIsInUiOiJVMDVCTjNSOFQxVyJ9"}}}},"400":{"description":"A query parameter or the cursor is invalid.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":{"code":"INVALID_REQUEST","message":"Invalid query parameter 'from': Required."}}}}},"401":{"description":"The API token is missing, invalid, or revoked.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":{"code":"UNAUTHORIZED","message":"A valid API token is required."}}}}},"429":{"description":"The request rate limit was exceeded.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"Retry-After":{"description":"Seconds to wait before retrying the request.","schema":{"type":"integer","minimum":0}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests. Try again later."}}}}},"default":{"description":"Any other error. The error code says which; see Errors in the API description.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":{"code":"INTERNAL_ERROR","message":"Internal server error."}}}}}}}},"/v1/insights/offices":{"get":{"operationId":"getOfficeInsights","tags":["Insights"],"summary":"Office dashboard metrics","description":"Aggregates selected offices and people into the existing office dashboard cards and chart series. If officeIds is omitted, use all current offices. Team/person filters constrain bookings; distinct users are counted across the selected offices. No eligible records gives a zero report and null mostPopularDay. Names, membership and operating weekdays use current configuration.","x-rate-limit-tier":"standard","parameters":[{"$ref":"#/components/parameters/OfficeIds"},{"$ref":"#/components/parameters/TeamIds"},{"$ref":"#/components/parameters/UserIds"},{"$ref":"#/components/parameters/ReferenceDate"},{"$ref":"#/components/parameters/Period"},{"$ref":"#/components/parameters/From"},{"$ref":"#/components/parameters/To"}],"responses":{"200":{"description":"Success. All documented object properties are required unless stated otherwise. Null indicates an unavailable or inapplicable value.","headers":{"Cache-Control":{"description":"Always no-store for customer data.","schema":{"type":"string","enum":["no-store"]}},"X-Request-Id":{"description":"Request correlation ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OfficeInsightsResponse"},"examples":{"example":{"$ref":"#/components/examples/OfficeInsightsExample"}}}}},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"403":{"$ref":"#/components/responses/403"},"404":{"$ref":"#/components/responses/404"},"405":{"$ref":"#/components/responses/405"},"422":{"$ref":"#/components/responses/422"},"429":{"$ref":"#/components/responses/429"},"500":{"$ref":"#/components/responses/500"},"502":{"$ref":"#/components/responses/502"},"503":{"$ref":"#/components/responses/503"}},"x-query-rules":["period=custom requires both from and to; presets forbid from and to.","Ranges are inclusive, from <= to, and at most 366 days.","All selected offices must have identical operating weekdays; otherwise return 422 INCOMPATIBLE_OFFICE_WEEKDAYS. Zero eligible offices returns an empty/zero report with an empty workingWeekdays array."]}},"/v1/insights/people":{"get":{"operationId":"listPeopleInsights","tags":["Insights"],"summary":"People dashboard and recent activity export","description":"Lists eligible people and their booking-based attendance statistics. The JSON response contains the data needed for the people table and its trend chart. CSV matches the current Recent activity export and contains only onboarded, active Officely users. Relative metrics are anchored to referenceDate; a date-range picker does not change these fixed reporting windows. CSV is the complete filtered result, not the first JSON page.","x-rate-limit-tier":"standard","parameters":[{"$ref":"#/components/parameters/OfficeIds"},{"$ref":"#/components/parameters/TeamIds"},{"$ref":"#/components/parameters/UserIds"},{"$ref":"#/components/parameters/ReferenceDate"},{"$ref":"#/components/parameters/Search"},{"$ref":"#/components/parameters/IncludeNonOfficely"},{"$ref":"#/components/parameters/IncludeArchived"},{"$ref":"#/components/parameters/SortBy"},{"$ref":"#/components/parameters/SortOrder"},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Format"}],"responses":{"200":{"description":"Success. All documented object properties are required unless stated otherwise. Null indicates an unavailable or inapplicable value.","headers":{"Cache-Control":{"description":"Always no-store for customer data.","schema":{"type":"string","enum":["no-store"]}},"X-Request-Id":{"description":"Request correlation ID.","schema":{"type":"string","format":"uuid"}},"Content-Disposition":{"description":"Present for CSV. attachment; filename=\"officely_<report>_<range>.csv\"","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PeopleInsightsResponse"},"examples":{"example":{"$ref":"#/components/examples/PeopleInsightsExample"}}},"text/csv":{"schema":{"type":"string"},"example":"Name,Email,User ID,Number of Days this Week,Last Four Weeks,Last Four Weeks vs Average (%)\r\nAlex Morgan,alex@example.com,usr_alex,2,8,0\r\n"}}},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"403":{"$ref":"#/components/responses/403"},"404":{"$ref":"#/components/responses/404"},"405":{"$ref":"#/components/responses/405"},"422":{"$ref":"#/components/responses/422"},"429":{"$ref":"#/components/responses/429"},"500":{"$ref":"#/components/responses/500"},"502":{"$ref":"#/components/responses/502"},"503":{"$ref":"#/components/responses/503"}},"x-query-rules":["CSV forbids cursor and limit; includeNonOfficelyUsers and includeArchived must be false.","JSON supports all documented population filters; CSV applies the narrower active/onboarded export population.","CSV has at most 10,000 rows and never silently truncates."],"x-csv-rate-limit-tier":"bulk"}},"/v1/insights/people/{userId}":{"get":{"operationId":"getPersonInsights","tags":["Insights"],"summary":"Individual people summary","description":"Returns profile, fixed rolling metrics, weekly totals, usual weekdays, and six trend points. officeIds narrows the attendance calculations, not access to the requested person; this detail route does not enforce the home-office population filter. A known person with no bookings has zero statistics. Monthly date-level history is provided by the attendance endpoint. Archived known people are readable on this explicit detail route.","x-rate-limit-tier":"standard","parameters":[{"$ref":"#/components/parameters/UserPath"},{"$ref":"#/components/parameters/OfficeIds"},{"$ref":"#/components/parameters/ReferenceDate"}],"responses":{"200":{"description":"Success. All documented object properties are required unless stated otherwise. Null indicates an unavailable or inapplicable value.","headers":{"Cache-Control":{"description":"Always no-store for customer data.","schema":{"type":"string","enum":["no-store"]}},"X-Request-Id":{"description":"Request correlation ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PersonInsightsResponse"},"examples":{"example":{"$ref":"#/components/examples/PersonInsightsExample"}}}}},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"403":{"$ref":"#/components/responses/403"},"404":{"$ref":"#/components/responses/404"},"405":{"$ref":"#/components/responses/405"},"422":{"$ref":"#/components/responses/422"},"429":{"$ref":"#/components/responses/429"},"500":{"$ref":"#/components/responses/500"},"502":{"$ref":"#/components/responses/502"},"503":{"$ref":"#/components/responses/503"}}}},"/v1/insights/people/{userId}/attendance":{"get":{"operationId":"getPersonAttendance","tags":["Insights"],"summary":"Monthly office attendance dates","description":"Returns up to 12 inclusive calendar months, newest month first. Within each month, offices sort by ID and dates ascend. Months without bookings remain present. Date labels are office-local. The default includes the reference month and 11 preceding months. This follows the current monthly detail cutoff: bookings through the Sunday of referenceDate ISO week, capped by the requested month range; future days in that week can appear. Count unique person/date days at the month level.","x-rate-limit-tier":"standard","parameters":[{"$ref":"#/components/parameters/UserPath"},{"$ref":"#/components/parameters/OfficeIds"},{"$ref":"#/components/parameters/ReferenceDate"},{"$ref":"#/components/parameters/FromMonth"},{"$ref":"#/components/parameters/ToMonth"}],"responses":{"200":{"description":"Success. All documented object properties are required unless stated otherwise. Null indicates an unavailable or inapplicable value.","headers":{"Cache-Control":{"description":"Always no-store for customer data.","schema":{"type":"string","enum":["no-store"]}},"X-Request-Id":{"description":"Request correlation ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserAttendanceResponse"},"examples":{"example":{"$ref":"#/components/examples/UserAttendanceExample"}}}}},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"403":{"$ref":"#/components/responses/403"},"404":{"$ref":"#/components/responses/404"},"405":{"$ref":"#/components/responses/405"},"422":{"$ref":"#/components/responses/422"},"429":{"$ref":"#/components/responses/429"},"500":{"$ref":"#/components/responses/500"},"502":{"$ref":"#/components/responses/502"},"503":{"$ref":"#/components/responses/503"}},"x-query-rules":["fromMonth and toMonth must be supplied together and must each be the first day of a real calendar month.","fromMonth <= toMonth, with no more than 12 calendar months inclusive.","Explicit toMonth after the reference month is rejected."]}},"/v1/insights/work-statuses":{"get":{"operationId":"listInsightsWorkStatuses","tags":["Work statuses"],"summary":"Detailed work statuses and bookings export","description":"Returns current derived status rows over a bounded date range. Includes office and non-office statuses; noStatus is omitted. Office filters remove office rows outside the selected offices while retaining non-office rows, matching the current Bookings export. Use types=office for office bookings only. Dates ascend, then user.id, type, and office.id, with missing office sorting first. Customer fields include the names, email, extras, guest emails, notes and check-in information already included in the export. This endpoint is a read-only snapshot and does not create or update users.","x-rate-limit-tier":"standard","parameters":[{"$ref":"#/components/parameters/OfficeIds"},{"$ref":"#/components/parameters/TeamIds"},{"$ref":"#/components/parameters/UserIds"},{"$ref":"#/components/parameters/ReferenceDate"},{"$ref":"#/components/parameters/StatusFrom"},{"$ref":"#/components/parameters/StatusTo"},{"$ref":"#/components/parameters/Types"},{"$ref":"#/components/parameters/IncludeArchived"},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Format"}],"responses":{"200":{"description":"Success. All documented object properties are required unless stated otherwise. Null indicates an unavailable or inapplicable value.","headers":{"Cache-Control":{"description":"Always no-store for customer data.","schema":{"type":"string","enum":["no-store"]}},"X-Request-Id":{"description":"Request correlation ID.","schema":{"type":"string","format":"uuid"}},"Content-Disposition":{"description":"Present for CSV. attachment; filename=\"officely_<report>_<range>.csv\"","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkStatusesResponse"},"examples":{"example":{"$ref":"#/components/examples/WorkStatusesExample"}}},"text/csv":{"schema":{"type":"string"},"example":"Date,Name,Email,Type,Office,Neighbourhood,NeighbourhoodCategory,Extras,Guests,Notes,Checked In\r\n2026-10-14,Alex Morgan,alex@example.com,Working remotely,,,,,,,\r\n2026-10-15,Alex Morgan,alex@example.com,Office,London,Product,Teams,Monitor,guest@example.com,Customer workshop,Yes\r\n"}}},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"403":{"$ref":"#/components/responses/403"},"404":{"$ref":"#/components/responses/404"},"405":{"$ref":"#/components/responses/405"},"422":{"$ref":"#/components/responses/422"},"429":{"$ref":"#/components/responses/429"},"500":{"$ref":"#/components/responses/500"},"502":{"$ref":"#/components/responses/502"},"503":{"$ref":"#/components/responses/503"}},"x-query-rules":["from and to are both required, from <= to, at most 366 inclusive days.","to cannot be more than 366 days after referenceDate.","CSV forbids cursor and limit. It returns all filtered rows up to 10,000; overflow is 422 EXPORT_TOO_LARGE."],"x-csv-rate-limit-tier":"bulk"}},"/v1/users":{"get":{"operationId":"listUsers","tags":["Directory"],"summary":"People directory","description":"Lists users with identity and onboarding information. Supports searching and current home-office/team/person filters. Active onboarded users are the default population. includeNonOfficelyUsers adds eligible Slack directory users; on Teams only known users are available. includeArchived adds known archived or platform-deactivated users. Sort is name ascending, then id. This read must not create missing Officely users.","x-rate-limit-tier":"light","parameters":[{"$ref":"#/components/parameters/OfficeIds"},{"$ref":"#/components/parameters/TeamIds"},{"$ref":"#/components/parameters/UserIds"},{"$ref":"#/components/parameters/ReferenceDate"},{"$ref":"#/components/parameters/Search"},{"$ref":"#/components/parameters/IncludeNonOfficely"},{"$ref":"#/components/parameters/IncludeArchived"},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"}],"responses":{"200":{"description":"Success. All documented object properties are required unless stated otherwise. Null indicates an unavailable or inapplicable value.","headers":{"Cache-Control":{"description":"Always no-store for customer data.","schema":{"type":"string","enum":["no-store"]}},"X-Request-Id":{"description":"Request correlation ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsersResponse"},"examples":{"example":{"$ref":"#/components/examples/UsersExample"}}}}},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"403":{"$ref":"#/components/responses/403"},"404":{"$ref":"#/components/responses/404"},"405":{"$ref":"#/components/responses/405"},"422":{"$ref":"#/components/responses/422"},"429":{"$ref":"#/components/responses/429"},"500":{"$ref":"#/components/responses/500"},"502":{"$ref":"#/components/responses/502"},"503":{"$ref":"#/components/responses/503"}}}},"/v1/teams":{"get":{"operationId":"listTeams","tags":["Directory"],"summary":"Team directory and current membership","description":"Lists current teams and membership for the authenticated workspace, sorted by name then id. teamIds optionally selects explicit teams. Member IDs can include people not returned by the default active/onboarded people query. Team membership is current and must not be interpreted as historical membership on a booking date.","x-rate-limit-tier":"light","parameters":[{"$ref":"#/components/parameters/TeamIds"},{"$ref":"#/components/parameters/ReferenceDate"},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"}],"responses":{"200":{"description":"Success. All documented object properties are required unless stated otherwise. Null indicates an unavailable or inapplicable value.","headers":{"Cache-Control":{"description":"Always no-store for customer data.","schema":{"type":"string","enum":["no-store"]}},"X-Request-Id":{"description":"Request correlation ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamsResponse"},"examples":{"example":{"$ref":"#/components/examples/TeamsExample"}}}}},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"403":{"$ref":"#/components/responses/403"},"404":{"$ref":"#/components/responses/404"},"405":{"$ref":"#/components/responses/405"},"422":{"$ref":"#/components/responses/422"},"429":{"$ref":"#/components/responses/429"},"500":{"$ref":"#/components/responses/500"},"502":{"$ref":"#/components/responses/502"},"503":{"$ref":"#/components/responses/503"}}}}},"security":[{"bearerAuth":[]}]}