Public holidays for this business's country and state
/api/organization/holidaysSuggestions for the Special hours screen, proxied from date.nager.at and narrowed to the company's own country and state.
Read-only, and it writes nothing. It answers "which dates does your country and state observe"; what the business then does on those dates is a separate, deliberate POST /api/organization/special-hours. Keeping the two apart is what stops a third-party dataset from ever changing a tenant's availability on its own.
Regional filtering is not cosmetic. In 2026 the source returns Anzac Day twice, on 25 April for SA/TAS/VIC and 27 April for NSW/ACT/WA. Unfiltered, a Sydney venue is shown two Anzac Days and one of them is a day it is open. When the company's state cannot be resolved to an ISO 3166-2 code, everything is returned and regionUnknown says so, because hiding a holiday we could not verify is the worse failure of the two.
Only Public holidays are offered; the source also reports Bank, School, Optional, Observance and Authorities days, and a list that offers to close a salon for Groundhog Day is a list nobody trusts again.
Never 5xx on a source failure. A country the source does not cover, a missing country setting and an upstream outage all answer 200 with supported: false and a reason, because the Special hours screen works perfectly well without suggestions and rendering an error over a working feature teaches operators to distrust it. Cached for a week per country-year. Readable by any member.
Authorization
sessionCookie The dashboard's Supabase Auth session cookie, set at sign-in. Large sessions are split across
numbered chunks (…auth-token.0, .1), so treat this as a cookie family rather than one name.
Every request re-validates it against the Auth server (getUser()), never by decoding the cookie
locally: a JWT nothing has checked is not a credential. Tenancy is then read from the verified
app_metadata.company_id claim and enforced by row-level security; it is never read from request
input, on any route, ever.
role (admin / staff) is deliberately not in RLS. It gates specific actions in route code,
the operations marked admin below, so hiding a button in the UI is cosmetic only, and a route's
own check is the enforcement.
In: cookie
Query Parameters
Defaults to the current year. Bounded to last year through three years ahead: the value is interpolated into a URL on a third-party host, so an unbounded one would make this an open proxy.
Response Body
application/json
application/json
application/json
application/json
curl -X GET "https://example.com/api/organization/holidays"{ "supported": true, "reason": "no_country", "country": "string", "state": "string", "regionUnknown": true, "year": 0, "yearRange": { "min": 0, "max": 0 }, "holidays": [ { "date": "2019-08-24", "name": "string", "englishName": "string", "regional": true, "regions": [ "string" ] } ]}Remove a tier (admin, or deposit_staff_editable) DELETE
Same gate as `POST` above. Removing a tier that does not exist is not surfaced as an error the caller needs to react to differently from success.
Switch between the subdomain and the classic /{slug} link as the asserted address (admin) POST
Flips `book_companies.site_subdomain_preferred`. Refuses with 400 rather than a silent no-op if the company has no subdomain provisioned yet: there is nothing this preference could mean before then, and the dashboard control itself is never shown in that state. Not vertical-gated, unlike most of the Website screen's own routes: hospitality can hold a subdomain too (`ensureTenantSubdomainIfEntitled`, `tenant-subdomain.ts`, fires from the Stripe webhook regardless of `business_type`), so this has to be reachable from both engines. Admin-only, same posture the sibling `offline` route takes: this changes what search engines and the dashboard itself treat as this business's real address, a bigger call than the general settings a staff member with `manage_org_settings` can already make. No cache to invalidate, unlike `offline`'s own route: `tenantCanonicalUrl()` reads this column with a plain, uncached read on every call, by design, so there is nothing stale to revalidate.