---
title: "Add a rotation layer"
method: POST
path: "/on-call-schedules/{schedule}/rotations"
tags: ["On-call"]
---

# Add a rotation layer

`POST /on-call-schedules/{schedule}/rotations`

## Request

- Base URL: `https://api.spectate.net/v1`
- URL: `https://api.spectate.net/v1/on-call-schedules/{schedule}/rotations`
- Auth: HTTP bearer

New layers go below the existing ones unless `position` is given. Participants must be
members of the team (`422`).

## Path parameters

- `schedule` string, uuid, required

## Request body

- CreateOnCallRotation: A new rotation layer of a schedule.
  - `name` string, required: Name, up to 255 characters
  - `position` integer: Layer order, 0 for the top. Default: below the existing layers
  - `shift_unit` 'hours' | 'days' | 'weeks', required: The unit of a rotation's shift length. | | |---| | `hours` <br/> Absolute hours: shifts keep their length across DST changes. | | `days` <br/> Calendar days in the schedule's time zone: the handoff stays at the same wall-clock time. | | `weeks` <br/> Calendar weeks in the schedule's time zone. |
  - `shift_length` integer, required: Shift length in `shift_unit`s: up to 720 hours, 90 days or 12 weeks
  - `start_date` string, date, required: The first handoff's date in the schedule's time zone; turns are counted from it
  - `handoff_time` string, required: Handoff time as `HH:MM` in the schedule's time zone
  - `restrictions` OnCallRestrictionsInput: When a rotation layer covers, each week.
    - `days` integer[], required: ISO weekdays the layer covers, 1 (Monday) to 7 (Sunday), at least one
    - `start_time` string, nullable: From when on those days, as `HH:MM` in the schedule's time zone; leave out with `end_time` for the whole day
    - `end_time` string, nullable: Until when, as `HH:MM`
  - `participant_ids` string[]: 1 to 50 team members taking turns, in order

## Response `201`

The new rotation layer.

- OnCallRotation: A rotation layer: its participants take turns of `shift_length` `shift_unit`s, from `start_date` at `handoff_time`. Where layers overlap, the top layer (`position` 0) wins.
  - `id` string, uuid, required: Rotation ID
  - `name` string, required: Name
  - `position` integer, required: Layer order; 0 is the top layer and wins where layers overlap
  - `shift_unit` 'hours' | 'days' | 'weeks', required: The unit of a rotation's shift length. | | |---| | `hours` <br/> Absolute hours: shifts keep their length across DST changes. | | `days` <br/> Calendar days in the schedule's time zone: the handoff stays at the same wall-clock time. | | `weeks` <br/> Calendar weeks in the schedule's time zone. |
  - `shift_length` integer, required: Shift length in `shift_unit`s
  - `start_date` string, date, required: The first handoff's date in the schedule's time zone
  - `handoff_time` string, required: Handoff time as `HH:MM` in the schedule's time zone
  - `restrictions` OnCallRestrictions, required: When a rotation layer covers, each week; outside it the layers below take over.
    - `days` integer[], required: ISO weekdays the layer covers, 1 (Monday) to 7 (Sunday)
    - `start_time` string, nullable, required: From when on those days, as `HH:MM` in the schedule's time zone; `null` with `end_time` `null` for the whole day
    - `end_time` string, nullable, required: Until when, as `HH:MM`; before `start_time` runs past midnight
  - `participants` MemberReference[], required: The members taking turns, in order
    - `id` string, uuid, required: Member (user) ID
    - `name` string, required: Name
    - `email` string, email, required: Email address
  - `created_at` string, date-time, required: When the rotation was created

## Other responses

- `401`: `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.
- `403`: `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.
- `404`: `RESOURCE_NOT_FOUND`: there is no such resource in this team.
- `422`: `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.
- `429`: `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`.

---

[API](https://skmtc.dev/spectate/apis/spectate-api.md) - [All operations](https://skmtc.dev/spectate/apis/spectate-api/llms.txt) - [OpenAPI document](https://skmtc.dev/spectate/apis/spectate-api/revisions/9b1a233997de?raw)
