Skip to content

Get personal shifts

GET
/v1/users/{userId}/shifts
curl --request GET \
--url https://api.roundrobinbot.eu/v1/users/example/shifts \
--header 'Authorization: Bearer <token>'

Requires read:oncall. Returns recorded and projected shifts for a Slack user in the API key’s workspace. Request a range of at most 31 days. Workspaces with more than 1000 rotations or callers with more than 100 accessible rotations are refused. Read every page and inspect each rotation’s completion and limitation codes before concluding that no duty exists. Each rotation has its own asOfUtc. Pages are fresh reads and do not share a fixed snapshot.

userId
required
string

The Slack user identifier.

from
string format: date-time

Required inclusive range start as an RFC 3339 timestamp.

to
string format: date-time

Required exclusive range end, after from and at most 31 days later.

page
integer format: int32

Page number, starting at 1. Defaults to 1. Values beyond the last page return the last page; an empty result returns page 1.

pageSize
integer format: int32

Rows per page, from 1 to 100. Defaults to 25.

OK

Media typeapplication/json

A page of a person’s recorded and projected shifts across accessible rotations.

object
availabilityFreshness

unknown: this response does not establish the freshness of availability sources.

string
data
Array<object>

A recorded or projected duty interval for the requested person.

object
actions
One of:
null
cellId

The cell identifier, when available.

null | string
changesAtUtc

The earliest later instant at which phase changes by the clock alone: the start while upcoming, the end while running. Absent when it will not change.

null | string format: date-time
displayRowId

The Plan display-row identifier, when available.

null | string
end

The exclusive interval end. Null means no end is known.

null | string format: date-time
laneId

The lane identifier, when available.

null | string
onDutySinceIsDutyShift

Whether this interval begins at the start of the person’s turn. A turn on a window with hours is several intervals, one per opening, and only the first claims the start; the rest begin because cover opened. False at an edge created by splitting at the rotation’s asOfUtc, so a turn already part spent claims no start.

boolean
phase

upcoming, running or ended: where the interval stands against the instant the response is read, the half-open [start, end) with no end meaning it never ends.

string
rotationId

The Round Robin rotation identifier.

string
rotationName

The rotation name.

string
source

history for recorded duty or projected for projected duty.

string
start

The inclusive interval start. Clip the displayed interval to the requested range.

string format: date-time
turn

The holder’s position in the list the cell deals from. It is a position and not a counter, so a three-person weekly rotation deals turn 0 again three weeks later: group openings by cell, user and turn, and cut the group at each row where onDutySinceIsDutyShift is true.

integer format: int32
userId

The Slack user identifier of the person assigned to this interval.

string
windowId

The coverage-window identifier, when available.

null | string
nominalProvenance

unsupported: this response does not identify the nominal holder beneath a substitution.

string
page
integer format: int32
pageSize
integer format: int32
rotations

Read states for all accessible rotations examined for this request, including rotations with no matching shifts.

Array<object>

A rotation’s read state and limits on its projected shifts.

object
asOfUtc

The instant separating this rotation’s history from projected duty. Other rotations may use different instants.

string format: date-time
completion

incomplete when future external duty is requested without a successful provider read; otherwise complete. Check limitationCodes separately.

string
failureReason

projectionUnavailable when the rotation could not be projected on this page.

null | string
limitationCodes

The limitations of this read: randomFutureUnknown for unknown randomized future duty, manualFutureContingent for duty dependent on a manual change.

Array<object>

One reason a read is not exhaustive, with the availability source it concerns when it concerns one.

object
code
required

The reason, one of recurrenceExpansionIncomplete, manualAvailabilityUnavailable, googleCalendarUnavailable, proposalRecurrenceIncomplete, externalRotation, rotationDisabled, calendarFreshnessUnknown, projectionUnavailable, candidateHorizon, randomFutureUnknown or manualFutureContingent.

string
source

The availability source the reason is about, manualAvailability or googleCalendar. Absent when it is about no source.

null | string
providerReach

read, unreachable or notAsked for the external schedule provider. This is not availability-source freshness.

string
rotationId

The Round Robin rotation identifier.

string
totalItems
integer format: int64
totalPages
integer format: int32
Examplegenerated
{
"availabilityFreshness": "example",
"data": [
{
"actions": {
"canChangeAssignment": true,
"canRequestCover": true
},
"cellId": "example",
"changesAtUtc": "2026-04-15T12:00:00Z",
"displayRowId": "example",
"end": "2026-04-15T12:00:00Z",
"laneId": "example",
"onDutySinceIsDutyShift": true,
"phase": "example",
"rotationId": "example",
"rotationName": "example",
"source": "example",
"start": "2026-04-15T12:00:00Z",
"turn": 1,
"userId": "example",
"windowId": "example"
}
],
"nominalProvenance": "example",
"page": 1,
"pageSize": 1,
"rotations": [
{
"asOfUtc": "2026-04-15T12:00:00Z",
"completion": "example",
"failureReason": "example",
"limitationCodes": [
{
"code": "example",
"source": "example"
}
],
"providerReach": "example",
"rotationId": "example"
}
],
"totalItems": 1,
"totalPages": 1
}