Set who is on duty
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/on-call"), Headers = { { "If-Match", "example" }, { "Authorization", "Bearer <token>" }, }, Content = new StringContent("{ \"userIds\": [ \"example\" ] }") { Headers = { ContentType = new MediaTypeHeaderValue("application/*+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/on-call"
payload := strings.NewReader("{ \"userIds\": [ \"example\" ] }")
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")
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");RequestBody body = RequestBody.create(mediaType, "{ \"userIds\": [ \"example\" ] }");Request request = new Request.Builder() .url("https://api.roundrobinbot.eu/v1/rotations/example/on-call") .put(body) .addHeader("If-Match", "example") .addHeader("Authorization", "Bearer <token>") .addHeader("Content-Type", "application/*+json") .build();
Response response = client.newCall(request).execute();import axios from 'axios';
const options = { method: 'PUT', url: 'https://api.roundrobinbot.eu/v1/rotations/example/on-call', headers: { 'If-Match': 'example', Authorization: 'Bearer <token>', 'Content-Type': 'application/*+json' }, data: '{ "userIds": [ "example" ] }'};
try { const { data } = await axios.request(options); console.log(data);} catch (error) { console.error(error);}const url = 'https://api.roundrobinbot.eu/v1/rotations/example/on-call';const options = { method: 'PUT', headers: { 'If-Match': 'example', Authorization: 'Bearer <token>', 'Content-Type': 'application/*+json' }, body: '{ "userIds": [ "example" ] }'};
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/on-call \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/*+json' \ --header 'If-Match: example' \ --data '{ "userIds": [ "example" ] }'Puts the people you name on duty, replacing whoever holds the shift now. They must be members of the rotation, and userIds must name at least one: an empty list is refused rather than read as “take everybody off duty”. Answers with the new on-call state and a fresh ETag. Naming the people who already hold the seats they would take changes nobody’s duty. When they were already put there by name, nothing is written and the same ETag comes back.
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 body of PUT /v1/rotations/{rotationId}/on-call: who should be on duty.
object
The Slack user ids to put on duty. At least one, and each must be a member of the rotation.
Examplegenerated
{ "userIds": [ "example" ]}The body of PUT /v1/rotations/{rotationId}/on-call: who should be on duty.
object
The Slack user ids to put on duty. At least one, and each must be a member of the rotation.
Examplegenerated
{ "userIds": [ "example" ]}The body of PUT /v1/rotations/{rotationId}/on-call: who should be on duty.
object
The Slack user ids to put on duty. At least one, and each must be a member of the rotation.
Examplegenerated
{ "userIds": [ "example" ]}The body of PUT /v1/rotations/{rotationId}/on-call: who should be on duty.
object
The Slack user ids to put on duty. At least one, and each must be a member of the rotation.
Examplegenerated
{ "userIds": [ "example" ]}Responses
Section titled “Responses”OK
Current on-call assignments for a rotation. Responses with externalAssignments have no ETag; read the assignment freshness and coverage fields on each response.
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.
Number of current user assignments, including unmapped participants and duplicate assignments.
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.
Synchronized assignments active at asOfUtc, including unmapped participants, duplicate assignments and explicit empty slots.
One external assignment interval, including an explicitly unassigned slot.
object
Cell holding the synchronized assignment, or null for a future assignment without a stored cell.
Provider metadata for this assignment.
object
Assignment member kind: user or empty.
Provider end of the occurrence in UTC.
Original provider start of the occurrence in UTC.
Provider override ID for an override source.
Provider participant ID for a user assignment. Null for an empty slot.
Provider rotation ID for a rotation or rotation-override source.
Provider custom-shift ID for a custom-shift or custom-shift-override source.
Provider source type: schedule_rotation, custom_shift, schedule_rotation_override or custom_shift_override.
Provider email address when available. Null for explicit empty slots or when no email is available.
Display label for an unmapped participant: provider name, email address or participant ID. Null for mapped users and empty slots.
Stable local identity of a synchronized occurrence. Null for a future assignment without a synchronized identity.
Inclusive start of this assignment interval in UTC.
Exclusive end of this assignment interval in UTC.
Mapped Slack user ID. Null for unmapped participants and explicit empty slots.
Distinct provider participant IDs among current user assignments.
Distinct current responders, deduplicated by Slack user ID when mapped and provider participant ID otherwise.
Current assignments that the provider explicitly leaves unassigned.
Inclusive start of the saved provider snapshot. Check state before using its coverage.
Exclusive end of the saved provider snapshot. Later coverage is unknown.
Last provider read failure code, or null when none is recorded. Check state and the read timestamps for current freshness.
Time of the last failed provider read, or null when none is recorded.
Time of the last successful provider read, or null when none is recorded.
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.
Current assignments whose end is later than atUtc.
One external assignment interval, including an explicitly unassigned slot.
object
Cell holding the synchronized assignment, or null for a future assignment without a stored cell.
Provider metadata for this assignment.
object
Assignment member kind: user or empty.
Provider end of the occurrence in UTC.
Original provider start of the occurrence in UTC.
Provider override ID for an override source.
Provider participant ID for a user assignment. Null for an empty slot.
Provider rotation ID for a rotation or rotation-override source.
Provider custom-shift ID for a custom-shift or custom-shift-override source.
Provider source type: schedule_rotation, custom_shift, schedule_rotation_override or custom_shift_override.
Provider email address when available. Null for explicit empty slots or when no email is available.
Display label for an unmapped participant: provider name, email address or participant ID. Null for mapped users and empty slots.
Stable local identity of a synchronized occurrence. Null for a future assignment without a synchronized identity.
Inclusive start of this assignment interval in UTC.
Exclusive end of this assignment interval in UTC.
Mapped Slack user ID. Null for unmapped participants and explicit empty slots.
Current assignments ending at atUtc.
One external assignment interval, including an explicitly unassigned slot.
object
Cell holding the synchronized assignment, or null for a future assignment without a stored cell.
Provider metadata for this assignment.
object
Assignment member kind: user or empty.
Provider end of the occurrence in UTC.
Original provider start of the occurrence in UTC.
Provider override ID for an override source.
Provider participant ID for a user assignment. Null for an empty slot.
Provider rotation ID for a rotation or rotation-override source.
Provider custom-shift ID for a custom-shift or custom-shift-override source.
Provider source type: schedule_rotation, custom_shift, schedule_rotation_override or custom_shift_override.
Provider email address when available. Null for explicit empty slots or when no email is available.
Display label for an unmapped participant: provider name, email address or participant ID. Null for mapped users and empty slots.
Stable local identity of a synchronized occurrence. Null for a future assignment without a synchronized identity.
Inclusive start of this assignment interval in UTC.
Exclusive end of this assignment interval in UTC.
Mapped Slack user ID. Null for unmapped participants and explicit empty slots.
Assignments starting at atUtc, available only from a fresh provider snapshot.
One external assignment interval, including an explicitly unassigned slot.
object
Cell holding the synchronized assignment, or null for a future assignment without a stored cell.
Provider metadata for this assignment.
object
Assignment member kind: user or empty.
Provider end of the occurrence in UTC.
Original provider start of the occurrence in UTC.
Provider override ID for an override source.
Provider participant ID for a user assignment. Null for an empty slot.
Provider rotation ID for a rotation or rotation-override source.
Provider custom-shift ID for a custom-shift or custom-shift-override source.
Provider source type: schedule_rotation, custom_shift, schedule_rotation_override or custom_shift_override.
Provider email address when available. Null for explicit empty slots or when no email is available.
Display label for an unmapped participant: provider name, email address or participant ID. Null for mapped users and empty slots.
Stable local identity of a synchronized occurrence. Null for a future assignment without a synchronized identity.
Inclusive start of this assignment interval in UTC.
Exclusive end of this assignment interval in UTC.
Mapped Slack user ID. Null for unmapped participants and explicit empty slots.
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.
Number of current assignments, including explicit empty slots. This is an assignment count, not a staffing target.
Freshness: fresh, stale or unavailable. Fresh data covers asOfUtc, agrees with synchronized assignments and has no failed read at or after the last success.
Current user assignments without a Slack mapping. Duplicate assignments count separately.
Who takes each seat next, one entry per running seat of a native rotation, earliest start first, ties in window order and then lane order. A seat 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. 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 seat next, and when.
object
Cell the person takes.
Whether this is the seat’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.
Lane containing the cell.
Lane name, when available.
When the person takes the seat 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).
Their position in the native turn order.
When their turn ends in UTC, where the window has a hand-over after that.
Slack user ID of the person who takes the seat.
Window containing the cell.
Window name, when available.
Why nobody is on call: nobody-on-call-unplanned when a running place is open and has nobody in it, nobody-on-call-as-arranged when every running place is shut by its hours. The two spellings the duty history uses. Absent while any place 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. Places 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
Cell holding this assignment.
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.
Lane containing the cell. Lanes for external assignments do not identify provider roles.
Lane name, when available.
Assignment start in UTC, when known.
Members skipped for absence when this assignment began.
A member skipped because of an absence at assignment time.
object
Absence start in UTC, when known.
Absence source: googleCalendar or internalAvailability. Null when the source is unknown.
Absence end in UTC, when known.
Slack user ID of the skipped member.
Position in the native turn order. External assignments have no native turn order.
When this person’s turn ends in UTC: the next hand-over of the seat, which can be later than coveredUntil when the window closes first. Null where nothing hands the seat over.
Slack user ID of the person on duty.
Window containing the cell. External assignment windows do not define provider recurrence.
Window name, when available.
Rotation ID.
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 person’s Slack avatar, at 192px.
Null when the install was never granted users:read.email, not only when unknown.
The Slack user id.
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 Slack Connect person: visible through a shared channel, never a member of the workspace.
The workspace that owns this person’s directory entry, which under Enterprise Grid can differ from the calling key’s workspace.
The person’s Slack time zone, as an IANA identifier (Europe/Rome). Absent when Round Robin has not seen one for them.
Examplegenerated
{ "externalAssignments": { "asOfUtc": "2026-04-15T12:00:00Z", "assignedAssignmentCount": 1, "coverage": "example", "current": [ { "cellId": "example", "externalAssignment": { "memberKind": "example", "originalEndUtc": "2026-04-15T12:00:00Z", "originalStartUtc": "2026-04-15T12:00:00Z", "overrideId": "example", "participantId": "example", "rotationId": "example", "shiftId": "example", "sourceType": "example" }, "externalEmail": "example", "externalName": "example", "localAssignmentId": "example", "sinceUtc": "2026-04-15T12:00:00Z", "untilUtc": "2026-04-15T12:00:00Z", "user": "example" } ], "distinctParticipantCount": 1, "distinctResponderCount": 1, "emptyAssignmentCount": 1, "knownFromUtc": "2026-04-15T12:00:00Z", "knownUntilUtc": "2026-04-15T12:00:00Z", "lastReadFailure": "example", "lastReadFailureUtc": "2026-04-15T12:00:00Z", "lastSuccessfulReadUtc": "2026-04-15T12:00:00Z", "nextChange": { "atUtc": "2026-04-15T12:00:00Z", "continuing": [ { "cellId": "example", "externalAssignment": { "memberKind": "example", "originalEndUtc": "2026-04-15T12:00:00Z", "originalStartUtc": "2026-04-15T12:00:00Z", "overrideId": "example", "participantId": "example", "rotationId": "example", "shiftId": "example", "sourceType": "example" }, "externalEmail": "example", "externalName": "example", "localAssignmentId": "example", "sinceUtc": "2026-04-15T12:00:00Z", "untilUtc": "2026-04-15T12:00:00Z", "user": "example" } ], "ending": [ { "cellId": "example", "externalAssignment": { "memberKind": "example", "originalEndUtc": "2026-04-15T12:00:00Z", "originalStartUtc": "2026-04-15T12:00:00Z", "overrideId": "example", "participantId": "example", "rotationId": "example", "shiftId": "example", "sourceType": "example" }, "externalEmail": "example", "externalName": "example", "localAssignmentId": "example", "sinceUtc": "2026-04-15T12:00:00Z", "untilUtc": "2026-04-15T12:00:00Z", "user": "example" } ], "starting": [ { "cellId": "example", "externalAssignment": { "memberKind": "example", "originalEndUtc": "2026-04-15T12:00:00Z", "originalStartUtc": "2026-04-15T12:00:00Z", "overrideId": "example", "participantId": "example", "rotationId": "example", "shiftId": "example", "sourceType": "example" }, "externalEmail": "example", "externalName": "example", "localAssignmentId": "example", "sinceUtc": "2026-04-15T12:00:00Z", "untilUtc": "2026-04-15T12:00:00Z", "user": "example" } ] }, "noAnswerReason": "example", "requiredAssignmentCount": 1, "state": "example", "unmappedAssignmentCount": 1 }, "nextOnCall": [ { "cellId": "example", "comingBack": true, "laneId": "example", "laneName": "example", "since": "2026-04-15T12:00:00Z", "turn": 1, "turnEnds": "2026-04-15T12:00:00Z", "userId": "example", "windowId": "example", "windowName": "example" } ], "nobodyOnCallReason": "example", "onCall": [ { "cellId": "example", "coveredUntil": "2026-04-15T12:00:00Z", "laneId": "example", "laneName": "example", "since": "2026-04-15T12:00:00Z", "skippedForAbsence": [ { "from": "2026-04-15T12:00:00Z", "source": "example", "until": "2026-04-15T12:00:00Z", "userId": "example" } ], "turn": 1, "turnEnds": "2026-04-15T12:00:00Z", "userId": "example", "windowId": "example", "windowName": "example" } ], "rotationId": "example", "unmappedExternalDuty": { "email": "example", "name": "example", "until": "2026-04-15T12:00:00Z" }, "users": [ { "avatarUrl": "example", "displayName": "example", "email": "example", "id": "example", "isDeleted": true, "isExternal": true, "isGuest": true, "realName": "example", "teamId": "example", "timeZone": "example" } ]}Bad Request
object
Examplegenerated
{ "detail": "example", "instance": "example", "status": 1, "title": "example", "type": "example"}Unauthorized
object
Examplegenerated
{ "detail": "example", "instance": "example", "status": 1, "title": "example", "type": "example"}Forbidden
object
Examplegenerated
{ "detail": "example", "instance": "example", "status": 1, "title": "example", "type": "example"}Not Found
object
Examplegenerated
{ "detail": "example", "instance": "example", "status": 1, "title": "example", "type": "example"}Conflict
object
Examplegenerated
{ "detail": "example", "instance": "example", "status": 1, "title": "example", "type": "example"}Precondition Failed
object
Examplegenerated
{ "detail": "example", "instance": "example", "status": 1, "title": "example", "type": "example"}Precondition Required
object
Examplegenerated
{ "detail": "example", "instance": "example", "status": 1, "title": "example", "type": "example"}