Replace a rotation's grid
using System.Net.Http.Headers;var client = new HttpClient();var request = new HttpRequestMessage{ Method = HttpMethod.Put, RequestUri = new Uri("https://api.roundrobinbot.eu/v1/rotations/example/coverage"), Headers = { { "If-Match", "example" }, { "Authorization", "Bearer <token>" }, }, Content = new StringContent("{ \"lanes\": [ { \"id\": \"example\", \"name\": \"example\" } ], \"windows\": [ { \"id\": \"example\", \"name\": \"example\", \"timeZone\": \"example\", \"coverage\": [ { \"startDay\": \"example\", \"startTime\": \"example\", \"endDay\": \"example\", \"endTime\": \"example\" } ], \"cadence\": { \"type\": \"example\", \"timeZone\": \"example\", \"startsAt\": \"example\", \"period\": 1, \"skipWeekends\": true, \"skipNationalHolidays\": true, \"countryCodes\": [ \"example\" ], \"daysOfWeek\": [ \"example\" ], \"dayOfWeek\": \"example\", \"weeksInMonth\": [ 1 ], \"times\": [ \"example\" ] }, \"listId\": \"example\", \"rosterId\": \"example\" } ], \"cells\": [ { \"id\": \"example\", \"laneId\": \"example\", \"windowId\": \"example\", \"listId\": \"example\", \"rosterId\": \"example\" } ], \"doubleCover\": true }") { Headers = { ContentType = new MediaTypeHeaderValue("application/json-patch+json") } }};using (var response = await client.SendAsync(request)){ response.EnsureSuccessStatusCode(); var body = await response.Content.ReadAsStringAsync(); Console.WriteLine(body);}package main
import ( "fmt" "strings" "net/http" "io")
func main() {
url := "https://api.roundrobinbot.eu/v1/rotations/example/coverage"
payload := strings.NewReader("{ \"lanes\": [ { \"id\": \"example\", \"name\": \"example\" } ], \"windows\": [ { \"id\": \"example\", \"name\": \"example\", \"timeZone\": \"example\", \"coverage\": [ { \"startDay\": \"example\", \"startTime\": \"example\", \"endDay\": \"example\", \"endTime\": \"example\" } ], \"cadence\": { \"type\": \"example\", \"timeZone\": \"example\", \"startsAt\": \"example\", \"period\": 1, \"skipWeekends\": true, \"skipNationalHolidays\": true, \"countryCodes\": [ \"example\" ], \"daysOfWeek\": [ \"example\" ], \"dayOfWeek\": \"example\", \"weeksInMonth\": [ 1 ], \"times\": [ \"example\" ] }, \"listId\": \"example\", \"rosterId\": \"example\" } ], \"cells\": [ { \"id\": \"example\", \"laneId\": \"example\", \"windowId\": \"example\", \"listId\": \"example\", \"rosterId\": \"example\" } ], \"doubleCover\": true }")
req, _ := http.NewRequest("PUT", url, payload)
req.Header.Add("If-Match", "example") req.Header.Add("Authorization", "Bearer <token>") req.Header.Add("Content-Type", "application/json-patch+json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close() body, _ := io.ReadAll(res.Body)
fmt.Println(res) fmt.Println(string(body))
}OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse("application/json-patch+json");RequestBody body = RequestBody.create(mediaType, "{ \"lanes\": [ { \"id\": \"example\", \"name\": \"example\" } ], \"windows\": [ { \"id\": \"example\", \"name\": \"example\", \"timeZone\": \"example\", \"coverage\": [ { \"startDay\": \"example\", \"startTime\": \"example\", \"endDay\": \"example\", \"endTime\": \"example\" } ], \"cadence\": { \"type\": \"example\", \"timeZone\": \"example\", \"startsAt\": \"example\", \"period\": 1, \"skipWeekends\": true, \"skipNationalHolidays\": true, \"countryCodes\": [ \"example\" ], \"daysOfWeek\": [ \"example\" ], \"dayOfWeek\": \"example\", \"weeksInMonth\": [ 1 ], \"times\": [ \"example\" ] }, \"listId\": \"example\", \"rosterId\": \"example\" } ], \"cells\": [ { \"id\": \"example\", \"laneId\": \"example\", \"windowId\": \"example\", \"listId\": \"example\", \"rosterId\": \"example\" } ], \"doubleCover\": true }");Request request = new Request.Builder() .url("https://api.roundrobinbot.eu/v1/rotations/example/coverage") .put(body) .addHeader("If-Match", "example") .addHeader("Authorization", "Bearer <token>") .addHeader("Content-Type", "application/json-patch+json") .build();
Response response = client.newCall(request).execute();import axios from 'axios';
const options = { method: 'PUT', url: 'https://api.roundrobinbot.eu/v1/rotations/example/coverage', headers: { 'If-Match': 'example', Authorization: 'Bearer <token>', 'Content-Type': 'application/json-patch+json' }, data: '{ "lanes": [ { "id": "example", "name": "example" } ], "windows": [ { "id": "example", "name": "example", "timeZone": "example", "coverage": [ { "startDay": "example", "startTime": "example", "endDay": "example", "endTime": "example" } ], "cadence": { "type": "example", "timeZone": "example", "startsAt": "example", "period": 1, "skipWeekends": true, "skipNationalHolidays": true, "countryCodes": [ "example" ], "daysOfWeek": [ "example" ], "dayOfWeek": "example", "weeksInMonth": [ 1 ], "times": [ "example" ] }, "listId": "example", "rosterId": "example" } ], "cells": [ { "id": "example", "laneId": "example", "windowId": "example", "listId": "example", "rosterId": "example" } ], "doubleCover": true }'};
try { const { data } = await axios.request(options); console.log(data);} catch (error) { console.error(error);}const url = 'https://api.roundrobinbot.eu/v1/rotations/example/coverage';const options = { method: 'PUT', headers: { 'If-Match': 'example', Authorization: 'Bearer <token>', 'Content-Type': 'application/json-patch+json' }, body: '{ "lanes": [ { "id": "example", "name": "example" } ], "windows": [ { "id": "example", "name": "example", "timeZone": "example", "coverage": [ { "startDay": "example", "startTime": "example", "endDay": "example", "endTime": "example" } ], "cadence": { "type": "example", "timeZone": "example", "startsAt": "example", "period": 1, "skipWeekends": true, "skipNationalHolidays": true, "countryCodes": [ "example" ], "daysOfWeek": [ "example" ], "dayOfWeek": "example", "weeksInMonth": [ 1 ], "times": [ "example" ] }, "listId": "example", "rosterId": "example" } ], "cells": [ { "id": "example", "laneId": "example", "windowId": "example", "listId": "example", "rosterId": "example" } ], "doubleCover": true }'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request PUT \ --url https://api.roundrobinbot.eu/v1/rotations/example/coverage \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json-patch+json' \ --header 'If-Match: example' \ --data '{ "lanes": [ { "id": "example", "name": "example" } ], "windows": [ { "id": "example", "name": "example", "timeZone": "example", "coverage": [ { "startDay": "example", "startTime": "example", "endDay": "example", "endTime": "example" } ], "cadence": { "type": "example", "timeZone": "example", "startsAt": "example", "period": 1, "skipWeekends": true, "skipNationalHolidays": true, "countryCodes": [ "example" ], "daysOfWeek": [ "example" ], "dayOfWeek": "example", "weeksInMonth": [ 1 ], "times": [ "example" ] }, "listId": "example", "rosterId": "example" } ], "cells": [ { "id": "example", "laneId": "example", "windowId": "example", "listId": "example", "rosterId": "example" } ], "doubleCover": true }'Gives the rotation the lanes, coverage windows and cells you describe. A replacement, not a patch: the lanes you send are the lanes it will have, and one you leave out is deleted along with whoever was on duty in it. Answers with the whole rotation and a fresh ETag. Read the rotation first and send its lanes, windows and cells back with your change made. Leave windows out entirely to keep the windows it has, which is what an edit to the rows alone should do. Every lane and window carries an id: to add one, give it any string of your own for its cells to name. Lanes in windows this leaves empty are dealt straight away rather than at the next hand-over, so a lane you add has somebody on it when the response comes back. A switched-off rotation can be edited too: they stay empty until the rotation is switched on.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”Header Parameters
Section titled “Header Parameters”The ETag from your last read of this resource, sent back exactly as you received it, quotes included. The write happens only if nothing changed in between: a stale validator is answered 412 and nothing is written. Send * to write against whatever is current on purpose. Omitting the header is 428, never an unconditional write. https://docs.roundrobinbot.eu/api/conventions/#conditional-writes
Request Bodyrequired
Section titled “Request Bodyrequired”The grid PUT /v1/rotations/{rotationId}/coverage gives a rotation: its lanes, its coverage windows, and which list each lane draws on in each window.
object
The rows, in the order they should be dealt: the first lane is the primary one.
One row of the proposed grid.
object
The lane’s id, or a handle of your own for a lane you are adding. Always required.
What to call this lane, such as Primary or Frontend. Left out on a rotation with one lane, which never shows a name.
The windows: when the rotation is covered, and how often duty changes hands there.
One window of the proposed grid.
object
The window’s id, or a handle of your own for a window you are adding. Always required.
What to call this window, such as EMEA.
The time zone the covered hours below are read in, as a city identifier (Europe/Rome) or UTC. Fixed offsets are refused rather than guessed at.
The repeating week this window is open for. Leave it empty for a window that is open all week, which is what a rotation with no restricted hours has.
One stretch of the coverage week, which may run past midnight into the next day.
object
A weekday name, monday through sunday, lower case.
A time of day, HH:mm.
How often duty changes hands in this window. Leave it out to keep the cadence this window already has: a caller changing the hours must not flatten the handover as a side effect.
object
One of dayOfWeek, daysOfWeekList, dayOfMonth, nthWeekdayOfMonth, daily or workday.
The time zone the schedule runs in, as a city identifier: Europe/Rome, or UTC. Fixed offsets and old spellings are refused rather than guessed at.
When the schedule starts, as an RFC 3339 timestamp. A value with no offset is read as UTC.
How many units of the schedule’s own kind sit between two hand-overs: 2 on a dayOfWeek schedule is fortnightly. Defaults to 1.
Whether hand-overs that land on a weekend move on. Defaults to false, and is always true for workday. Needs countryCodes: which days are the weekend is a fact about a country.
Whether hand-overs that land on a national holiday move on. Defaults to false, and is always true for workday. Needs countryCodes for the same reason.
The ISO 3166-1 alpha-2 countries whose weekends and holidays the skips are read from. At least one is required whenever either skip is on, and so on every workday schedule, which turns both on. Without one the skips would skip nothing while still reading as active.
For daysOfWeekList: the weekdays it hands over on, lower case (monday … sunday). At least one.
For nthWeekdayOfMonth: which weekday, lower case. Not used by dayOfWeek, which takes its day from startsAt.
For nthWeekdayOfMonth: which occurrences in the month, 1 through 5. At least one.
For daily: the times of day it hands over at, as HH:mm. At least one.
The list this window draws on in every lane, for a window you are adding. Send it and no entries of cells for the window, and one is written in each lane for you. Entries you send for the window are taken as sent, and a window the rotation already has refuses it.
Deprecated: use listId. Still accepted with the same meaning; when both are sent they have to agree.
Every lane crossed with every window, one entry each.
One lane in one window of the proposed grid.
object
The id of this lane in this window, or left out to create one.
The lane, naming one of the lanes in this body.
The window, naming one of the windows in play.
The list this lane is dealt from in this window, which is required on every entry.
Deprecated: use listId. Still accepted with the same meaning; when both are sent they have to agree.
Whether one person may be on duty in two lanes at once when the list behind them is too short to fill both. Defaults to false, which leaves the lanes it cannot fill empty.
Examplegenerated
{ "lanes": [ { "id": "example", "name": "example" } ], "windows": [ { "id": "example", "name": "example", "timeZone": "example", "coverage": [ { "startDay": "example", "startTime": "example", "endDay": "example", "endTime": "example" } ], "cadence": { "type": "example", "timeZone": "example", "startsAt": "example", "period": 1, "skipWeekends": true, "skipNationalHolidays": true, "countryCodes": [ "example" ], "daysOfWeek": [ "example" ], "dayOfWeek": "example", "weeksInMonth": [ 1 ], "times": [ "example" ] }, "listId": "example", "rosterId": "example" } ], "cells": [ { "id": "example", "laneId": "example", "windowId": "example", "listId": "example", "rosterId": "example" } ], "doubleCover": true}The grid PUT /v1/rotations/{rotationId}/coverage gives a rotation: its lanes, its coverage windows, and which list each lane draws on in each window.
object
The rows, in the order they should be dealt: the first lane is the primary one.
One row of the proposed grid.
object
The lane’s id, or a handle of your own for a lane you are adding. Always required.
What to call this lane, such as Primary or Frontend. Left out on a rotation with one lane, which never shows a name.
The windows: when the rotation is covered, and how often duty changes hands there.
One window of the proposed grid.
object
The window’s id, or a handle of your own for a window you are adding. Always required.
What to call this window, such as EMEA.
The time zone the covered hours below are read in, as a city identifier (Europe/Rome) or UTC. Fixed offsets are refused rather than guessed at.
The repeating week this window is open for. Leave it empty for a window that is open all week, which is what a rotation with no restricted hours has.
One stretch of the coverage week, which may run past midnight into the next day.
object
A weekday name, monday through sunday, lower case.
A time of day, HH:mm.
How often duty changes hands in this window. Leave it out to keep the cadence this window already has: a caller changing the hours must not flatten the handover as a side effect.
object
One of dayOfWeek, daysOfWeekList, dayOfMonth, nthWeekdayOfMonth, daily or workday.
The time zone the schedule runs in, as a city identifier: Europe/Rome, or UTC. Fixed offsets and old spellings are refused rather than guessed at.
When the schedule starts, as an RFC 3339 timestamp. A value with no offset is read as UTC.
How many units of the schedule’s own kind sit between two hand-overs: 2 on a dayOfWeek schedule is fortnightly. Defaults to 1.
Whether hand-overs that land on a weekend move on. Defaults to false, and is always true for workday. Needs countryCodes: which days are the weekend is a fact about a country.
Whether hand-overs that land on a national holiday move on. Defaults to false, and is always true for workday. Needs countryCodes for the same reason.
The ISO 3166-1 alpha-2 countries whose weekends and holidays the skips are read from. At least one is required whenever either skip is on, and so on every workday schedule, which turns both on. Without one the skips would skip nothing while still reading as active.
For daysOfWeekList: the weekdays it hands over on, lower case (monday … sunday). At least one.
For nthWeekdayOfMonth: which weekday, lower case. Not used by dayOfWeek, which takes its day from startsAt.
For nthWeekdayOfMonth: which occurrences in the month, 1 through 5. At least one.
For daily: the times of day it hands over at, as HH:mm. At least one.
The list this window draws on in every lane, for a window you are adding. Send it and no entries of cells for the window, and one is written in each lane for you. Entries you send for the window are taken as sent, and a window the rotation already has refuses it.
Deprecated: use listId. Still accepted with the same meaning; when both are sent they have to agree.
Every lane crossed with every window, one entry each.
One lane in one window of the proposed grid.
object
The id of this lane in this window, or left out to create one.
The lane, naming one of the lanes in this body.
The window, naming one of the windows in play.
The list this lane is dealt from in this window, which is required on every entry.
Deprecated: use listId. Still accepted with the same meaning; when both are sent they have to agree.
Whether one person may be on duty in two lanes at once when the list behind them is too short to fill both. Defaults to false, which leaves the lanes it cannot fill empty.
Examplegenerated
{ "lanes": [ { "id": "example", "name": "example" } ], "windows": [ { "id": "example", "name": "example", "timeZone": "example", "coverage": [ { "startDay": "example", "startTime": "example", "endDay": "example", "endTime": "example" } ], "cadence": { "type": "example", "timeZone": "example", "startsAt": "example", "period": 1, "skipWeekends": true, "skipNationalHolidays": true, "countryCodes": [ "example" ], "daysOfWeek": [ "example" ], "dayOfWeek": "example", "weeksInMonth": [ 1 ], "times": [ "example" ] }, "listId": "example", "rosterId": "example" } ], "cells": [ { "id": "example", "laneId": "example", "windowId": "example", "listId": "example", "rosterId": "example" } ], "doubleCover": true}The grid PUT /v1/rotations/{rotationId}/coverage gives a rotation: its lanes, its coverage windows, and which list each lane draws on in each window.
object
The rows, in the order they should be dealt: the first lane is the primary one.
One row of the proposed grid.
object
The lane’s id, or a handle of your own for a lane you are adding. Always required.
What to call this lane, such as Primary or Frontend. Left out on a rotation with one lane, which never shows a name.
The windows: when the rotation is covered, and how often duty changes hands there.
One window of the proposed grid.
object
The window’s id, or a handle of your own for a window you are adding. Always required.
What to call this window, such as EMEA.
The time zone the covered hours below are read in, as a city identifier (Europe/Rome) or UTC. Fixed offsets are refused rather than guessed at.
The repeating week this window is open for. Leave it empty for a window that is open all week, which is what a rotation with no restricted hours has.
One stretch of the coverage week, which may run past midnight into the next day.
object
A weekday name, monday through sunday, lower case.
A time of day, HH:mm.
How often duty changes hands in this window. Leave it out to keep the cadence this window already has: a caller changing the hours must not flatten the handover as a side effect.
object
One of dayOfWeek, daysOfWeekList, dayOfMonth, nthWeekdayOfMonth, daily or workday.
The time zone the schedule runs in, as a city identifier: Europe/Rome, or UTC. Fixed offsets and old spellings are refused rather than guessed at.
When the schedule starts, as an RFC 3339 timestamp. A value with no offset is read as UTC.
How many units of the schedule’s own kind sit between two hand-overs: 2 on a dayOfWeek schedule is fortnightly. Defaults to 1.
Whether hand-overs that land on a weekend move on. Defaults to false, and is always true for workday. Needs countryCodes: which days are the weekend is a fact about a country.
Whether hand-overs that land on a national holiday move on. Defaults to false, and is always true for workday. Needs countryCodes for the same reason.
The ISO 3166-1 alpha-2 countries whose weekends and holidays the skips are read from. At least one is required whenever either skip is on, and so on every workday schedule, which turns both on. Without one the skips would skip nothing while still reading as active.
For daysOfWeekList: the weekdays it hands over on, lower case (monday … sunday). At least one.
For nthWeekdayOfMonth: which weekday, lower case. Not used by dayOfWeek, which takes its day from startsAt.
For nthWeekdayOfMonth: which occurrences in the month, 1 through 5. At least one.
For daily: the times of day it hands over at, as HH:mm. At least one.
The list this window draws on in every lane, for a window you are adding. Send it and no entries of cells for the window, and one is written in each lane for you. Entries you send for the window are taken as sent, and a window the rotation already has refuses it.
Deprecated: use listId. Still accepted with the same meaning; when both are sent they have to agree.
Every lane crossed with every window, one entry each.
One lane in one window of the proposed grid.
object
The id of this lane in this window, or left out to create one.
The lane, naming one of the lanes in this body.
The window, naming one of the windows in play.
The list this lane is dealt from in this window, which is required on every entry.
Deprecated: use listId. Still accepted with the same meaning; when both are sent they have to agree.
Whether one person may be on duty in two lanes at once when the list behind them is too short to fill both. Defaults to false, which leaves the lanes it cannot fill empty.
Examplegenerated
{ "lanes": [ { "id": "example", "name": "example" } ], "windows": [ { "id": "example", "name": "example", "timeZone": "example", "coverage": [ { "startDay": "example", "startTime": "example", "endDay": "example", "endTime": "example" } ], "cadence": { "type": "example", "timeZone": "example", "startsAt": "example", "period": 1, "skipWeekends": true, "skipNationalHolidays": true, "countryCodes": [ "example" ], "daysOfWeek": [ "example" ], "dayOfWeek": "example", "weeksInMonth": [ 1 ], "times": [ "example" ] }, "listId": "example", "rosterId": "example" } ], "cells": [ { "id": "example", "laneId": "example", "windowId": "example", "listId": "example", "rosterId": "example" } ], "doubleCover": true}The grid PUT /v1/rotations/{rotationId}/coverage gives a rotation: its lanes, its coverage windows, and which list each lane draws on in each window.
object
The rows, in the order they should be dealt: the first lane is the primary one.
One row of the proposed grid.
object
The lane’s id, or a handle of your own for a lane you are adding. Always required.
What to call this lane, such as Primary or Frontend. Left out on a rotation with one lane, which never shows a name.
The windows: when the rotation is covered, and how often duty changes hands there.
One window of the proposed grid.
object
The window’s id, or a handle of your own for a window you are adding. Always required.
What to call this window, such as EMEA.
The time zone the covered hours below are read in, as a city identifier (Europe/Rome) or UTC. Fixed offsets are refused rather than guessed at.
The repeating week this window is open for. Leave it empty for a window that is open all week, which is what a rotation with no restricted hours has.
One stretch of the coverage week, which may run past midnight into the next day.
object
A weekday name, monday through sunday, lower case.
A time of day, HH:mm.
How often duty changes hands in this window. Leave it out to keep the cadence this window already has: a caller changing the hours must not flatten the handover as a side effect.
object
One of dayOfWeek, daysOfWeekList, dayOfMonth, nthWeekdayOfMonth, daily or workday.
The time zone the schedule runs in, as a city identifier: Europe/Rome, or UTC. Fixed offsets and old spellings are refused rather than guessed at.
When the schedule starts, as an RFC 3339 timestamp. A value with no offset is read as UTC.
How many units of the schedule’s own kind sit between two hand-overs: 2 on a dayOfWeek schedule is fortnightly. Defaults to 1.
Whether hand-overs that land on a weekend move on. Defaults to false, and is always true for workday. Needs countryCodes: which days are the weekend is a fact about a country.
Whether hand-overs that land on a national holiday move on. Defaults to false, and is always true for workday. Needs countryCodes for the same reason.
The ISO 3166-1 alpha-2 countries whose weekends and holidays the skips are read from. At least one is required whenever either skip is on, and so on every workday schedule, which turns both on. Without one the skips would skip nothing while still reading as active.
For daysOfWeekList: the weekdays it hands over on, lower case (monday … sunday). At least one.
For nthWeekdayOfMonth: which weekday, lower case. Not used by dayOfWeek, which takes its day from startsAt.
For nthWeekdayOfMonth: which occurrences in the month, 1 through 5. At least one.
For daily: the times of day it hands over at, as HH:mm. At least one.
The list this window draws on in every lane, for a window you are adding. Send it and no entries of cells for the window, and one is written in each lane for you. Entries you send for the window are taken as sent, and a window the rotation already has refuses it.
Deprecated: use listId. Still accepted with the same meaning; when both are sent they have to agree.
Every lane crossed with every window, one entry each.
One lane in one window of the proposed grid.
object
The id of this lane in this window, or left out to create one.
The lane, naming one of the lanes in this body.
The window, naming one of the windows in play.
The list this lane is dealt from in this window, which is required on every entry.
Deprecated: use listId. Still accepted with the same meaning; when both are sent they have to agree.
Whether one person may be on duty in two lanes at once when the list behind them is too short to fill both. Defaults to false, which leaves the lanes it cannot fill empty.
Examplegenerated
{ "lanes": [ { "id": "example", "name": "example" } ], "windows": [ { "id": "example", "name": "example", "timeZone": "example", "coverage": [ { "startDay": "example", "startTime": "example", "endDay": "example", "endTime": "example" } ], "cadence": { "type": "example", "timeZone": "example", "startsAt": "example", "period": 1, "skipWeekends": true, "skipNationalHolidays": true, "countryCodes": [ "example" ], "daysOfWeek": [ "example" ], "dayOfWeek": "example", "weeksInMonth": [ 1 ], "times": [ "example" ] }, "listId": "example", "rosterId": "example" } ], "cells": [ { "id": "example", "laneId": "example", "windowId": "example", "listId": "example", "rosterId": "example" } ], "doubleCover": true}Responses
Section titled “Responses”OK
A rotation: the grid of duties it runs, who is in it, and who is on duty in each lane and window right now.
object
The short code the rotation answers to in Slack.
Whether every member of the workspace can see the rotation.
manual, auto or external.
How many lanes are running, which is how many people hold the shift at once.
How many lanes in windows on this rotation have somebody on duty right now.
How many lanes in windows on this rotation have nobody on them at all.
Whether this rotation has more than one lane or window to be on duty in at once.
Whether one person may be on duty in two lanes at once when the list behind them is too short to fill both.
Whether days the cadence skips (weekends, national holidays) count as time the rotation is not covered. One switch for the whole rotation, read into every window’s own reading.
The channels this rotation posts in: the same facts as channelSettings, flattened to the ids that receive duty messages.
Every channel this rotation uses, each saying what Round Robin does in it. Write one with PUT /v1/rotations/{rotationId}/channels/{channelId}.
One Slack channel a rotation uses, and what Round Robin does in it.
object
The Slack channel id, for example C0123456789.
Whether hand-overs, reminders and mentions of this rotation are posted in this channel.
Whether this channel’s topic is rewritten with whoever is on duty when duty changes hands. Reported as false on every channel when enableTopic is off, whatever the channel itself holds, so a reader never has to combine two fields to know whether a topic is written.
Whether the rotation keeps channel topics pointed at whoever is on duty. The switch for the whole rotation: with it off, no channel’s topic is written whatever its own syncsTopic says.
The template the topic is written from, or null to use Round Robin’s own wording. Shares its placeholders with the message templates, which are not part of this version.
Everybody in the rotation: the union across every list it draws on.
object
Members added individually.
One member of a rotation.
object
Where the member sits in the order the lists are built from.
Members that came in through a Slack user group, listed under the group they came from. Add or remove somebody in Slack’s group and the rotation follows.
A Slack user group in the rotation, and the people currently in it.
object
One member of a rotation.
object
Where the member sits in the order the lists are built from.
The rows of the grid: the kinds of duty this rotation runs.
A row of the grid: a kind of duty, such as primary or backend.
object
What the customer calls this lane, and absent until they name it.
The windows of the grid: covered hours, a time zone, and a handover cadence.
A window of the grid: when the rotation is covered, and how often duty changes hands there.
object
The one zone this window’s covered hours are expressed in, as its own identifier (Europe/Rome). Never rewritten to the tzdb canonical name a linked city shares. Empty on a manual rotation, which has no cadence and so no zone to express one in.
The repeating week this window is open for, as stored. Empty means the whole week.
One stretch of the coverage week, which may run past midnight into the next day.
object
A weekday name, monday through sunday.
A time of day, HH:mm.
Whether the window restricts nothing: open the whole week, every week.
How often duty changes hands in this window.
object
One of dayOfWeek, daysOfWeekList, dayOfMonth, nthWeekdayOfMonth, daily, workday, manual or external. Fields that mean nothing for the type are absent rather than defaulted, so test for presence rather than for a zero.
The time zone the cadence was configured with, as its own identifier (Europe/Rome). Never rewritten to the tzdb canonical name a linked city shares.
When the cadence starts, in its own time zone.
How many units of the cadence’s own kind sit between two hand-overs.
The countries whose weekends and holidays the skips are read from.
The next hand-overs this window has already scheduled. For anything further out, ask for a window from GET /v1/rotations/{rotationId}/schedule.
Set for dayOfWeek and nthWeekdayOfMonth.
Set for daysOfWeekList.
Set for dayOfMonth.
Set for nthWeekdayOfMonth: which occurrences in the month, 1 through 5.
Set for daily: the times of day it hands over at.
Set for external: which partner drives the rotation. One of pagerDuty, jsm for Jira Service Management, or none when the rotation is external but no partner is linked yet.
Whether the window is open at the moment of the response.
Every lane crossed with every window, and whoever holds each one.
A lane crossed with a window: where somebody can be on duty.
object
Which list this lane is dealt from in this window, matching an entry in the rotation’s lists.
Deprecated: use listId, which carries the same value.
Whether this lane in this window is defined but not running, because the workspace is not on a paid plan.
Whoever is on duty here, or nothing.
object
The Slack user holding the lane in this window, or null when a partner named somebody Slack cannot.
Their position in the list this lane is dealt from, and absent for a person a partner named, who was never dealt from a list at all.
Whether they are waiting for the window to open rather than on duty right now.
End of this holder’s current stretch of cover: the window closing, or the turn ending if that comes first. Null while nothing bounds the stretch, and while the holder is not covering (the window is shut or the holder is waiting): nextCoverage.startUtc gives when cover resumes.
When this holder’s turn ends: the next hand-over of the lane in its window, which can be later than coveredUntil when the window closes first. Null where nothing hands it over.
Members the list would otherwise have named, who were passed over because they were absent. A skip, decided once before the shift starts, rather than a hand-over of part of one.
A member skipped because of an absence at assignment time.
object
Slack user ID of the skipped member.
Absence start in UTC, when known.
Absence end in UTC, when known.
Absence source: googleCalendar or internalAvailability. Null when the source is unknown.
The lists this rotation deals from, each in the order this rotation deals it.
A list this rotation deals from, in the order this rotation deals it.
object
The list this order belongs to. Absent on a rotation whose people are not on a shared list yet.
The list’s name. Absent when the list could not be read.
The turn order: who is dealt, and in what order.
One position in a turn order.
object
Set when the member is in the order by way of a user group.
The turn the next handover deals from.
Deprecated: use lists, which carries the same entries under the name listId.
Deprecated: use lists, whose entries carry the same values under the name listId.
object
Deprecated: use listId on lists.
The list’s name. Absent when the list could not be read.
The turn order: who is dealt, and in what order.
One position in a turn order.
object
Set when the member is in the order by way of a user group.
The turn the next handover deals from.
The Slack user group kept in sync with whoever is on duty.
The on-duty resource, embedded, so the common question needs no second call.
object
Current external assignment summary, including unmapped participants, empty slots and the next known boundary.
object
UTC instant used to evaluate current assignments and coverage.
Freshness: fresh, stale or unavailable. Fresh data covers asOfUtc, agrees with synchronized assignments and has no failed read at or after the last success.
Why there is no usable answer: switchedOff (the rotation is off, nobody is on duty), bindingMissing (no binding to the partner’s schedule), notReadYet (no successful read yet) or snapshotNotCurrent (the last read does not cover asOfUtc). Null when the summary answers. With a reason set, current is empty and nobody is claimed to be assigned.
Coverage: assigned when a user assignment is active; empty when only explicit empty assignments are active; gap for a confirmed interval with no assignments; otherwise unknown.
Time of the last successful provider read, or null when none is recorded.
Time of the last failed provider read, or null when none is recorded.
Inclusive start of the saved provider snapshot. Check state before using its coverage.
Exclusive end of the saved provider snapshot. Later coverage is unknown.
Synchronized assignments active at asOfUtc, including unmapped participants, duplicate assignments and explicit empty slots.
One external assignment interval, including an explicitly unassigned slot.
object
Stable local identity of a synchronized occurrence. Null for a future assignment without a synchronized identity.
Identifier of the lane in a window holding the synchronized assignment, or null for a future assignment without a stored one.
Mapped Slack user ID. Null for unmapped participants and explicit empty slots.
Display label for an unmapped participant: provider name, email address or participant ID. Null for mapped users and empty slots.
Provider email address when available. Null for explicit empty slots or when no email is available.
Inclusive start of this assignment interval in UTC.
Exclusive end of this assignment interval in UTC.
Provider metadata for this assignment.
object
Assignment member kind: user or empty.
Provider participant ID for a user assignment. Null for an empty slot.
Provider source type: schedule_rotation, custom_shift, schedule_rotation_override or custom_shift_override.
Provider rotation ID for a rotation or rotation-override source.
Provider custom-shift ID for a custom-shift or custom-shift-override source.
Provider override ID for an override source.
Original provider start of the occurrence in UTC.
Provider end of the occurrence in UTC.
Number of current assignments, including explicit empty slots. This is an assignment count, not a staffing target.
Number of current user assignments, including unmapped participants and duplicate assignments.
Last provider read failure code, or null when none is recorded. Check state and the read timestamps for current freshness.
Distinct current responders, deduplicated by Slack user ID when mapped and provider participant ID otherwise.
Distinct provider participant IDs among current user assignments.
Current user assignments without a Slack mapping. Duplicate assignments count separately.
Current assignments that the provider explicitly leaves unassigned.
Next known boundary after asOfUtc, or null when none is known. Stale data supplies known ends only, without future starts.
object
UTC instant of the assignment boundary.
Assignments starting at atUtc, available only from a fresh provider snapshot.
One external assignment interval, including an explicitly unassigned slot.
object
Stable local identity of a synchronized occurrence. Null for a future assignment without a synchronized identity.
Identifier of the lane in a window holding the synchronized assignment, or null for a future assignment without a stored one.
Mapped Slack user ID. Null for unmapped participants and explicit empty slots.
Display label for an unmapped participant: provider name, email address or participant ID. Null for mapped users and empty slots.
Provider email address when available. Null for explicit empty slots or when no email is available.
Inclusive start of this assignment interval in UTC.
Exclusive end of this assignment interval in UTC.
Provider metadata for this assignment.
object
Assignment member kind: user or empty.
Provider participant ID for a user assignment. Null for an empty slot.
Provider source type: schedule_rotation, custom_shift, schedule_rotation_override or custom_shift_override.
Provider rotation ID for a rotation or rotation-override source.
Provider custom-shift ID for a custom-shift or custom-shift-override source.
Provider override ID for an override source.
Original provider start of the occurrence in UTC.
Provider end of the occurrence in UTC.
Current assignments whose end is later than atUtc.
One external assignment interval, including an explicitly unassigned slot.
object
Stable local identity of a synchronized occurrence. Null for a future assignment without a synchronized identity.
Identifier of the lane in a window holding the synchronized assignment, or null for a future assignment without a stored one.
Mapped Slack user ID. Null for unmapped participants and explicit empty slots.
Display label for an unmapped participant: provider name, email address or participant ID. Null for mapped users and empty slots.
Provider email address when available. Null for explicit empty slots or when no email is available.
Inclusive start of this assignment interval in UTC.
Exclusive end of this assignment interval in UTC.
Provider metadata for this assignment.
object
Assignment member kind: user or empty.
Provider participant ID for a user assignment. Null for an empty slot.
Provider source type: schedule_rotation, custom_shift, schedule_rotation_override or custom_shift_override.
Provider rotation ID for a rotation or rotation-override source.
Provider custom-shift ID for a custom-shift or custom-shift-override source.
Provider override ID for an override source.
Original provider start of the occurrence in UTC.
Provider end of the occurrence in UTC.
Current assignments ending at atUtc.
One external assignment interval, including an explicitly unassigned slot.
object
Stable local identity of a synchronized occurrence. Null for a future assignment without a synchronized identity.
Identifier of the lane in a window holding the synchronized assignment, or null for a future assignment without a stored one.
Mapped Slack user ID. Null for unmapped participants and explicit empty slots.
Display label for an unmapped participant: provider name, email address or participant ID. Null for mapped users and empty slots.
Provider email address when available. Null for explicit empty slots or when no email is available.
Inclusive start of this assignment interval in UTC.
Exclusive end of this assignment interval in UTC.
Provider metadata for this assignment.
object
Assignment member kind: user or empty.
Provider participant ID for a user assignment. Null for an empty slot.
Provider source type: schedule_rotation, custom_shift, schedule_rotation_override or custom_shift_override.
Provider rotation ID for a rotation or rotation-override source.
Provider custom-shift ID for a custom-shift or custom-shift-override source.
Provider override ID for an override source.
Original provider start of the occurrence in UTC.
Provider end of the occurrence in UTC.
Rotation ID.
Why nobody is on duty: nobody-on-call-unplanned when a running lane in an open window has nobody in it, nobody-on-call-as-arranged when every running lane is shut by its hours. The two spellings the duty history uses. Absent while any lane is live, even if another lane has no one: an empty onCall with no reason here is a person with no Slack identity, so read externalAssignments or unmappedExternalDuty. Lanes a downgrade stopped count for neither.
Current mapped Slack assignments. An empty list does not establish a coverage gap: check externalAssignments or unmappedExternalDuty.
One current mapped Slack assignment. A user can appear more than once when they hold multiple assignments.
object
Slack user ID of the person on duty.
Position in the native turn order. External assignments have no native turn order.
Identifier of the lane in a window holding this assignment.
The lane. Lanes for external assignments do not identify provider roles.
Lane name, when available.
The window. External assignment windows do not define provider recurrence.
Window name, when available.
Assignment start in UTC, when known.
Exclusive end in UTC of this stretch of cover: the window closing, or the turn ending if that comes first. Null while nothing bounds the stretch.
When this person’s turn ends in UTC: the next hand-over of the lane in its window, which can be later than coveredUntil when the window closes first. Null where nothing hands it over.
Members skipped for absence when this assignment began.
A member skipped because of an absence at assignment time.
object
Slack user ID of the skipped member.
Absence start in UTC, when known.
Absence end in UTC, when known.
Absence source: googleCalendar or internalAvailability. Null when the source is unknown.
Who takes each lane next, one entry per running lane in each window of a native rotation, earliest start first, ties in window order and then lane order. A lane whose window is shut lists the person who comes back when it opens (comingBack); otherwise the person its next hand-over deals. Absences are not resolved, since the scheduler skips somebody who is away only when it deals. For a window nothing fires on, the entry is what a rotate of the whole rotation does: a lane nobody on its list is free to take has no entry and is listed in seatsWithNobodyFree. Empty for a randomised rotation, which draws at the hand-over, for a switched-off rotation, and for a provider-owned one (read externalAssignments).
The person who takes one lane in a window next, and when.
object
Slack user ID of the person who takes the lane.
Their position in the native turn order.
Identifier of the lane in a window the person takes.
The lane.
Lane name, when available.
The window.
Window name, when available.
When the person takes the lane in UTC: the window’s next hand-over, or the moment it opens where the same person is coming back. Null where the window has no computed firing (a manual one).
When their turn ends in UTC, where the window has a hand-over after that.
Whether this is the lane’s holder resuming when a shut window opens, rather than a new person being dealt. Read since as a hand-over only where this is false.
The lanes in a window that a rotate leaves as they are, because nobody on their list is free: everyone on the list either holds this lane or stays on duty in a lane the rotate does not change. Such a lane has no entry in nextOnCall. Listed only for a window nothing fires on, which is handed over by a rotate; empty for a window that hands over on a schedule, for a randomised rotation, for a switched-off rotation, and for a provider-owned one.
A lane in a window that a rotate leaves as it is, because nobody on its list is free to take it.
object
Identifier of the lane in a window, the same cellId the on-call entries carry.
The lane.
Lane name, when available.
The window.
Window name, when available.
Single unmapped duty for an external schedule without externalAssignments. Null when externalAssignments is present.
object
Provider email address.
Provider display name, when available.
Exclusive assignment end in UTC, when known.
Directory records for current mapped Slack users and skipped members when ?expand=users is requested. Null otherwise. Expansion disables ETag validation.
A Slack user, as Round Robin knows them.
object
The Slack user id.
The workspace that owns this person’s directory entry, which under Enterprise Grid can differ from the calling key’s workspace.
Null when the install was never granted users:read.email, not only when unknown.
A Slack Connect person: visible through a shared channel, never a member of the workspace.
Deactivated in Slack, or gone from the workspace. These people are still answered rather than hidden, so an id a rotation still names resolves to something you can render. A person nothing in the workspace names any more (no rotation, role, partner schedule mapping, or open cover, swap or arrangement) is removed 30 days after they left. Their id then answers 404 on this endpoint, on the availability of a person and on a person’s shifts.
The person’s Slack avatar, at 192px.
The person’s Slack time zone, as an IANA identifier (Europe/Rome). Absent when Round Robin has not seen one for them.
Examplegenerated
{ "id": "example", "name": "example", "description": "example", "code": "example", "enabled": true, "public": true, "mode": "example", "runningLanes": 1, "heldSeats": 1, "openSeats": 1, "isGrid": true, "doubleCover": true, "skipsAreOffTime": true, "owners": [ "example" ], "channels": [ "example" ], "channelSettings": [ { "channelId": "example", "postsMessages": true, "syncsTopic": true } ], "enableTopic": true, "topicTemplate": "example", "members": { "users": [ { "userId": "example", "sequenceNumber": 1 } ], "userGroups": [ { "userGroupId": "example", "users": [ { "userId": "example", "sequenceNumber": 1 } ] } ] }, "lanes": [ { "id": "example", "name": "example" } ], "windows": [ { "id": "example", "name": "example", "timeZone": "example", "coverage": [ { "startDay": "example", "startTime": "example", "endDay": "example", "endTime": "example" } ], "alwaysOpen": true, "cadence": { "type": "example", "timeZone": "example", "startsAt": "2026-04-15T12:00:00Z", "period": 1, "skipWeekends": true, "skipNationalHolidays": true, "countryCodes": [ "example" ], "nextEvents": [ "2026-04-15T12:00:00Z" ], "dayOfWeek": "example", "daysOfWeek": [ "example" ], "dayOfMonth": 1, "weeksInMonth": [ 1 ], "times": [ "example" ], "partner": "example" }, "openNow": true, "currentCoverage": { "startUtc": "2026-04-15T12:00:00Z", "endUtc": "2026-04-15T12:00:00Z" }, "nextCoverage": { "startUtc": "2026-04-15T12:00:00Z", "endUtc": "2026-04-15T12:00:00Z" } } ], "cells": [ { "id": "example", "laneId": "example", "windowId": "example", "listId": "example", "rosterId": "example", "stopped": true, "holder": { "userId": "example", "externalUser": { "email": "example", "name": "example" }, "turn": 1, "waiting": true, "since": "2026-04-15T12:00:00Z", "coveredUntil": "2026-04-15T12:00:00Z", "turnEnds": "2026-04-15T12:00:00Z", "skippedForAbsence": [ { "userId": "example", "from": "2026-04-15T12:00:00Z", "until": "2026-04-15T12:00:00Z", "source": "example" } ] } } ], "lists": [ { "listId": "example", "name": "example", "order": [ { "userId": "example", "userGroupId": "example", "turn": 1 } ], "nextTurn": 1 } ], "rosters": [ { "rosterId": "example", "name": "example", "order": [ { "userId": "example", "userGroupId": "example", "turn": 1 } ], "nextTurn": 1 } ], "onDutyUserGroupId": "example", "onCall": { "externalAssignments": { "asOfUtc": "2026-04-15T12:00:00Z", "state": "example", "noAnswerReason": "example", "coverage": "example", "lastSuccessfulReadUtc": "2026-04-15T12:00:00Z", "lastReadFailureUtc": "2026-04-15T12:00:00Z", "knownFromUtc": "2026-04-15T12:00:00Z", "knownUntilUtc": "2026-04-15T12:00:00Z", "current": [ { "localAssignmentId": "example", "cellId": "example", "user": "example", "externalName": "example", "externalEmail": "example", "sinceUtc": "2026-04-15T12:00:00Z", "untilUtc": "2026-04-15T12:00:00Z", "externalAssignment": { "memberKind": "example", "participantId": "example", "sourceType": "example", "rotationId": "example", "shiftId": "example", "overrideId": "example", "originalStartUtc": "2026-04-15T12:00:00Z", "originalEndUtc": "2026-04-15T12:00:00Z" } } ], "requiredAssignmentCount": 1, "assignedAssignmentCount": 1, "lastReadFailure": "example", "distinctResponderCount": 1, "distinctParticipantCount": 1, "unmappedAssignmentCount": 1, "emptyAssignmentCount": 1, "nextChange": { "atUtc": "2026-04-15T12:00:00Z", "starting": [ { "localAssignmentId": "example", "cellId": "example", "user": "example", "externalName": "example", "externalEmail": "example", "sinceUtc": "2026-04-15T12:00:00Z", "untilUtc": "2026-04-15T12:00:00Z", "externalAssignment": { "memberKind": "example", "participantId": "example", "sourceType": "example", "rotationId": "example", "shiftId": "example", "overrideId": "example", "originalStartUtc": "2026-04-15T12:00:00Z", "originalEndUtc": "2026-04-15T12:00:00Z" } } ], "continuing": [ { "localAssignmentId": "example", "cellId": "example", "user": "example", "externalName": "example", "externalEmail": "example", "sinceUtc": "2026-04-15T12:00:00Z", "untilUtc": "2026-04-15T12:00:00Z", "externalAssignment": { "memberKind": "example", "participantId": "example", "sourceType": "example", "rotationId": "example", "shiftId": "example", "overrideId": "example", "originalStartUtc": "2026-04-15T12:00:00Z", "originalEndUtc": "2026-04-15T12:00:00Z" } } ], "ending": [ { "localAssignmentId": "example", "cellId": "example", "user": "example", "externalName": "example", "externalEmail": "example", "sinceUtc": "2026-04-15T12:00:00Z", "untilUtc": "2026-04-15T12:00:00Z", "externalAssignment": { "memberKind": "example", "participantId": "example", "sourceType": "example", "rotationId": "example", "shiftId": "example", "overrideId": "example", "originalStartUtc": "2026-04-15T12:00:00Z", "originalEndUtc": "2026-04-15T12:00:00Z" } } ] } }, "rotationId": "example", "nobodyOnCallReason": "example", "onCall": [ { "userId": "example", "turn": 1, "cellId": "example", "laneId": "example", "laneName": "example", "windowId": "example", "windowName": "example", "since": "2026-04-15T12:00:00Z", "coveredUntil": "2026-04-15T12:00:00Z", "turnEnds": "2026-04-15T12:00:00Z", "skippedForAbsence": [ { "userId": "example", "from": "2026-04-15T12:00:00Z", "until": "2026-04-15T12:00:00Z", "source": "example" } ] } ], "nextOnCall": [ { "userId": "example", "turn": 1, "cellId": "example", "laneId": "example", "laneName": "example", "windowId": "example", "windowName": "example", "since": "2026-04-15T12:00:00Z", "turnEnds": "2026-04-15T12:00:00Z", "comingBack": true } ], "seatsWithNobodyFree": [ { "cellId": "example", "laneId": "example", "laneName": "example", "windowId": "example", "windowName": "example" } ], "unmappedExternalDuty": { "email": "example", "name": "example", "until": "2026-04-15T12:00:00Z" }, "users": [ { "id": "example", "teamId": "example", "displayName": "example", "realName": "example", "email": "example", "isGuest": true, "isExternal": true, "isDeleted": true, "avatarUrl": "example", "timeZone": "example" } ] }, "createdAt": "2026-04-15T12:00:00Z", "updatedAt": "2026-04-15T12:00:00Z"}Bad Request
object
Examplegenerated
{ "type": "example", "title": "example", "status": 1, "detail": "example", "instance": "example"}Unauthorized
object
Examplegenerated
{ "type": "example", "title": "example", "status": 1, "detail": "example", "instance": "example"}Payment Required
object
Examplegenerated
{ "type": "example", "title": "example", "status": 1, "detail": "example", "instance": "example"}Forbidden
object
Examplegenerated
{ "type": "example", "title": "example", "status": 1, "detail": "example", "instance": "example"}Not Found
object
Examplegenerated
{ "type": "example", "title": "example", "status": 1, "detail": "example", "instance": "example"}Conflict
object
Examplegenerated
{ "type": "example", "title": "example", "status": 1, "detail": "example", "instance": "example"}Precondition Failed
object
Examplegenerated
{ "type": "example", "title": "example", "status": 1, "detail": "example", "instance": "example"}Precondition Required
object
Examplegenerated
{ "type": "example", "title": "example", "status": 1, "detail": "example", "instance": "example"}