---
title: "Preview a schedule"
description: "Compute the shifts and coverage gaps a schedule's saved rotation produces over the next four weeks, without writing anything."
---

`POST /api/im/schedules/:id/preview`

Runs the schedule's **saved** configuration (cadence, rotation groups, weekly windows, validity range) through the same shift calculation the paging worker uses, for the next four weeks from now, and returns the shifts and the gaps where nobody is on call. Nothing is stored.

By default the schedule's own saved overrides are included. Send `overrides` to try other override windows instead. Team-level overrides and `all_teams` overrides created on other schedules are not part of the preview.

## 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. No team role is needed.

## Request Body

The body is optional.

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `overrides` | array | No | Up to 500 override windows that replace the saved overrides for this preview. Each: `{ userId, startsAt, endsAt, type?, coveredByUserIds? }`, `type` `online` (default) or `offline`, `coveredByUserIds` only for `offline`. `[]` previews without any overrides. |

## Example (cURL)

```bash
curl -X POST "$BASE_URL/api/im/schedules/7/preview" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
```

## Response

`200 OK`

```json
{
  "from": "2026-10-09T12:00:00.000Z",
  "to": "2026-11-06T12:00:00.000Z",
  "timezone": "Europe/Berlin",
  "shifts": [
    {
      "userId": "u_abc123",
      "layerIndex": 0,
      "startsAt": "2026-10-09T12:00:00.000Z",
      "endsAt": "2026-10-12T07:00:00.000Z",
      "isOverride": false
    },
    {
      "userId": "u_def456",
      "layerIndex": 0,
      "startsAt": "2026-10-12T07:00:00.000Z",
      "endsAt": "2026-10-19T07:00:00.000Z",
      "isOverride": false
    }
  ],
  "gaps": [
    { "from": "2026-11-02T07:00:00.000Z", "to": "2026-11-06T12:00:00.000Z" }
  ]
}
```

- `layerIndex` numbers the concurrent on-call positions (`0` to `roundRobinSize - 1`); override shifts sit on higher indexes. `isOverride` is `true` for a shift that comes from an override.
- `gaps` lists every stretch of the window in which no shift covers anyone. A schedule without rotation groups has one gap over the whole window.

## Common errors

- `401 Unauthorized` (`unauthorized`) when not authenticated
- `403 Forbidden` (`imAccessDenied`) for a customer-scoped token, or a session without an IM-eligible role
- `403 Forbidden` (`imNotEnabled`) when Incident Management is not activated for the organization
- `404 Not Found` (`imScheduleNotFound`) when `:id` does not exist or belongs to another organization
- `400 Bad Request` (`invalidRequestBody`) when `:id` is not a positive integer, `overrides` is not an array or has more than 500 entries, an entry has no `userId` or no valid `startsAt` before `endsAt`, or the saved configuration cannot be turned into shifts (the message says why)
