Skip to content

On-Call Schedules

Alga supports multi-layer on-call schedules with follow-the-sun restrictions and overrides.

Schedule Structure

A schedule's display name is derived dynamically from its owning team — no name field is stored on the schedule itself. There is exactly one schedule per team, auto-provisioned when the team is created.

Each schedule has one or more layers that define rotating on-call coverage. A layer carries:

FieldDescription
nameDisplay name for the layer (e.g., "Primary", "Secondary")
rotation_typeweekly, daily, or custom
rotation_intervalHow many units of rotation_type per shift (e.g., 2 for bi-weekly)
start_dateWhen the rotation begins (RFC3339)
end_dateOptional end; the layer stops resolving after this
timezoneIANA timezone the layer's windows are interpreted in (default UTC)
start_time / end_timeDaily active window as HH:MM in the layer's timezone; empty end_time means active all day
days_of_weekActive days (empty means every day)
priorityHigher-priority layers win when multiple layers are active
user_idsOrdered list of users in the rotation

When more than one layer is active at a given moment, the layer with the highest priority determines who is on call. Users added to a layer must be members of the schedule's team and must have a phone number on file.

Overrides

Temporary schedule changes can be created via overrides. An override records user_id, start_at, end_at, and created_by:

  • Covers a specific time range
  • Takes absolute precedence over every layer — while an override is active, the override's user is on call regardless of layer priority or rotation
  • Useful for PTO, sick days, or manual coverage swaps

Viewing On-Call Status

Who is On-Call Now?

  • Global: GET /api/v1/on-call/who-is-on-call — All schedules' current on-call
  • Per Schedule: GET /api/v1/on-call/schedules/{id}/current — Specific schedule
  • My Shifts: GET /api/v1/on-call/me — Current/pending shifts for the logged-in user

Timeline

GET /api/v1/on-call/schedules/{id}/timeline — Shows next N rotations

Handoffs

On-call handoffs formalize the transfer of pager responsibility between responders. Each handoff record includes:

  • Outgoing / Incoming user — the responder ending their shift and the one taking over
  • Handoff time (handoff_at) — when the transfer occurs
  • Statuspending until the incoming responder acknowledges, then acknowledged
  • Outgoing notes — context from the outgoing responder (open issues, items to watch); editable only by the outgoing user
  • Incoming notes — notes from the incoming responder; editable only by the incoming user
  • Incident summary — a snapshot of active incidents at handoff time

Handoffs ensure continuity of on-call coverage and reduce the risk of dropped context during shift transitions. Only the incoming user can acknowledge a handoff, and pending handoffs are surfaced prominently so nothing falls through the cracks.

Pager Load Metrics

Track on-call burden per shift to identify overloaded responders and optimize rotation design. GET /api/v1/on-call/metrics requires schedule_id, start_date, and end_date (RFC3339) query parameters and returns per-shift statistics:

  • Alerts received / acknowledged / resolved / missed — alert volume and outcomes during each shift
  • Average ack time (avg_ack_time_seconds) — mean time to acknowledge during the shift
  • Summarytotal_shifts, avg_ack_rate, and avg_ack_time_seconds across the range

Pass group_by=user to aggregate shifts per responder instead of per shift.

API Endpoints

Schedule Management

Note: Schedules are auto-provisioned one-per-team. Creating a team (POST /api/v1/teams) automatically creates its on-call schedule. Schedules cannot be created directlyPOST /api/v1/on-call/schedules returns HTTP 405 with the message "schedules are auto-created from teams and cannot be created directly." Only GET and PATCH work on /api/v1/on-call/schedules/{id}.

MethodPathAuthPermissionDescription
GET/api/v1/on-call/schedulesSessiononcall:readList schedules
GET/api/v1/on-call/schedules/{id}Sessiononcall:readGet schedule with layers
PATCH/api/v1/on-call/schedules/{id}Sessiononcall:writeUpdate schedule
DELETE/api/v1/on-call/schedules/{id}Sessiononcall:writeDelete schedule

On-Call Lookup

MethodPathAuthPermissionDescription
GET/api/v1/on-call/who-is-on-callSessiononcall:readGlobal on-call status
GET/api/v1/on-call/meSessiononcall:readMy current/pending shifts
GET/api/v1/on-call/my-on-callSessiononcall:readAlias for /on-call/me
GET/api/v1/on-call/schedules/{id}/currentSessiononcall:readCurrent on-call for schedule
GET/api/v1/on-call/schedules/{id}/timelineSessiononcall:readNext N rotations
GET/api/v1/on-call/schedules/{id}/icalSessiononcall:readExport shifts as iCalendar (.ics)

Overrides

MethodPathAuthPermissionDescription
GET/api/v1/on-call/schedules/{id}/overridesSessiononcall:readList overrides
POST/api/v1/on-call/schedules/{id}/overridesSessiononcall:writeCreate override
DELETE/api/v1/on-call/overrides/{id}Sessiononcall:writeDelete override

Handoffs

MethodPathAuthPermissionDescription
GET/api/v1/on-call/handoffsSessiononcall:readList handoffs
GET/api/v1/on-call/handoffs/{id}Sessiononcall:readGet handoff
GET/api/v1/on-call/handoffs/pendingSessiononcall:readPending handoffs
POST/api/v1/on-call/handoffs/{id}/notesSessiononcall:writeSave notes (outgoing_notes or incoming_notes)
POST/api/v1/on-call/handoffs/{id}/acknowledgeSessiononcall:writeAcknowledge

Pager Load Metrics

MethodPathAuthPermissionDescription
GET/api/v1/on-call/metricsSessiononcall:readPager load metrics

Agent API

MethodPathAuthDescription
GET/api/v1/agent/on-call/currentBearerWho is on call

Released under the MIT License.