Schedules
List, read, create and delete Incident Management on-call schedules, and how a schedule's rotation cadence works.
A schedule belongs to one team and one of its escalation tiers. Its timezone, validity range, weekly windows, rotation cadence and rotation groups decide who is on shift when. A background worker turns that definition into concrete shifts up to 90 days ahead; paging, Who Is On Call and the team calendar read those shifts. These endpoints manage the definition, not the shifts.
Configure the rotation with Update a schedule, or create a fully configured schedule in one call with Add a schedule to a tier. Preview a schedule shows the resulting shifts.
Authentication
Base IM access: an IM-eligible role (admin, editor or responder) or an organization-wide API token, and Incident Management activated for the organization. Listing and reading are open to any caller with that access. Creating and deleting need the team write bar for the schedule's team: organization admin role, or team admin. An API token runs with the role of the user who created it, so only a token created by an organization admin passes.
List schedules
GET /api/im/schedules
Returns every schedule of your organization, ordered by name.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
envelope | string | none | items: answer as { items, total, page, perPage }. Becomes the default on 2027-01-18. |
Example (cURL)
curl -X GET "$BASE_URL/api/im/schedules?envelope=items" \
-H "Authorization: Bearer $TOKEN"Response
200 OK
{
"items": [
{
"id": 7,
"organizationId": 1,
"teamId": 3,
"teamName": "Platform Team",
"name": "Primary On-Call",
"timezone": "Europe/Berlin",
"tierId": 21,
"createdAt": "2026-06-02T08:00:00.000Z",
"updatedAt": "2026-09-14T10:12:00.000Z"
}
],
"total": 1,
"page": 1,
"perPage": 1
}List form: with envelope=items the list arrives as { items, total, page, perPage }. Without it the endpoint still answers the current form (a bare array of the same schedules), which is deprecated; { items, ... } becomes the default on 2027-01-18.
Get a schedule
GET /api/im/schedules/:id
Returns the full schedule configuration, its team and its overrides (same item shape as Schedule Overrides). rotations lists the rotation groups with their members (with userImage), in the same shape as schedules[].rotations of Get a tier; they are also part of the team's escalation chain.
Example (cURL)
curl -X GET "$BASE_URL/api/im/schedules/7" \
-H "Authorization: Bearer $TOKEN"Response
200 OK
{
"id": 7,
"organizationId": 1,
"teamId": 3,
"tierId": 21,
"name": "Primary On-Call",
"timezone": "Europe/Berlin",
"effectiveFrom": null,
"effectiveUntil": null,
"weeklySchedules": [],
"rotationMode": "explicit",
"rotationRepeats": "weekly",
"customRepeatUnit": null,
"customRepeatValue": null,
"autoRotationSize": null,
"roundRobinSize": 1,
"roundRobinCursor": 4,
"startsOnDayOfWeek": 1,
"startsOnDateOfMonth": null,
"startsOnTime": "09:00",
"createdAt": "2026-06-02T08:00:00.000Z",
"updatedAt": "2026-09-14T10:12:00.000Z",
"team": { "id": 3, "name": "Platform Team" },
"overrides": [],
"rotations": [
{
"id": 31,
"rotationOrder": 1,
"members": [
{ "userId": "usr_abc", "userName": "Alex Example", "userImage": null, "memberOrder": 1 }
]
}
]
}roundRobinCursor is an internal counter for round-robin paging and cannot be set.
Create a schedule
POST /api/im/schedules
Creates an empty schedule under a tier: 24/7, rotationMode: "none", no rotation groups. It pages nobody until you add rotation groups with Update a schedule.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
teamId | number | Yes | The owning team. Must belong to your organization. |
tierId | number | Yes | A tier of that team. |
name | string | Yes | 1 to 120 characters after trimming. |
timezone | string | Yes | IANA zone (e.g. Europe/Berlin). Every handover and weekly window is evaluated in this zone, across DST. |
Example (cURL)
curl -X POST "$BASE_URL/api/im/schedules" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ "teamId": 3, "tierId": 21, "name": "Primary On-Call", "timezone": "Europe/Berlin" }'Response
200 OK: the new schedule, same fields as Get a schedule without team and overrides.
Delete a schedule
DELETE /api/im/schedules/:id
Deletes the schedule with its rotation groups, overrides and shifts.
Example (cURL)
curl -X DELETE "$BASE_URL/api/im/schedules/7" \
-H "Authorization: Bearer $TOKEN"Response
200 OK
{ "success": true }Rotation cadence
The cadence decides how often on-call hands over. It is set with Update a schedule or when adding a schedule to a tier.
| Field | Type | Description |
|---|---|---|
rotationMode | string | none (one continuous shift, nobody hands over), auto (the member pool is split into groups automatically) or explicit (you define the groups). Default none. |
rotationRepeats | string | null | daily, weekly, biweekly, monthly or custom. Must be null for none, required otherwise. |
customRepeatUnit | string | null | Required for custom: minutes, hours, days, weeks or months. |
customRepeatValue | integer | null | Required for custom: 1 or more, in the unit above. |
autoRotationSize | integer | null | Required for auto: members per automatically built group, 1 or more. |
roundRobinSize | integer | How many rotation members are on call at the same time, 1 or more. Default 1. |
startsOnTime | string | null | "HH:mm", time of day of the handover in the schedule's timezone. Required unless the mode is none. |
startsOnDayOfWeek | integer | null | ISO weekday (1 = Monday to 7 = Sunday). Required for weekly, biweekly and custom with weeks. |
startsOnDateOfMonth | integer | null | 1 to 31, clamped to the month's last day. Required for monthly and custom with months. |
The shortest possible shift is one minute (customRepeatUnit: "minutes", customRepeatValue: 1). Handover times are minute-precise at every cadence.
Sub-day cadences (minutes, hours) step in absolute time rather than wall-clock time. Across a DST switch they keep handing over every N minutes in real time instead of duplicating or skipping an hour of handovers.
How far ahead shifts are materialized
Shifts are materialized on a rolling horizon of up to 90 days. A fast cadence is materialized less far ahead, because the number of shift rows is the horizon divided by the cadence: a one-minute rotation over 90 days would be 129,600 shifts per member. Such a schedule is kept roughly 41 hours ahead instead, topped up every hour.
This is not a coverage limit. Paging reads the shift that is current now, and the materializer runs far more often than the horizon shrinks. Only a preview far into the future is shorter for a fast cadence. Every cadence of an hour or longer keeps the full 90 days.
Common errors
401 Unauthorized(unauthorized) when not authenticated403 Forbidden(imAccessDenied) for a customer-scoped token, or a session without an IM-eligible role403 Forbidden(imNotEnabled) when Incident Management is not activated for the organization403 Forbidden(imTeamWriteDenied) on create or delete when you are neither organization admin nor team admin of the team404 Not Found(imScheduleNotFound) when:iddoes not exist or belongs to another organization404 Not Found(imTeamNotFound) on create whenteamIddoes not exist or belongs to another organization400 Bad Request(invalidRequestBody) when:idis not a positive integer, or on create whenteamIdortierIdis missing or not a positive integer,tierIdis not a tier ofteamId,nameis missing or longer than 120 characters, ortimezoneis missing or not a valid IANA zone
Team On-Call and Statistics
Read who is on call for a team right now, the team's on-call calendar for a time window, and the team's incident statistics.
Update a schedule
Change an on-call schedule's name, timezone, validity range, weekly windows, rotation cadence and rotation membership, in one atomic call.