Skip to content

Webhook delivery and retries

KingMinos delivers each event at least once. Expect duplicates and out-of-order arrivals: dedupe on event id (kmevt_…) and order by created when sequence matters.

  • Timeout: each attempt waits up to 10 seconds.
  • Retries: one initial attempt plus 7 retries. The first retry waits at least 1 minute plus 0–300 seconds of per-delivery jitter; later retries wait at least 2, 4, 8, 16, 30, and 60 minutes. These are minimums: retries are picked up by a sweep that runs every 2 minutes, so each can land up to about 2 minutes later, and the roughly two-hour total is a floor.
  • Success: any 2xx response.
  • Redirects are not followed. A 3xx counts as a failed attempt and retries like any other non-2xx; register the final URL.
  • Terminal (no retry): HTTP 404 and 413 mark the delivery dead immediately.
  • Other failures retry until exhausted, then status dead.
  • last_error on a delivery is a short code: http_<status>, timeout, transport_error, dns_nxdomain, or webhook_secret_unavailable for a failed attempt; endpoint_inactive, webhooks_not_enabled, or blocked_endpoint_host:<reason> when the delivery went dead without being sent.

If webhooks are turned off for the workspace, pending deliveries to its endpoints stop and go dead (webhooks_not_enabled).

After 20 consecutive terminally failed (dead) deliveries, KingMinos auto-disables the webhook. A successful delivery resets the counter. Re-enable with PATCH /v1/webhooks/{id} and { "is_active": true }, then replay recent dead deliveries. Re-enable first: a replay to a paused endpoint goes dead.

GET /v1/events is the reconciliation log. Events remain queryable even if no webhook was active when they were emitted. Use it to recover anything missed while an endpoint was down, then replay specific deliveries.

Query Use
?type=run.failed Incident history per capability
?delivered=false No successful delivery yet (still retrying, dead, or no endpoint subscribed)
?delivered=true At least one successful delivery
?limit=&cursor= Keyset pagination from next_cursor. next_cursor is returned only when a full page (limit rows) came back; its absence means the last page.