Skip to content

Get a rotation's projected schedule

GET
/v1/rotations/{rotationId}/schedule
curl --request GET \
--url 'https://api.roundrobinbot.eu/v1/rotations/example/schedule?from=2026-04-15T12%3A00%3A00Z&to=2026-04-15T12%3A00%3A00Z' \
--header 'Authorization: Bearer <token>'

The shifts the rotation’s rules produce inside a window you name. from and to are both required and no more than 90 days apart. No ETag: the answer is computed forward from the rules and the clock, so no stored version stands behind it.

rotationId
required
string
from
required
string format: date-time
to
required
string format: date-time
page
integer | string format: int32
/^-?(?:0|[1-9]\d*)$/
pageSize
integer | string format: int32
/^-?(?:0|[1-9]\d*)$/
sort
string

OK

Media typeapplication/json

The envelope every /v1 collection comes back in.

object
data
Array<object>

One shift in a rotation’s projected schedule.

object
start

When the shift starts.

string format: date-time
end

When it ends, or null for a shift with no computed end (a manual rotation waiting to be advanced by hand).

null | string format: date-time
userId

The Slack user id of whoever actually holds the shift.

string
turn

Their position in the rotation’s turn order.

integer | string format: int32
/^-?(?:0|[1-9]\d*)$/
source

Either scheduled, when the rotation’s own rules produced this shift, or manual, when somebody put a person on it by hand. There is no third value.

string
skippedForAbsence

Members the plan would otherwise have named, passed over because they were absent. The userId above is who holds the shift instead.

Array<object>

A member the rotation passed over because they were away.

object
userId

The Slack user id of the member who was passed over.

string
from
null | string format: date-time
until
null | string format: date-time
source

Where the absence came from: googleCalendar or internalAvailability. Null on older records, which predate the field, so treat it as optional.

null | string
page
integer | string format: int32
/^-?(?:0|[1-9]\d*)$/
pageSize
integer | string format: int32
/^-?(?:0|[1-9]\d*)$/
totalItems
integer | string format: int64
/^-?(?:0|[1-9]\d*)$/
totalPages
integer | string format: int32
/^-?(?:0|[1-9]\d*)$/
Examplegenerated
{
"data": [
{
"start": "2026-04-15T12:00:00Z",
"end": "2026-04-15T12:00:00Z",
"userId": "example",
"turn": 1,
"source": "example",
"skippedForAbsence": [
{
"userId": "example",
"from": "2026-04-15T12:00:00Z",
"until": "2026-04-15T12:00:00Z",
"source": "example"
}
]
}
],
"page": 1,
"pageSize": 1,
"totalItems": 1,
"totalPages": 1
}

Bad Request

Media typeapplication/json
object
type
null | string
title
null | string
status
null | integer | string format: int32
/^-?(?:0|[1-9]\d*)$/
detail
null | string
instance
null | string
Examplegenerated
{
"type": "example",
"title": "example",
"status": 1,
"detail": "example",
"instance": "example"
}

Unauthorized

Media typeapplication/json
object
type
null | string
title
null | string
status
null | integer | string format: int32
/^-?(?:0|[1-9]\d*)$/
detail
null | string
instance
null | string
Examplegenerated
{
"type": "example",
"title": "example",
"status": 1,
"detail": "example",
"instance": "example"
}

Forbidden

Media typeapplication/json
object
type
null | string
title
null | string
status
null | integer | string format: int32
/^-?(?:0|[1-9]\d*)$/
detail
null | string
instance
null | string
Examplegenerated
{
"type": "example",
"title": "example",
"status": 1,
"detail": "example",
"instance": "example"
}

Not Found

Media typeapplication/json
object
type
null | string
title
null | string
status
null | integer | string format: int32
/^-?(?:0|[1-9]\d*)$/
detail
null | string
instance
null | string
Examplegenerated
{
"type": "example",
"title": "example",
"status": 1,
"detail": "example",
"instance": "example"
}