List a webhook endpoint's deliveries
#!/usr/bin/env bashset -euo pipefailAPI=https://api.speccapture.comAUTH="Authorization: Bearer $SPECCAPTURE_API_KEY"
WEBHOOK_ID=0f8fad5b-d9cb-469f-a165-70867728950e # the webhookId from adding the endpoint
log=$(curl -sS --fail-with-body "$API/v1/webhooks/$WEBHOOK_ID/deliveries?limit=20" \ -H "$AUTH") || { echo "$log" >&2; exit 1; }
jq -r '.data[] as $delivery | ("\($delivery.createdAt) \($delivery.eventType) \($delivery.status) after \($delivery.attempts) attempts", if $delivery.lastError != null then " \($delivery.lastError)" else empty end)' <<<"$log"using System.Text.Json;
using HttpClient http = new() { BaseAddress = new Uri("https://api.speccapture.com") };http.DefaultRequestHeaders.Authorization = new("Bearer", Environment.GetEnvironmentVariable("SPECCAPTURE_API_KEY"));
string webhookId = args[0]; // the webhookId from adding the endpoint
JsonElement log = await Json(await Call(HttpMethod.Get, $"/v1/webhooks/{webhookId}/deliveries?limit=20"));
foreach (JsonElement delivery in log.GetProperty("data").EnumerateArray()) { Console.WriteLine($"{delivery.GetProperty("createdAt")} {delivery.GetProperty("eventType")} {delivery.GetProperty("status")} after {delivery.GetProperty("attempts")} attempts"); if (delivery.GetProperty("lastError").ValueKind != JsonValueKind.Null) { Console.WriteLine($" {delivery.GetProperty("lastError")}"); }}
// Sends a request; stops with the problem's code and detail if the API refuses it.async Task<HttpResponseMessage> Call(HttpMethod method, string path, HttpContent? body = null, string? idempotencyKey = null) { using HttpRequestMessage request = new(method, path) { Content = body }; if (idempotencyKey is not null) request.Headers.Add("Idempotency-Key", idempotencyKey); HttpResponseMessage response = await http.SendAsync(request); if (!response.IsSuccessStatusCode) { JsonElement problem = await Json(response); string? detail = (problem.TryGetProperty("detail", out JsonElement text) ? text : problem.GetProperty("title")).GetString(); Console.Error.WriteLine($"{(int)response.StatusCode} {problem.GetProperty("code")}: {detail}"); Environment.Exit(1); } return response;}
// Reads an answer as JSON.static async Task<JsonElement> Json(HttpResponseMessage response) => JsonDocument.Parse(await response.Content.ReadAsStringAsync()).RootElement;import osimport sys
import requests
API = "https://api.speccapture.com"session = requests.Session()session.headers["Authorization"] = f"Bearer {os.environ['SPECCAPTURE_API_KEY']}"
def call(method, path, **kwargs): """Send a request; stop with the problem's code and detail if the API refuses it.""" response = session.request(method, API + path, **kwargs) if not response.ok: problem = response.json() sys.exit(f"{response.status_code} {problem['code']}: {problem.get('detail', problem['title'])}") return response
webhook_id = sys.argv[1] # the webhookId from adding the endpoint
log = call("GET", f"/v1/webhooks/{webhook_id}/deliveries?limit=20").json()
for delivery in log["data"]: print(f"{delivery['createdAt']} {delivery['eventType']} {delivery['status']} after {delivery['attempts']} attempts") if delivery["lastError"] is not None: print(f" {delivery['lastError']}")const API = "https://api.speccapture.com";const headers = { Authorization: `Bearer ${process.env.SPECCAPTURE_API_KEY}` };
const [webhookId] = process.argv.slice(2); // the webhookId from adding the endpoint
const log = await call("GET", `/v1/webhooks/${webhookId}/deliveries?limit=20`).then((response) => response.json());
for (const delivery of log.data) { console.log(`${delivery.createdAt} ${delivery.eventType} ${delivery.status} after ${delivery.attempts} attempts`); if (delivery.lastError !== null) { console.log(` ${delivery.lastError}`); }}
// Sends a request; stops with the problem's code and detail if the API refuses it.async function call(method, path, init = {}) { const response = await fetch(API + path, { ...init, method, headers: { ...headers, ...init.headers } }); if (!response.ok) { const problem = await response.json(); console.error(`${response.status} ${problem.code}: ${problem.detail ?? problem.title}`); process.exit(1); } return response;}Each event sent to the endpoint, newest first: its event id (the webhook-id header), type, job, the url it went to, status (pending, delivered or dead), attempts, what the endpoint last answered and when, when the next attempt is due, the last error in words, and when it was queued and delivered. Never a body or a signature. Page with limit and cursor (the previous page’s nextCursor), narrow with createdAfter and createdBefore (when an event was queued) and status. Another workspace’s endpoint, or a deleted one, is 404 not_found.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”Query Parameters
Section titled “Query Parameters”How many items the page holds: 1 to 200, 50 when left out.
The previous page’s nextCursor, exactly as it came: the list continues just after that page’s last item, so items made or removed meanwhile never shift a page. Leave it out for the first page.
Only items queued strictly after this date and time (ISO 8601, such as 2026-10-14T09:30:00Z; without an offset it is UTC).
Only items queued strictly before this date and time (ISO 8601, such as 2026-10-14T09:30:00Z; without an offset it is UTC).
Only items with this status.
Responses
Section titled “Responses”OK
object
object
Bad Request: a problem with a stable code. See Errors for every code and what to do about it.
Every error: a problem with a stable code. https://speccapture.com/docs/api/errors lists every code.
object
A link to the code’s entry in the docs.
What went wrong, as a stable code to branch on: a published code never changes meaning.
This request’s trace: quote it when asking for help.
Not Found: a problem with a stable code. See Errors for every code and what to do about it.
Every error: a problem with a stable code. https://speccapture.com/docs/api/errors lists every code.
object
A link to the code’s entry in the docs.
What went wrong, as a stable code to branch on: a published code never changes meaning.
This request’s trace: quote it when asking for help.