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("{ \"operationId\": \"example\", \"recipientUserId\": \"example\", \"legs\": [ { \"key\": \"example\", \"cellId\": \"example\", \"holderUserId\": \"example\", \"from\": \"2026-04-15T12:00:00Z\", \"to\": \"2026-04-15T12:00:00Z\" } ], \"reason\": \"example\", \"acknowledgedConflictIds\": [ \"example\" ] }") { Headers = { ContentType = new MediaTypeHeaderValue("application/json-patch+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("{ \"operationId\": \"example\", \"recipientUserId\": \"example\", \"legs\": [ { \"key\": \"example\", \"cellId\": \"example\", \"holderUserId\": \"example\", \"from\": \"2026-04-15T12:00:00Z\", \"to\": \"2026-04-15T12:00:00Z\" } ], \"reason\": \"example\", \"acknowledgedConflictIds\": [ \"example\" ] }")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>") req.Header.Add("Content-Type", "application/json-patch+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-patch+json");RequestBody body = RequestBody.create(mediaType, "{ \"operationId\": \"example\", \"recipientUserId\": \"example\", \"legs\": [ { \"key\": \"example\", \"cellId\": \"example\", \"holderUserId\": \"example\", \"from\": \"2026-04-15T12:00:00Z\", \"to\": \"2026-04-15T12:00:00Z\" } ], \"reason\": \"example\", \"acknowledgedConflictIds\": [ \"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-patch+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-patch+json'}, data: '{ "operationId": "example", "recipientUserId": "example", "legs": [ { "key": "example", "cellId": "example", "holderUserId": "example", "from": "2026-04-15T12:00:00Z", "to": "2026-04-15T12:00:00Z" } ], "reason": "example", "acknowledgedConflictIds": [ "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-patch+json'}, body: '{ "operationId": "example", "recipientUserId": "example", "legs": [ { "key": "example", "cellId": "example", "holderUserId": "example", "from": "2026-04-15T12:00:00Z", "to": "2026-04-15T12:00:00Z" } ], "reason": "example", "acknowledgedConflictIds": [ "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-patch+json' \ --data '{ "operationId": "example", "recipientUserId": "example", "legs": [ { "key": "example", "cellId": "example", "holderUserId": "example", "from": "2026-04-15T12:00:00Z", "to": "2026-04-15T12:00:00Z" } ], "reason": "example", "acknowledgedConflictIds": [ "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
A caller-generated identifier of at most 128 characters. Reuse it only for an identical retry.
The other participant’s Slack user identifier. Must differ from the requester.
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
A nonempty identifier unique to this interval within the request.
The cell identifier from the rotation plan.
The Slack user identifier of the person who holds this interval.
The full shift’s inclusive start, with UTC offset zero. Must be after the current time when proposing a swap.
The full shift’s exclusive end, with UTC offset zero. Must be no more than six months after the current time.
An optional explanation of at most 2000 characters. Use an empty string to omit it.
Current conflict identifiers acknowledged for the interval this caller would receive.
Examplegenerated
{ "operationId": "example", "recipientUserId": "example", "legs": [ { "key": "example", "cellId": "example", "holderUserId": "example", "from": "2026-04-15T12:00:00Z", "to": "2026-04-15T12:00:00Z" } ], "reason": "example", "acknowledgedConflictIds": [ "example" ]}Two full future shifts to exchange with another Slack member in the same rotation.
object
A caller-generated identifier of at most 128 characters. Reuse it only for an identical retry.
The other participant’s Slack user identifier. Must differ from the requester.
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
A nonempty identifier unique to this interval within the request.
The cell identifier from the rotation plan.
The Slack user identifier of the person who holds this interval.
The full shift’s inclusive start, with UTC offset zero. Must be after the current time when proposing a swap.
The full shift’s exclusive end, with UTC offset zero. Must be no more than six months after the current time.
An optional explanation of at most 2000 characters. Use an empty string to omit it.
Current conflict identifiers acknowledged for the interval this caller would receive.
Examplegenerated
{ "operationId": "example", "recipientUserId": "example", "legs": [ { "key": "example", "cellId": "example", "holderUserId": "example", "from": "2026-04-15T12:00:00Z", "to": "2026-04-15T12:00:00Z" } ], "reason": "example", "acknowledgedConflictIds": [ "example" ]}Two full future shifts to exchange with another Slack member in the same rotation.
object
A caller-generated identifier of at most 128 characters. Reuse it only for an identical retry.
The other participant’s Slack user identifier. Must differ from the requester.
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
A nonempty identifier unique to this interval within the request.
The cell identifier from the rotation plan.
The Slack user identifier of the person who holds this interval.
The full shift’s inclusive start, with UTC offset zero. Must be after the current time when proposing a swap.
The full shift’s exclusive end, with UTC offset zero. Must be no more than six months after the current time.
An optional explanation of at most 2000 characters. Use an empty string to omit it.
Current conflict identifiers acknowledged for the interval this caller would receive.
Examplegenerated
{ "operationId": "example", "recipientUserId": "example", "legs": [ { "key": "example", "cellId": "example", "holderUserId": "example", "from": "2026-04-15T12:00:00Z", "to": "2026-04-15T12:00:00Z" } ], "reason": "example", "acknowledgedConflictIds": [ "example" ]}Two full future shifts to exchange with another Slack member in the same rotation.
object
A caller-generated identifier of at most 128 characters. Reuse it only for an identical retry.
The other participant’s Slack user identifier. Must differ from the requester.
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
A nonempty identifier unique to this interval within the request.
The cell identifier from the rotation plan.
The Slack user identifier of the person who holds this interval.
The full shift’s inclusive start, with UTC offset zero. Must be after the current time when proposing a swap.
The full shift’s exclusive end, with UTC offset zero. Must be no more than six months after the current time.
An optional explanation of at most 2000 characters. Use an empty string to omit it.
Current conflict identifiers acknowledged for the interval this caller would receive.
Examplegenerated
{ "operationId": "example", "recipientUserId": "example", "legs": [ { "key": "example", "cellId": "example", "holderUserId": "example", "from": "2026-04-15T12:00:00Z", "to": "2026-04-15T12:00:00Z" } ], "reason": "example", "acknowledgedConflictIds": [ "example" ]}Responses
Section titled “Responses”OK
The proposed assignments and whether conflict acknowledgments and remaining-time consent permit proceeding.
object
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
The acknowledgment identifier for this conflict and the previewed terms.
absence, sameCellArrangement or unknownAvailability.
The affected person’s Slack user identifier.
The inclusive UTC start of the conflict intersection with the requested interval.
The exclusive UTC end of the conflict intersection with the requested interval.
arrangement, manualAvailability, googleCalendar or slackStatus.
Whether explicit acknowledgment permits proceeding with this conflict. False means the conflict blocks the write.
Example
{ "legs": [ { "acknowledged": false, "hasStarted": false } ]}