Read one delivery's attempts
using System.Net.Http.Headers;var client = new HttpClient();var request = new HttpRequestMessage{ Method = HttpMethod.Get, RequestUri = new Uri("https://api.roundrobinbot.eu/v1/webhooks/example/deliveries/example/attempts"), Headers = { { "Authorization", "Bearer <token>" }, },};using (var response = await client.SendAsync(request)){ response.EnsureSuccessStatusCode(); var body = await response.Content.ReadAsStringAsync(); Console.WriteLine(body);}package main
import ( "fmt" "net/http" "io")
func main() {
url := "https://api.roundrobinbot.eu/v1/webhooks/example/deliveries/example/attempts"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
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();
Request request = new Request.Builder() .url("https://api.roundrobinbot.eu/v1/webhooks/example/deliveries/example/attempts") .get() .addHeader("Authorization", "Bearer <token>") .build();
Response response = client.newCall(request).execute();import axios from 'axios';
const options = { method: 'GET', url: 'https://api.roundrobinbot.eu/v1/webhooks/example/deliveries/example/attempts', headers: {Authorization: 'Bearer <token>'}};
try { const { data } = await axios.request(options); console.log(data);} catch (error) { console.error(error);}const url = 'https://api.roundrobinbot.eu/v1/webhooks/example/deliveries/example/attempts';const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request GET \ --url https://api.roundrobinbot.eu/v1/webhooks/example/deliveries/example/attempts \ --header 'Authorization: Bearer <token>'The whole retry ladder of one delivery, oldest attempt first, each with the exact body and headers that attempt sent. The body is what was posted at the time, byte for byte, which is what a signature verifies over. It is not the rotation as it stands now: the payload carries state, so an event sent yesterday describes yesterday. Always one page, because a delivery has as many attempts as the ladder has rungs, so page and pageSize are not accepted here. No ETag: the rows are append-only and nothing here carries a version.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”Responses
Section titled “Responses”OK
The envelope every /v1 collection comes back in.
object
One attempt with the exact bytes we sent it with.
object
The exact bytes we POSTed.
The headers we sent, including Round-Robin-Signature and Round-Robin-Timestamp, so the HMAC over the body above can be reproduced.
One header we sent, spelled exactly as it went out.
object
A bounded snippet of what your server answered with, on an attempt that got an answer. Absent on a row where nothing was sent.
Whether your real answer was longer than the snippet above carries.
What your Retry-After header asked for, in seconds, on a 429 or 503 answer. Absent otherwise. Not necessarily what the next attempt waited: the ladder clamps this, so a receiver can ask us to wait longer than it otherwise would, never to hurry it.
The id your receiver deduplicates on. Minted once per event and identical across every attempt, so two calls carrying the same id are the same event and the second is safe to ignore.
1 for the first send, incrementing over the retry ladder.
The event type, as it appears in the payload: duty.changed and the rest.
The rotation the event happened on.
How the attempt ended.
The status code your server answered with, absent when nothing answered. That absence is the whole difference between failed and no_response.
How long the attempt took, from the request leaving to the answer or the failure that ended it. Absent when no request was made.
Why the attempt ended when no status code explains it, from a closed snake_case vocabulary: timeout, connection, secure_connection, name_resolution, redirect_not_followed, private_address and the rest. Never the receiver’s own answer, which the attempts route reports separately as a bounded response snippet.
When the attempt was made.
Which round of the retry ladder this attempt belongs to, counting from 1: the first send and its in-process retries are round 1, then each scheduled redelivery step is its own round.
How many rounds the retry ladder has today, so you never have to hard-code its shape.
When the next attempt is due, if there is one. Absent when this attempt was delivered, when nothing more will be tried, or on a row recorded before this field existed.
Examplegenerated
{ "data": [ { "requestBody": "example", "requestHeaders": [ { "name": "example", "value": "example" } ], "responseBodySnippet": "example", "responseBodyTruncated": true, "retryAfterSecondsRequested": 1, "deliveryId": "example", "attemptNumber": 1, "eventType": "example", "rotationId": "example", "outcome": "example", "statusCode": 1, "durationMs": 1, "error": "example", "at": "2026-04-15T12:00:00Z", "round": 1, "totalRounds": 1, "nextAttemptDueAt": "2026-04-15T12:00:00Z" } ], "page": 1, "pageSize": 1, "totalItems": 1, "totalPages": 1}Bad Request
object
Examplegenerated
{ "type": "example", "title": "example", "status": 1, "detail": "example", "instance": "example"}Unauthorized
object
Examplegenerated
{ "type": "example", "title": "example", "status": 1, "detail": "example", "instance": "example"}Forbidden
object
Examplegenerated
{ "type": "example", "title": "example", "status": 1, "detail": "example", "instance": "example"}Not Found
object
Examplegenerated
{ "type": "example", "title": "example", "status": 1, "detail": "example", "instance": "example"}