Build on-call alerting with the On-Call API
If you run infrastructure, you eventually need to answer three questions when something breaks: who is on call right now, who gets paged next if they don’t respond, and has anyone acknowledged this yet. The On-Call API gives you those three answers as pure, stateless compute — you send a rotation or policy definition, Orbit resolves it — without locking you into a separate incident-alerting vendor or making you learn a second messaging API to actually reach someone. This guide walks through the full loop: define a rotation, build an escalation policy on top of it, drive an incident through its lifecycle, and send the pages it produces.On-Call is compute-only. It never pages anyone and never persists state on Orbit’s side — you own the incident record (in your own database, or even in memory for a quick script) and pass its current snapshot on every call. The one thing it does not do for you is the send itself: that goes through the Messages API, same as any other Orbit send.
Step 1 — Define a rotation
A rotation is an ordered list of members and a cadence.anchor is the ISO instant the first member’s shift begins; every hand-off after that is one shift length later, so the math stays correct across DST changes.
cadence is daily, weekly, or custom. For custom, also set shift_length_seconds (for example 43200 for 12-hour shifts). Members are opaque strings — Orbit never interprets them, so use whatever id you already page with (a user id, an E.164 number, an email address).
Resolve who’s on call
on_call (the current member), the shift_start / shift_end window, and next_on_call / next_handoff_at. Pass an optional "at" (ISO instant) to resolve who was — or will be — on call at a different time, which is useful for testing a rotation before it goes live.
Step 2 — Build an escalation policy
A policy is an ordered list of steps. Each step pages a target — either a live rotation (resolved at page time, so a hand-off mid-incident still pages the right person) or a fixed list of users — over one or more channels, and waitsescalate_after_seconds for an acknowledgement before moving to the next step.
repeat re-runs the whole policy that many additional times if nobody ever acknowledges — set it to 0 for a policy that pages once through and stops.
Plan the escalation timeline
targets and channels, at what offset_seconds from incident start, and the concrete fire_at instant. This is the schedule you hand to Step 3.
Step 3 — Drive the incident lifecycle
You own the incident record. On-Call gives you two stateless operations against a snapshot you keep in your own store:POST /oncall/incident/tick— “what’s due right now?” Pass the incident snapshot (its policy,started_at, currentstatus, andpages_firedhigh-water mark) and Orbit returns the pages due this tick, the new high-water mark to persist, andnext_tick_at— when to calltickagain. Call this on a timer (or lazily, whenever your own scheduler wakes up) until the incident is acknowledged, resolved, orexhausted(every page fired with no response).POST /oncall/incident/transition— apply an operator action:ack,resolve, orreassign(swap in a new policy and restart the timeline, e.g. escalating a Sev-2 to a Sev-1 policy). An invalid transition — acknowledging an already-resolved incident, for example — is rejected with409 incident_transition_invalidinstead of silently corrupting your state.
tick or transition call — that snapshot (specifically its pages_fired mark and status) is the only state On-Call asks you to keep.
Step 4 — Page the resolved targets
tick tells you which targets and channels are due — it does not send anything. Fan each due page out through the Messages API on the channel(s) the step named:
escalate_after_seconds window elapses.
Frequently asked questions
Does On-Call replace PagerDuty or Opsgenie?
Not necessarily — it’s the same rotation/escalation primitives those tools use, built on your existing Orbit channels. Some teams use it standalone; others use it to build a lightweight alerting path for one service without paying for a full incident-management seat.Does Orbit store my rotations or incidents?
No. Every On-Call endpoint is pure compute over the request body — you send the full rotation, policy, or incident snapshot on every call, and Orbit returns the resolved answer. Persistence is entirely on your side.What happens if nobody acknowledges the incident?
Once every page across every step and repeat round has fired with noack, tick reports status: "exhausted" and next_tick_at: null — there is nothing left to schedule. Your driver should treat this as its own alert (e.g. page a fallback channel or open a ticket).
Can I change who gets paged mid-incident?
Yes — send areassign transition with a new policy. This restarts the escalation timeline from the top under the new policy, which is useful for escalating a Sev-2 incident to a broader Sev-1 policy.
See also
- On-Call API reference — full endpoint, scope, and field reference
- Messages API — the send surface that actually pages a resolved target
- Webhooks — subscribe to delivery status for a page you sent