Skip to content

Testing and troubleshooting webhooks

  1. Register the endpoint and store the signing secret (Setting up webhooks).
  2. Implement signature verification (Payloads and signatures).
  3. POST /v1/webhooks/{id}/test — returns 202 with { "event_id": "kmevt_…" } and queues a test.ping delivery.
  4. Confirm your endpoint returned 2xx and that GET /v1/webhooks/{id}/deliveries shows succeeded.
Try it in the console

A paused endpoint (is_active: false, including after an auto-disable) returns 409 webhook_endpoint_inactive on test. Re-enable it with PATCH { "is_active": true } first.

POST /v1/webhooks/{id}/deliveries/{delivery_id}/replay creates a new delivery linked via replay_of_delivery_id. Use this after fixing your endpoint or after an auto-disable incident. Re-enable a paused endpoint before replaying — a replay to a paused endpoint goes dead.

If you never receive run.failed / run.recovered: confirm the endpoint is_active, that enabled_events includes those types (or is empty), and that a real healthy↔failing transition occurred for a workspace×capability. Use GET /v1/events to see whether events were emitted without a successful delivery — an event with delivered: false means there is no successful delivery yet (still retrying, dead, or no endpoint subscribed); no event at all means no transition occurred.

403 webhooks_not_enabled — webhooks are not enabled on your workspace (admin toggle). While the gate is off, pending deliveries stop and go dead with last_error: webhooks_not_enabled. 403 webhook_scope_required — the API token lacks the webhooks scope; create one with Can manage webhooks checked. 403 webhook_owner_required — mutations need the workspace owner.

  • Verify against the raw body bytes.
  • Confirm you stored the latest secret after create or rotate.
  • Reject only after a constant-time compare; check clock skew against t= (for example a 5-minute window).

KingMinos accepts HTTPS only and rejects private, loopback, and link-local targets (including DNS that resolves to private space). Use a publicly reachable HTTPS endpoint.

Twenty consecutive dead deliveries disable the endpoint. Fix the handler, then PATCH { "is_active": true }, and optionally replay recent dead deliveries.