Create a swap request
using System.Net.Http.Headers;var client = new HttpClient();var request = new HttpRequestMessage{ Method = HttpMethod.Post, RequestUri = new Uri("https://api.roundrobinbot.eu/v1/rotations/example/swap-requests"), Headers = { { "If-Match", "example" }, { "Authorization", "Bearer <token>" }, }, Content = new StringContent("{ \"acknowledgedConflictIds\": [ \"example\" ], \"legs\": [ { \"cellId\": \"example\", \"from\": \"2026-04-15T12:00:00Z\", \"holderUserId\": \"example\", \"key\": \"example\", \"to\": \"2026-04-15T12:00:00Z\" } ], \"operationId\": \"example\", \"reason\": \"example\", \"recipientUserId\": \"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/swap-requests"
payload := strings.NewReader("{ \"acknowledgedConflictIds\": [ \"example\" ], \"legs\": [ { \"cellId\": \"example\", \"from\": \"2026-04-15T12:00:00Z\", \"holderUserId\": \"example\", \"key\": \"example\", \"to\": \"2026-04-15T12:00:00Z\" } ], \"operationId\": \"example\", \"reason\": \"example\", \"recipientUserId\": \"example\" }")
req, _ := http.NewRequest("POST", 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, "{ \"acknowledgedConflictIds\": [ \"example\" ], \"legs\": [ { \"cellId\": \"example\", \"from\": \"2026-04-15T12:00:00Z\", \"holderUserId\": \"example\", \"key\": \"example\", \"to\": \"2026-04-15T12:00:00Z\" } ], \"operationId\": \"example\", \"reason\": \"example\", \"recipientUserId\": \"example\" }");Request request = new Request.Builder() .url("https://api.roundrobinbot.eu/v1/rotations/example/swap-requests") .post(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: 'POST', url: 'https://api.roundrobinbot.eu/v1/rotations/example/swap-requests', headers: { 'If-Match': 'example', Authorization: 'Bearer <token>', 'Content-Type': 'application/*+json' }, data: '{ "acknowledgedConflictIds": [ "example" ], "legs": [ { "cellId": "example", "from": "2026-04-15T12:00:00Z", "holderUserId": "example", "key": "example", "to": "2026-04-15T12:00:00Z" } ], "operationId": "example", "reason": "example", "recipientUserId": "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/swap-requests';const options = { method: 'POST', headers: { 'If-Match': 'example', Authorization: 'Bearer <token>', 'Content-Type': 'application/*+json' }, body: '{ "acknowledgedConflictIds": [ "example" ], "legs": [ { "cellId": "example", "from": "2026-04-15T12:00:00Z", "holderUserId": "example", "key": "example", "to": "2026-04-15T12:00:00Z" } ], "operationId": "example", "reason": "example", "recipientUserId": "example" }'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://api.roundrobinbot.eu/v1/rotations/example/swap-requests \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/*+json' \ --header 'If-Match: example' \ --data '{ "acknowledgedConflictIds": [ "example" ], "legs": [ { "cellId": "example", "from": "2026-04-15T12:00:00Z", "holderUserId": "example", "key": "example", "to": "2026-04-15T12:00:00Z" } ], "operationId": "example", "reason": "example", "recipientUserId": "example" }'Requires a Slack member access token and If-Match from the latest preview. Creates a pending request. Duty remains unchanged until acceptance. Reuse operationId and the same body when retrying an uncertain result. A missing If-Match returns 428. On 412, refresh the preview before retrying.
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”Two full future shifts to exchange with another Slack member in the same rotation.
object
Current conflict identifiers acknowledged for the interval this caller would receive.
Exactly two full shifts: one held by the requester and one held by the recipient. Both must start after the current time.
One duty interval offered by a swap participant.
object
The cell identifier from the rotation plan.
The full shift’s inclusive start, with UTC offset zero. Must be after the current time when proposing a swap.
The Slack user identifier of the person who holds this interval.
A nonempty identifier unique to this interval within the request.
The full shift’s exclusive end, with UTC offset zero. Must be no more than six months after the current time.
A caller-generated identifier of at most 128 characters. Reuse it only for an identical retry.
An optional explanation of at most 2000 characters. Use an empty string to omit it.
The other participant’s Slack user identifier. Must differ from the requester.
Examplegenerated
{ "acknowledgedConflictIds": [ "example" ], "legs": [ { "cellId": "example", "from": "2026-04-15T12:00:00Z", "holderUserId": "example", "key": "example", "to": "2026-04-15T12:00:00Z" } ], "operationId": "example", "reason": "example", "recipientUserId": "example"}Two full future shifts to exchange with another Slack member in the same rotation.
object
Current conflict identifiers acknowledged for the interval this caller would receive.
Exactly two full shifts: one held by the requester and one held by the recipient. Both must start after the current time.
One duty interval offered by a swap participant.
object
The cell identifier from the rotation plan.
The full shift’s inclusive start, with UTC offset zero. Must be after the current time when proposing a swap.
The Slack user identifier of the person who holds this interval.
A nonempty identifier unique to this interval within the request.
The full shift’s exclusive end, with UTC offset zero. Must be no more than six months after the current time.
A caller-generated identifier of at most 128 characters. Reuse it only for an identical retry.
An optional explanation of at most 2000 characters. Use an empty string to omit it.
The other participant’s Slack user identifier. Must differ from the requester.
Examplegenerated
{ "acknowledgedConflictIds": [ "example" ], "legs": [ { "cellId": "example", "from": "2026-04-15T12:00:00Z", "holderUserId": "example", "key": "example", "to": "2026-04-15T12:00:00Z" } ], "operationId": "example", "reason": "example", "recipientUserId": "example"}Two full future shifts to exchange with another Slack member in the same rotation.
object
Current conflict identifiers acknowledged for the interval this caller would receive.
Exactly two full shifts: one held by the requester and one held by the recipient. Both must start after the current time.
One duty interval offered by a swap participant.
object
The cell identifier from the rotation plan.
The full shift’s inclusive start, with UTC offset zero. Must be after the current time when proposing a swap.
The Slack user identifier of the person who holds this interval.
A nonempty identifier unique to this interval within the request.
The full shift’s exclusive end, with UTC offset zero. Must be no more than six months after the current time.
A caller-generated identifier of at most 128 characters. Reuse it only for an identical retry.
An optional explanation of at most 2000 characters. Use an empty string to omit it.
The other participant’s Slack user identifier. Must differ from the requester.
Examplegenerated
{ "acknowledgedConflictIds": [ "example" ], "legs": [ { "cellId": "example", "from": "2026-04-15T12:00:00Z", "holderUserId": "example", "key": "example", "to": "2026-04-15T12:00:00Z" } ], "operationId": "example", "reason": "example", "recipientUserId": "example"}Two full future shifts to exchange with another Slack member in the same rotation.
object
Current conflict identifiers acknowledged for the interval this caller would receive.
Exactly two full shifts: one held by the requester and one held by the recipient. Both must start after the current time.
One duty interval offered by a swap participant.
object
The cell identifier from the rotation plan.
The full shift’s inclusive start, with UTC offset zero. Must be after the current time when proposing a swap.
The Slack user identifier of the person who holds this interval.
A nonempty identifier unique to this interval within the request.
The full shift’s exclusive end, with UTC offset zero. Must be no more than six months after the current time.
A caller-generated identifier of at most 128 characters. Reuse it only for an identical retry.
An optional explanation of at most 2000 characters. Use an empty string to omit it.
The other participant’s Slack user identifier. Must differ from the requester.
Examplegenerated
{ "acknowledgedConflictIds": [ "example" ], "legs": [ { "cellId": "example", "from": "2026-04-15T12:00:00Z", "holderUserId": "example", "key": "example", "to": "2026-04-15T12:00:00Z" } ], "operationId": "example", "reason": "example", "recipientUserId": "example"}Responses
Section titled “Responses”OK
The saved result. deliveryState reports publication progress, not confirmed Slack receipt.
object
An interval assignment. Its recorded terms remain distinct from actual served history.
object
The rotation cell identifier.
The next instant at which phase changes, or null once it has ended.
The inclusive UTC start.
The arrangement identifier.
directAssignment, acceptedCover or swapLeg. Direct-assignment writes change or end only directAssignment.
Original duty holders recorded before the first assignment, with completeness for this interval. Later edits retain that original record.
object
Whether original duty is known throughout the interval. False includes assignments without an original record.
Distinct Slack user identifiers in the recorded portion of the arrangement interval.
Original duty segments on detail reads. Null on list reads or when no original record is available.
object
The UTC time when the original duty was evaluated.
Whether every returned segment is resolved. An extension beyond the original recorded interval is unresolved.
The inclusive UTC start of the returned interval.
Original holders by interval, including periods with no assignee and unresolved periods.
Effective duty during part of an assignment interval.
object
The inclusive UTC start.
Whether the holders or absence of duty are known for this interval.
The exclusive UTC end.
Slack user identifiers of the effective holders. An empty list means no assignee only when resolved is true.
The exclusive UTC end of the returned interval.
upcoming, running or ended, from from and to at the time the response is built.
The arrangement revision used when changing or ending it.
The rotation identifier.
active or cancelled. An active record can describe an interval that has already ended.
The exclusive UTC end.
The recorded full or remaining turn, or null when no verified selection was saved. Use the arrangement’s From and To for the affected interval.
object
The inclusive UTC start of the original turn, including any part already served.
fullTurn or remainingTurn.
The exclusive UTC end of the original turn.
The assigned person’s Slack user identifier.
A swap request, its rotation name and the actions available to this caller.
object
True when the caller may accept, decline or cancel the request.
True while the request is pending or accepted.
The instant the state, phase and capabilities were evaluated.
The actions available to the caller.
object
Whether the caller may accept the request.
Whether the caller may cancel the request.
Whether the caller may decline the request.
The reason the actions are unavailable. Absent when they are available.
The same word as reason, or null when the actions are available.
The earliest later instant at which the state, a phase, active or actionable changes by the clock alone. Null when none will.
The request.
object
The request identifier.
The offered intervals.
An offered duty interval and its accepted assignment identifier, when present. phase is upcoming, running or ended for this leg at the time the response is built.
object
The accepted assignment identifier. Absent until the request is accepted.
The cell identifier.
The inclusive interval start.
The user who holds the interval.
The key of this leg within the request.
upcoming, running or ended for this leg at the instant the response is built.
The rotation identifier.
The exclusive interval end.
upcoming before the earliest leg starts, ended once the latest leg has ended, running between, at the instant the response is built.
The reason given with the request.
The user asked to swap.
The user who made the request.
The revision of the request.
The rotation identifier.
The lifecycle state of the request.
The name of the rotation.
Examplegenerated
{ "arrangements": [ { "cellId": "example", "changesAtUtc": "2026-04-15T12:00:00Z", "from": "2026-04-15T12:00:00Z", "id": "example", "kind": "example", "origin": { "complete": true, "userIds": [ "example" ] }, "originalSnapshot": { "asOfUtc": "2026-04-15T12:00:00Z", "complete": true, "from": "2026-04-15T12:00:00Z", "segments": [ { "from": "2026-04-15T12:00:00Z", "resolved": true, "to": "2026-04-15T12:00:00Z", "userIds": [ "example" ] } ], "to": "2026-04-15T12:00:00Z" }, "phase": "example", "revision": 1, "rotationId": "example", "state": "example", "to": "2026-04-15T12:00:00Z", "turnSelection": { "from": "2026-04-15T12:00:00Z", "kind": "example", "to": "2026-04-15T12:00:00Z" }, "userId": "example" } ], "deliveryState": "example", "effectiveFrom": "2026-04-15T12:00:00Z", "operationId": "example", "request": { "actionable": true, "active": true, "asOfUtc": "2026-04-15T12:00:00Z", "capability": { "canAccept": true, "canCancel": true, "canDecline": true, "reason": "example", "reasonCode": "example" }, "changesAtUtc": "2026-04-15T12:00:00Z", "request": { "id": "example", "legs": [ { "arrangementId": "example", "cellId": "example", "from": "2026-04-15T12:00:00Z", "holderUserId": "example", "key": "example", "phase": "example", "rotationId": "example", "to": "2026-04-15T12:00:00Z" } ], "phase": "example", "reason": "example", "recipientUserId": "example", "requesterUserId": "example", "revision": 1, "rotationId": "example", "state": "example" }, "rotationName": "example" }, "rotationVersion": 1}