Schedule configuration
A Schedule defines an on-call rotation for a Team: who is on call, in what order, how escalation works, and how VoIP calls behave. A Schedule belongs to a Team, so create the Team first.
Core fields
| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
name | string | Yes | — | Schedule name. Cannot be empty. |
timezone | string | No | Org setting | IANA timezone (e.g. Asia/Tokyo). If omitted, empty, or UTC, the Organization's timezone is used. |
description | string | No | "" | Free-text description. Up to 500 characters. |
labels | array | No | [] | List of string labels. Each label may contain only A-Z a-z 0-9 and - _ . : /, and is at most 200 characters (see Tags and labels). |
investigation_hints | string | No | — | Optional free-text hints shown to responders. |
rotation_period | string | Yes | — | One of manual, daily, weekly, biweekly, monthly. |
rotation_timeout_seconds | number | Yes | — | Seconds to wait for a responder before moving on. Range: 30–300. |
rotation_rounds | number | Yes | — | How many rounds to attempt. Range: 1–5. |
final_escalation_user_email | string | No | — | Email of the user notified as the final escalation. Resolved against the Team's members. |
members | array | Yes | — | At least one member. Each entry is { user_id, rotation_order } or { user_email, rotation_order }. Members must belong to the Team. |
configurations | array | No | [] | Overlay schedules with their own date ranges. Up to 10; date ranges must not overlap; each overlay needs at least one member. |
For members, identify the user by user_id or user_email (email takes precedence). The final-escalation user and all members must be members of the Team.
Each configurations overlay entry takes a required effective_date (start, YYYY-MM-DD), an optional end_date, and its own members list (same shape as the base members above).
VoIP call behavior
These optional fields control how the automated VoIP call to the on-call responder behaves. Omitting one of them from an update keeps its current value — it is not reset to the default.
| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
voip_skip_confirmation | boolean | No | false | When ON, voice and keypad (DTMF) actions on the call run immediately, without a confirmation prompt. Default OFF (confirmation required) for safety. |
voip_compact_guidance | boolean | No | false | When ON, the first guidance on the call skips the full menu and plays only the alert summary. Default OFF (full menu). |
voip_transcript_enabled | boolean | No | false | When ON, what is said on the call (by the responder and by the AI) is transcribed and saved to the bundle. Default OFF. |
voip_input_mode | string | No | voice_and_dtmf | Input modality: voice_and_dtmf (voice and keypad) or dtmf_only (keypad only; voice input is turned off, so microphone echo cannot occur). |
voip_barge_in | boolean | No | true | When ON, the responder can interrupt the spoken prompt by talking (full duplex). When OFF, the microphone is muted while the prompt plays and a beep tells the responder when to speak (half duplex). |
voip_confirm_retry_interval_seconds | number | No | 8 | Wait time (seconds) before re-prompting in confirmation mode. Range: 3–60 (default 8). Only applies when the confirmation step is on and voice input is enabled. |
voip_confirm_max_retries | number | No | 2 | Maximum re-prompts in confirmation mode. Range: 1–5 (default 2). After the limit, the call falls back to the session timeout. Only applies when the confirmation step is on and voice input is enabled. |
flapping_escalation_enabled | boolean | No | false | When ON, the server detects call flapping (caller repeatedly reconnects) and escalates to the next member early without waiting for the response timeout. Default OFF (opt-in). |
reconnect_window_seconds | number | No | 30 | Sliding window in seconds for counting reconnects to detect flapping. Range: 10–300 (default 30). |
flapping_reconnect_threshold | number | No | 3 | Number of reconnects within the window (initial connect is not counted) that triggers early escalation. Range: 2–10 (default 3). |
While voice input is enabled (voip_input_mode is voice_and_dtmf) and voip_barge_in is ON, voip_skip_confirmation cannot be ON: the update is rejected with incompatible_settings. The check uses the current value of any of the three fields you leave out of the update, so changing just one of them can be rejected too. To skip confirmation, set voip_input_mode to dtmf_only or turn voip_barge_in off in the same update.
Panic broadcast
| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
panic_broadcast_enabled | boolean | No | false | When ON, and the rotation has run out of rounds, Unit Oncall notifies everyone on the Schedule's on-call roster at once (VoIP and push) as a buffer step before falling through to final_escalation_user_email. The same applies when nobody on the rotation can take the call — for example, when everyone is marked absent and no substitute is available: with this ON, the whole roster is called at once first. The roster includes members who are marked absent; absences and substitutes do not apply to the broadcast. The first person to answer takes the alert; the other calls are cancelled. If nobody answers within the response window, the alert continues to the final-escalation step. When nobody is on the roster, the broadcast is skipped and the alert goes straight to final escalation. Default OFF (opt-in). |
Like the VoIP fields above, omitting panic_broadcast_enabled from an update keeps the current value — it is not reset to false.
Unreachable on-call members
Once a day, Unit Oncall checks every Schedule and notifies the Organization owners and every member of the Schedule's Team (notification center and mobile push) when the Schedule has people who can't be called:
- Someone on the rotation, an upcoming override, an absence substitute, or the final escalation user is no longer a member of the Organization. Calls skip them, so remove them from the Schedule.
- Someone on the Schedule has no phone registered. Calls can't reach them, so ask them to sign in to the Unit Oncall mobile app.
- Someone on the Schedule (other than an owner) doesn't meet the Organization's MFA or SSO requirement (
require_mfa/required_sso_providers). They can't enter the Organization, so ask them to set up MFA or link the required SSO account. - In the coming days, there is a day when nobody on the rotation can take calls (everyone is no longer a member, locked, or absent with no available substitute). The notification lists the first such day and how many there are.
A new problem is reported on the next daily check. A problem that is still there is reported again periodically until it is fixed. The notification type is schedule_unreachable_members; see Organization settings for how to turn its push or email delivery on or off.
Default bundle (default_bundle)
Every Schedule has exactly one default bundle — the last-resort receiver for alerts that match none of the Schedule's Bundle Settings entries, including alerts that carry no tags at all. It is created together with the Schedule, so there is nothing to add or delete: you only change its parameters, and you do that here rather than on the Bundle Settings pages.
| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
default_bundle | object | No | current values | The default bundle's parameters. Omitting the whole section keeps the current values — it does not reset them. Sending null means the same thing as omitting it. |
default_bundle.name | string | Yes | Schedule name | Display name of the default bundle. Up to 100 characters, and cannot be empty. |
default_bundle.description | string | Yes | "" | Free-text description. May be empty, but the key must be present. |
default_bundle.window_seconds | number | Yes | 30 | Time window in seconds for bundling incoming alerts. Range: 10–300. |
default_bundle.max_alerts_per_bundle | number | Yes | 1000 | How many alerts (counted in distinct fingerprints) pile up before the bundle notifies again. Not a size limit. Range: 1–1000. See Bundle Settings. |
default_bundle.auto_resolve_on_info | boolean | Yes | true | Resolve the bundle automatically when an info-severity alert arrives. |
default_bundle.auto_expire_hours | number | Yes | 24 | Hours after which an unclosed bundle expires automatically. Range: 1–720. |
default_bundle.cooldown_after_resolve_minutes | number | Yes | 0 | Minutes to wait after a bundle is resolved before opening a new one. Range: 0–60. |
default_bundle.cooldown_after_dismiss_minutes | number | Yes | 5 | Minutes to wait after a bundle is dismissed before opening a new one. Range: 0–60. |
The section is optional, but when you send it, send all eight keys. A partial section is rejected with missing_field, which names the keys you left out — the request never falls back to defaults for them. This is deliberate: without it, an omitted key would be read as its zero value and written back, and four of the eight (description, auto_resolve_on_info, and both cooldowns) are perfectly valid at their zero value, so they would change silently. Omitting auto_resolve_on_info, for example, would quietly stop info alerts from resolving the bundle. Edit the document you read back rather than assembling a partial one — a GET always returns all eight keys.
Omitting the section entirely, or sending it as null, keeps the current values; there is no way to reset the default bundle to the plan default through this section.
The default bundle has no tags: it is the receiver for everything that matched nothing, so there is nothing to select it by. It also has no enabled flag — the last-resort receiver cannot be turned off.
Sending either of them — or any other key the section does not define — is rejected, not ignored: the request fails with unknown_field on default_bundle and lists the offending keys, and the editor flags them before you save. This matters when you paste a Bundle Settings entry as a starting point, because those entries do have tags and enabled: silently dropping them would let you believe you had switched the last-resort receiver off when you had not. The invariants themselves are also enforced by database constraints, so no path can create a default bundle that carries tags or is disabled.
Changes to this section are recorded in the Schedule's own version history, and a rollback of the Schedule configuration restores the default bundle parameters along with everything else.
Ops-mode overrides (ops_config)
ops_config is an object of temporary, safety-side overrides for the settings above. It is read-only in this document: it appears in the configuration you read, but a PUT of the configuration never changes it — it is edited only in Ops mode, and it is deliberately excluded from version history, diffs, and rollback (so an operational stop is not silently undone by rolling a spec back).
Every key is a boolean that, when true, forces the corresponding setting to its safe side regardless of what the configuration above says (effective = configured AND NOT disabled). A key that is false or absent changes nothing.
Key in ops_config | Forces |
|---|---|
disable_skip_confirmation | Confirmation step ON, overriding voip_skip_confirmation. |
disable_compact_guidance | Full spoken guidance, overriding voip_compact_guidance. |
disable_transcript_enabled | Call transcripts OFF, overriding voip_transcript_enabled. |
disable_barge_in | Half duplex (no barge-in), overriding voip_barge_in. |
disable_panic_broadcast | Panic broadcast OFF, overriding panic_broadcast_enabled. |
disable_flapping_escalation | Early (flapping) escalation OFF, overriding flapping_escalation_enabled. |
voip_input_mode, voip_confirm_retry_interval_seconds, voip_confirm_max_retries, reconnect_window_seconds, and flapping_reconnect_threshold have no Ops override — they are not booleans, so there is no unambiguous safe side to force. Their configured values are used as-is.
