Skip to content

Create a duty arrangement

POST
/v1/rotations/{rotationId}/duty-arrangements
curl --request POST \
--url https://api.roundrobinbot.eu/v1/rotations/example/duty-arrangements \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json-patch+json' \
--header 'If-Match: example' \
--data '{ "operationId": "example", "cellId": "example", "userId": "example", "from": "2026-04-15T12:00:00Z", "to": "2026-04-15T12:00:00Z", "expectedRevision": 1, "turnSelection": { "kind": "example", "from": "2026-04-15T12:00:00Z", "to": "2026-04-15T12:00:00Z" }, "acknowledgedConflictIds": [ "example" ] }'

Requires write:duty, rotation edit authority and If-Match. Use the ETag from a rotation or arrangement read. If-Match: * accepts the current rotation version without checking a previously read version. Missing If-Match returns 428. A stale version returns 412: read current state, review the terms and retry with its ETag. A start in the past is moved to the actual transition time; an entirely elapsed interval is refused. A 409 with arrangementConflicts includes current conflicts. Preview again and acknowledge only conflicts that permit it. Use one operation ID per write. A retry by the same actor with the same terms returns the committed result; changed terms or reuse for another rotation returns 409 with operationIdConflict. Success returns 200 and an ETag. Change-event publication status does not confirm Slack delivery.

rotationId
required
string

The rotation identifier.

If-Match
required
string

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 cancellation.

Terms for a direct assignment or its preview.

object
operationId

A nonempty operation identifier of at most 128 characters, required for writes. Reuse it only to retry the same write.

string
cellId

The rotation cell receiving the assignment.

string
userId

The Slack user identifier of a person in the cell’s lane.

string
from

The requested inclusive UTC start. A current assignment begins at the actual transition time.

string format: date-time
to

The exclusive UTC end, later than both the start and the write’s transition time.

string format: date-time
expectedRevision

The current arrangement revision when changing an existing assignment or previewing that change.

null | integer | string format: int64
/^-?(?:0|[1-9]\d*)$/
turnSelection
One of:
null
acknowledgedConflictIds

Conflict identifiers explicitly acknowledged by the rotation editor.

Array<string>
Examplegenerated
{
"operationId": "example",
"cellId": "example",
"userId": "example",
"from": "2026-04-15T12:00:00Z",
"to": "2026-04-15T12:00:00Z",
"expectedRevision": 1,
"turnSelection": {
"kind": "example",
"from": "2026-04-15T12:00:00Z",
"to": "2026-04-15T12:00:00Z"
},
"acknowledgedConflictIds": [
"example"
]
}

OK

Media typeapplication/json

The committed assignment result for an operation.

object
operationId
required

The submitted operation identifier.

string
rotationVersion
required

The committed rotation version, also returned as an ETag.

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

The actual prospective transition start.

string format: date-time
arrangements
required

The arrangements changed by the operation, including cancelled records and any replacement.

Array<object>

An interval assignment. Its recorded terms remain distinct from actual served history.

object
id
required

The arrangement identifier.

string
rotationId
required

The rotation identifier.

string
cellId
required

The rotation cell identifier.

string
userId
required

The assigned person’s Slack user identifier.

string
from
required

The inclusive UTC start.

string format: date-time
to
required

The exclusive UTC end.

string format: date-time
revision
required

The arrangement revision used when changing or ending it.

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

active or cancelled. An active record can describe an interval that has already ended.

string
kind
required

directAssignment, acceptedCover or swapLeg. Direct-assignment writes change or end only directAssignment.

string
origin
One of:
null
originalSnapshot
One of:
null
turnSelection
One of:
null
deliveryState
required

pending or published for change-event publication. Neither value confirms that a Slack message has arrived.

string
Examplegenerated
{
"operationId": "example",
"rotationVersion": 1,
"effectiveFrom": "2026-04-15T12:00:00Z",
"arrangements": [
{
"id": "example",
"rotationId": "example",
"cellId": "example",
"userId": "example",
"from": "2026-04-15T12:00:00Z",
"to": "2026-04-15T12:00:00Z",
"revision": 1,
"state": "example",
"kind": "example",
"origin": {
"userIds": [
"example"
],
"complete": true
},
"originalSnapshot": {
"asOfUtc": "2026-04-15T12:00:00Z",
"from": "2026-04-15T12:00:00Z",
"to": "2026-04-15T12:00:00Z",
"complete": true,
"segments": [
{
"from": "2026-04-15T12:00:00Z",
"to": "2026-04-15T12:00:00Z",
"userIds": [
"example"
],
"resolved": true
}
]
},
"turnSelection": {
"kind": "example",
"from": "2026-04-15T12:00:00Z",
"to": "2026-04-15T12:00:00Z"
}
}
],
"deliveryState": "example"
}