Learn how to interact with Rotation App programmatically using our REST API to get on-call users, assign users, and manage rotation queues.
- All Slack workspace users with access to the rotation.
- API authentication requires an API key that you can generate from the Home tab.
The Rotation App REST API provides developers with programmatic access to rotation data and controls. Use this API to build custom applications, scripts, and integrations that interact directly with your rotations through HTTP requests.
Example use cases:
- Build monitoring dashboards that fetch current on-call users via API calls.
- Create custom scheduling scripts that assign users based on complex business logic.
- Integrate rotation data into existing applications and services (project management, incident management, etc.)
- Develop automated tools that manage rotation queues programmatically instead of on a schedule.
- Build custom incident management systems that query and update rotations.
Webhooks: Receive real-time event notifications when rotations change
Slack Workflows: No-code automation directly within Slack
API Base URL and Authentication
All API requests should be made to:
https://api.rotation.app/v1/t/<team_id>/r/<rotation_id>/<action_type>
URL Parameters:
team_id: Your Slack workspace/team IDrotation_id: The unique identifier of your rotationaction_type: The specific API action you want to perform
Authentication:
All API requests require authentication using an API key. Include your API key in the x-api-key header:
-H "x-api-key: YOUR_API_KEY"
Learn how to configure your API key
Finding Your Team and Rotation IDs
To use the API, you’ll need your team_id and rotation_id. Learn how to find these identifiers in our dedicated guide:
Learn how to find your rotation and team IDs
Available API Actions
Read shifts:
Modify the queue:
Modify individual shifts:
- Set Shifts: substitute, cancel, or set one or multiple shifts
- Substitute Shift
- Undo Substitution
- Cancel Shift
- Uncancel Shift
Get Current Shift Assignees
Retrieve the list of users currently assigned to the rotation.
Endpoint: GET /v1/t/<team_id>/r/<rotation_id>/get_current_shift_assignees
Parameters: None required
Example Request:
curl -X GET "https://api.rotation.app/v1/t/T123456/r/ROTA123/get_current_shift_assignees" \
-H "x-api-key: YOUR_API_KEY"
Response Format:
{
"current_shift_user_ids": ["user_id_1", "user_id_2", "user_id_3"],
"current_shift_user_ids_0": "user_id_1",
"current_shift_user_ids_1": "user_id_2",
"current_shift_user_ids_2": "user_id_3"
}
Response Fields:
current_shift_user_ids: Array of user IDs currently on callcurrent_shift_user_ids_<index>: Individual user ID at the specified index (provided for no-code tool compatibility)
Get Next Shift Assignees
Retrieve the list of users who will be assigned in the next shift.
Endpoint: GET /v1/t/<team_id>/r/<rotation_id>/get_next_shift_assignees
Parameters: None required
Example Request:
curl -X GET "https://api.rotation.app/v1/t/T123456/r/ROTA123/get_next_shift_assignees" \
-H "x-api-key: YOUR_API_KEY"
Response Format:
{
"next_shift_user_ids": ["user_id_1", "user_id_2", "user_id_3"],
"next_shift_user_ids_0": "user_id_1",
"next_shift_user_ids_1": "user_id_2",
"next_shift_user_ids_2": "user_id_3"
}
Response Fields:
next_shift_user_ids: Array of user IDs assigned to the next shiftnext_shift_user_ids_<index>: Individual user ID at the specified index (provided for no-code tool compatibility)
Get Other Shift Assignees
Retrieve the list of users assigned to future shifts (3rd, 4th, or 5th shift from now).
Available Endpoints:
GET /v1/t/<team_id>/r/<rotation_id>/get_shift_3_assignees- Third shiftGET /v1/t/<team_id>/r/<rotation_id>/get_shift_4_assignees- Fourth shiftGET /v1/t/<team_id>/r/<rotation_id>/get_shift_5_assignees- Fifth shift
Parameters: None required
Example Request:
curl -X GET "https://api.rotation.app/v1/t/T123456/r/ROTA123/get_shift_3_assignees" \
-H "x-api-key: YOUR_API_KEY"
Response Format:
{
"shift_3_user_ids": ["user_id_1", "user_id_2", "user_id_3"],
"shift_3_user_ids_0": "user_id_1",
"shift_3_user_ids_1": "user_id_2",
"shift_3_user_ids_2": "user_id_3"
}
Response Fields:
shift_<N>_user_ids: Array of user IDs assigned to that shiftshift_<N>_user_ids_<index>: Individual user ID at the specified index (provided for no-code tool compatibility)
Assign Specific User
Assign a specific user to be on call for the rotation.
Endpoint: POST /v1/t/<team_id>/r/<rotation_id>/assign_user
Body Parameters:
user_id(required): The ID of the user to assign
Example Request:
curl -X POST "https://api.rotation.app/v1/t/T123456/r/ROTA123/assign_user" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"user_id": "user_id_1"}'
Response Format:
{
"on_call_user_ids": ["user_id_1"],
"on_call_user_ids_0": "user_id_1"
}
Response Fields:
on_call_user_ids: Updated array of user IDs now on callon_call_user_ids_<index>: Individual user ID at the specified index
Assign Next User(s)
Assign the next user(s) in the rotation queue to be on call.
Endpoint: POST /v1/t/<team_id>/r/<rotation_id>/assign_next
Parameters: None required
Example Request:
curl -X POST "https://api.rotation.app/v1/t/T123456/r/ROTA123/assign_next" \
-H "x-api-key: YOUR_API_KEY"
Response Format:
{
"on_call_user_ids": ["user_id_1", "user_id_2", "user_id_3"],
"on_call_user_ids_0": "user_id_1",
"on_call_user_ids_1": "user_id_2",
"on_call_user_ids_2": "user_id_3"
}
Response Fields:
on_call_user_ids: Updated array of user IDs now on callon_call_user_ids_<index>: Individual user ID at the specified index
Shuffle Rotation Queue
Randomize the order of users in the rotation queue.
Endpoint: POST /v1/t/<team_id>/r/<rotation_id>/shuffle_rotation_queue
Body Parameters:
include_currently_on_call(optional): Boolean indicating whether currently on-call users should be included in the shuffle
Example Request:
curl -X POST "https://api.rotation.app/v1/t/T123456/r/ROTA123/shuffle_rotation_queue" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"include_currently_on_call": true}'
Response Format:
{
"on_call_user_ids": ["user_id_1", "user_id_2", "user_id_3"],
"on_call_user_ids_0": "user_id_1",
"on_call_user_ids_1": "user_id_2",
"on_call_user_ids_2": "user_id_3"
}
Response Fields:
on_call_user_ids: Updated array of user IDs now on call after shuffleon_call_user_ids_<index>: Individual user ID at the specified index
Get Shifts
Retrieve a range of upcoming shifts with their dates and assignees. Useful for pushing the rotation to dashboards, calendars, or external scheduling tools.
Endpoint: GET /v1/t/<team_id>/r/<rotation_id>/get_shifts
Query Parameters:
from(optional): Inclusive lower bound. Either a date (YYYY-MM-DD) or a 1-based shift number ("1","2", …). Defaults to shift1(the current shift).to(optional): Inclusive upper bound, same format asfrom. Defaults tofrom + 29(a 30-shift window). The maximum window size is 365 shifts.verbose(optional): Iftrue, each shift value is an object{ "assignees": [...], "naturalAssignees": [...] }instead of a bare user ID, array, ornull. Useful for seeing who the queue would have placed at a shift if there were no overrides.
Example Request:
curl -X GET "https://api.rotation.app/v1/t/T123456/r/ROTA123/get_shifts?from=2026-05-04&to=2026-05-08" \
-H "x-api-key: YOUR_API_KEY"
Response Format:
{
"shifts": {
"2026-05-04": "user_id_1",
"2026-05-05": "user_id_2",
"2026-05-06": null,
"2026-05-07": "user_id_3",
"2026-05-08": "user_id_1"
}
}
Response Fields:
shifts: An object keyed by shift date (YYYY-MM-DD, in the rotation’s local timezone) for cron-scheduled rotations, or by 1-based shift number for manual rotations. Values are user IDs for assigned shifts, arrays of user IDs for group rotations, ornullfor shifts where nobody is assigned (skipped or cancelled).- In verbose mode, each value is an object
{ "assignees": [...] | null, "naturalAssignees": [...] }.assigneesisnullfor skipped or cancelled shifts;naturalAssigneesalways shows who the queue would place there in the absence of overrides.
Set Shifts
Substitute, cancel, or set multiple shifts in a single call. This is the most flexible endpoint for syncing your rotation with an external source of truth (e.g. a Google Sheet or planning tool).
Endpoint: POST /v1/t/<team_id>/r/<rotation_id>/set_shifts
Body Parameters:
shifts(required): An object keyed by shift date (YYYY-MM-DD) or 1-based shift number ("1","2", …). Values are:- A user ID (
"U06S3JJUU92") to substitute that shift with the given user. - An array of user IDs (
["U06S3JJUU92", "U02M888M3C7"]) for group rotations (length must equal the rotation’s group size). nullto cancel the shift (no assignee; following shifts stay on schedule). See Cancelling a shift for the semantics.
- A user ID (
verbose(optional): Iftrue, each shift value in the response becomes an object{ "assignees": [...] | null, "naturalAssignees": [...] }instead of a bare user ID, array, ornull.
Example Request (substitute and cancel):
curl -X POST "https://api.rotation.app/v1/t/T123456/r/ROTA123/set_shifts" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"shifts": {
"2026-05-04": "U06S3JJUU92",
"2026-05-05": null
}
}'
Response Format:
{
"shifts": {
"2026-05-04": "U06S3JJUU92",
"2026-05-05": null
}
}
Verbose response (?verbose=true):
{
"shifts": {
"2026-05-04": {
"assignees": ["U06S3JJUU92"],
"naturalAssignees": ["U02M888M3C7"]
},
"2026-05-05": {
"assignees": null,
"naturalAssignees": ["U06S3JJUU92"]
}
}
}
Values are the computed post-write state for each shift you addressed, useful for verifying what actually landed. In verbose mode, naturalAssignees shows who the queue would place there if the override were removed. If a write was rejected (for example, a user ID not in the rotation), the API returns HTTP 400 with a per-key error map under errors.
"1", "2") if you’d rather address shifts positionally. "1" is the current shift.
Substitute Shift
Substitute the assigned user(s) at a single shift. A convenience wrapper around set_shifts with a one-entry payload, for callers that prefer one operation per request (Slack Workflows, single-shift automations).
Endpoint: POST /v1/t/<team_id>/r/<rotation_id>/substitute_shift
Body Parameters:
shift(required): The date (YYYY-MM-DD) or 1-based shift number to substitute.user_id(required for single-user rotations): The user ID to assign for this shift.user_ids(required for group rotations): Array of user IDs (length must equal the rotation’s group size).verbose(optional): Same asset_shifts— toggles the per-shift response shape.
Example Request:
curl -X POST "https://api.rotation.app/v1/t/T123456/r/ROTA123/substitute_shift" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"shift": "2026-05-04",
"user_id": "U06S3JJUU92"
}'
Response Format:
Same shape as set_shifts — a shifts object keyed by the shift you addressed, with the computed post-write state as the value.
{
"shifts": {
"2026-05-04": "U06S3JJUU92"
}
}
Cancel Shift
Cancels a single shift. Nobody is assigned, the natural assignee’s turn is used up, and the rest of the queue stays on the original schedule. See Cancelling a shift for the full semantics. A convenience wrapper around set_shifts with a null value.
Endpoint: POST /v1/t/<team_id>/r/<rotation_id>/cancel_shift
Body Parameters:
shift(required): The date (YYYY-MM-DD) or 1-based shift number to cancel.verbose(optional): Same asset_shifts, toggles the per-shift response shape.
Example Request:
curl -X POST "https://api.rotation.app/v1/t/T123456/r/ROTA123/cancel_shift" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "shift": "2026-05-04" }'
Response Format:
Same shape as set_shifts. The value is null for the cancelled shift.
{
"shifts": {
"2026-05-04": null
}
}
The INSERT-style skip described in the Manage Rotation Shifts guide (which defers the queue by one shift instead of using up the natural assignee’s turn) isn’t currently exposed in the public API. Use the Slack queue manager for that.
Uncancel Shift
Reverts a previously cancelled shift back to its natural assignee.
Endpoint: POST /v1/t/<team_id>/r/<rotation_id>/uncancel_shift
Body Parameters:
shift(required): The date (YYYY-MM-DD) or 1-based shift number to uncancel.verbose(optional): Same asset_shifts, toggles the per-shift response shape.
Example Request:
curl -X POST "https://api.rotation.app/v1/t/T123456/r/ROTA123/uncancel_shift" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "shift": "2026-05-04" }'
Response Format:
Same shape as set_shifts. The value is the natural assignee that now occupies the shift.
{
"shifts": {
"2026-05-04": "U06S3JJUU92"
}
}
Errors:
400if the shift isn’t currently cancelled or skipped.400if the shift was skipped via the queue manager’s INSERT-style “Skip this shift” action. Those need to be undone from Slack’s queue manager first.
Undo Substitution
Remove a substitution from a shift, returning it to the natural assignee.
Endpoint: POST /v1/t/<team_id>/r/<rotation_id>/undo_substitution
Body Parameters:
shift(required): The date (YYYY-MM-DD) or 1-based shift number whose substitution to remove.verbose(optional): Same asset_shifts— toggles the per-shift response shape.
Example Request:
curl -X POST "https://api.rotation.app/v1/t/T123456/r/ROTA123/undo_substitution" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "shift": "2026-05-04" }'
Response Format:
Same shape as set_shifts. The value is the natural assignee that now occupies the shift.
{
"shifts": {
"2026-05-04": "U06S3JJUU92"
}
}
Errors:
400if the shift doesn’t currently have an active substitution to undo.
Integration Examples
Dashboard Integration
Use get_current_shift_assignees to display current on-call users on monitoring dashboards or status pages.
Incident Management
Combine get_current_shift_assignees with incident management tools to automatically assign incidents to the current on-call user.
Custom Scheduling
Use assign_user and assign_next to implement custom scheduling logic based on external factors like workload or availability.
Load Balancing
Use shuffle_rotation_queue periodically to ensure fair distribution of on-call duties across team members.
CSV-to-rotation push
Use set_shifts to push an externally-managed schedule (a Google Sheet, a planning tool, an HR system) into Rotation App. Send the whole next month in one call, with assignments as user IDs and days off as null. Combine with get_shifts?verbose=true afterwards to verify the result.