Skip to main content

Availability and Calendar API

Two routes read from the same Calendar connector cache but expose deliberately different levels of detail — see Security Posture and the Calendar connector page for why the split exists.

GET /api/availability

Org-internal team free/busy for the Availability surface. Returns busy block times plus per-person sync state — no event titles or details are selected or returned by this route at all, not just hidden in the UI. The query itself only selects busy/free state, scoped to employees (is_employee = true, email matching the internal domain).

GET /api/calendar

Org-internal calendar intelligence from the event-detail cache — titles, attendees, project matching, unmatched-meeting review. This is the route that exposes what /api/availability deliberately withholds, and it is scoped more narrowly as a result (see the Calendar connector page for exactly which roles can see it).

POST /api/calendar

Creates an approval proposal for a calendar write — it never writes to Google directly.

{ "action": "propose_event", "..." : "..." }
{ "action": "override_project", "event_id": "calendar-event-uuid", "project_id": "project-uuid" }
{ "action": "clear_override", "event_id": "calendar-event-uuid" }

patchForManualProjectOverride / patchForClearedProjectOverride write to calendar_event_project_overrides, a table separate from the sync cache, so the next hourly sync doesn't silently erase a human correction. The proposal-shaped actions go through buildCalendarApprovalRow and land in the same approvals queue as every other proposed action — execution happens later, through calendar-act, after a human approves.

Where the code lives

  • sable-agents-demo/web/api/availability.js, _availability.js
  • sable-agents-demo/web/api/calendar.js, _calendar.js
  • sable-agents-demo/web/api/_approvals.jsshapeApproval, shared with the general approvals route