Preview 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/preview"), Headers = { { "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/preview"
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("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/preview") .post(body) .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/preview', headers: {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/preview';const options = { method: 'POST', headers: {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/preview \ --header 'Authorization: Bearer <token>' \ --header '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" }'Requires a Slack member access token. API keys are refused. Returns the proposed intervals and rotation ETag without changing duty or creating a request.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”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 proposed assignments and whether conflict acknowledgments and remaining-time consent permit proceeding.
object
Whether conflict acknowledgments and remaining-time consent permit proceeding.
The proposed assignments.
One proposed assignment and its conflicts. canAcknowledge identifies conflicts this caller may acknowledge. When hasStarted is true, from and to describe the remaining time; accepting requires its key in acknowledgedStartedLegKeys.
object
A conflict or an uncertainty affecting the proposed assignment.
object
Whether explicit acknowledgment permits proceeding with this conflict. False means the conflict blocks the write.
The inclusive UTC start of the conflict intersection with the requested interval.
The acknowledgment identifier for this conflict and the previewed terms.
arrangement, manualAvailability, googleCalendar or slackStatus.
The exclusive UTC end of the conflict intersection with the requested interval.
absence, sameCellArrangement or unknownAvailability.
The affected person’s Slack user identifier.
Set on an acceptance preview and null on a proposal preview.
Example
{ "legs": [ { "acknowledged": false, "hasStarted": false } ]}