SettleMint
DeploymentRunbooks

Webhook deliveries failing

A webhook endpoint stops receiving events: the retry schedule, the automatic circuit breaker that pauses a failing consumer, and how deliveries recover.

A webhook endpoint is a URL you register with a DALP instance so the platform pushes a signed HTTP request to it whenever a relevant event happens, instead of your systems polling for changes. This runbook is for when a registered endpoint stops receiving those pushes, whether that is every event or only some. It covers outbound webhook delivery from the platform to your consumer; webhooks your instance receives from compliance providers are a different surface with their own management screens.

Every check reads from the endpoint's delivery history: one row per attempt, with its status, its failure reason, and the response your consumer returned. In Console, open Platform settings, then Webhooks, then the endpoint; the Deliveries tab lists every attempt, and clicking a row shows the failure class, the signed request headers, the response, and a ready-made repro command. The same history is available from the CLI as dalp get webhooks deliveries <id>, and over the webhook management endpoints.

Whatever the cause, the history shows one of three shapes: attempts that keep failing, attempts that have stopped entirely, or attempts that succeeded while your consumer disagrees. Each shape has its own check below.

Symptoms

  • A registered webhook endpoint stops receiving events it previously received.
  • Deliveries to one endpoint fail while other endpoints on the same instance keep receiving events normally.
  • The endpoint's status in Console changed to Disabled without anyone disabling it.
  • Your consumer reports missing events for a time window, then receiving them all at once, or not at all.

Checks

The checks form a short decision tree. Read the delivery history first; its shape tells you which branch you are on.

The delivery history's shape picks the check to run.Start with the Deliveries screen, which lists one row per attempt with its failure reason and the consumer's response. Three shapes follow. Failing rows that keep appearing split on the failure reason: a retryable class such as DNS, TLS, a timeout, or a 5xx keeps retrying for three days, so fix reachability under check 3. A terminal 4xx is permanent for that one event, handled under check 4. No new rows at all means the circuit breaker is open: go to check 2. Rows that show delivered while your consumer disagrees point at receipt deadlines and duplicate handling under check 5.The delivery history's shape picks the check to run.The same decision tree as the desktop variant, drawn portrait, with the same three top-level shapes. Failing rows that keep appearing split further on the failure reason: a retryable class such as DNS, TLS, a timeout, or a 5xx keeps retrying for three days, so fix reachability under check 3. A terminal 4xx is permanent for that event, handled under check 4. No new rows at all means the breaker is open, go to check 2. Delivered rows the consumer disputes point at receipt deadlines or duplicates, go to check 5.

Read the delivery history before anything else. Rows that keep failing split on their failure reason: retryable classes keep retrying for three days, a terminal 4xx is permanent for that one event. No new rows calls for a breaker, subscription, runner, and event-production check, and delivered rows the consumer disputes point at receipt deadlines or duplicates.

  1. Confirm whether the endpoint's failures are transient or sustained. The signal is the Deliveries tab: a healthy endpoint shows mostly delivered rows, with occasional failed attempts followed by a delivered one for the same event. A single failed attempt retries automatically on an exponential schedule that starts near 30 seconds and roughly doubles after each attempt, with random jitter so many endpoints failing at once do not retry in lockstep. Retrying continues until 3 days after the platform recorded the event, not 3 days after the first attempt. The next attempt after expiry records abandonment. An open breaker prevents attempts, so that log can appear after the event has already aged out (check 2). A handful of retries in the history is normal operation, not an incident. Not every failure retries, though. A delivery your consumer rejects with an ordinary 4xx response, other than a request timeout or a rate-limit signal, is permanent for that event; a fix made afterward recovers future events but never that one. Each attempt itself times out after 20 seconds if the consumer never responds.

  2. Check whether the platform has stopped attempting deliveries entirely, not just failing them. The signal is the Circuit breaker card on the endpoint's Overview tab: Healthy means deliveries flow, Disabled means the breaker tripped and the platform is skipping deliveries to this endpoint rather than attempting them.

    • Tripping. An endpoint trips the breaker after 30 consecutive failed deliveries; missed receipt deadlines count toward that streak, manually sent test events never do.
    • Recovery. Recovery is automatic: the platform probes an open endpoint by re-sending its most recent live event, each probe at least a minute apart with 10 seconds to answer. A failed probe resets the success count, so a consumer that flaps between working and failing stays paused until it answers twice in a row. Two consecutive probe successes move the endpoint to Recovering, and live deliveries resume immediately; the next delivered event returns it to Healthy.
    • The Recovering trap. Entering Recovering does not reset the failure streak that tripped the breaker in the first place. One failed live delivery there reopens the breaker immediately, before a second probe or a delivered event ever gets the chance. A consumer that is only half fixed can loop through probe, Recovering, and Disabled without a single live delivery landing.
  3. Verify the consumer's endpoint is reachable and answering correctly. The signal is the Failure reason on each row.

    • Reading the taxonomy. It separates the ways a request can die: the name never resolved, the TLS handshake failed, the connection never opened, the response never finished, or the consumer answered with an error status. The sixth value, an unparseable response, also includes the two policy rejections described below. Check the policy reason before assuming the consumer returned an invalid response; the request might not have reached it. The healthy value is a delivered row, which the platform records only for a 2xx response; accepting the connection is not enough.
    • Network failures. All of them retry on the normal schedule, so fixing the consumer is enough and no platform-side change is needed.
    • Platform policy. The platform checks endpoint address and HTTPS policy at registration and before each dispatch. A URL that fails those checks cannot be registered. Operator-configured exceptions are described below. The endpoint URL must resolve to a publicly routable address; a receiver on private address space fails that check until the operator adds its range to webhooks.allowedTargetCidrs in the deployment's Helm values, or the equivalent DALP_WEBHOOKS_ALLOWED_TARGET_CIDRS environment variable. The URL must also use https. Both rules share one exception: an origin the operator lists in DALP_WEBHOOKS_TRUSTED_DESTINATIONS, for a private-network install, is exempt from the https requirement and the public-address check alike, so an endpoint on that list can legitimately use http:// or a private address. Tenant-facing APIs cannot add an origin to that list; only an operator changing the deployment's configuration can.
  4. If the integration verifies signed payloads, confirm the consumer holds the current signing secret. The signal is a run of terminal 4xx rows that started when a secret changed on either side. A consumer that rejects a signature usually does so with an ordinary 4xx, which the platform treats as permanent for that event. Fixing the secret recovers deliveries from that point forward but does not resurrect the events rejected while it was wrong; those need a replay, described in the next section. Two behaviors keep rotation itself from causing this. After a rotation the previous secret stays valid for 24 hours, and the platform signs with both secrets during the overlap. An event that waited in retry backoff is re-signed with a fresh timestamp before the next attempt, inside the Standard Webhooks tolerance window. A long network delay or clock mismatch can still exceed the receiver's timestamp tolerance. Check receiver time and the verified delivery headers.

  5. If the endpoint requires counter-signed receipts, confirm the consumer responds inside its receipt window. That window is 30 seconds in every configuration reachable from Console, the CLI, or the API; nothing tenant-facing changes it. The signal is rows that reached the consumer but still count as failures because the receipt never arrived in time. A late receipt is treated like any other failed delivery and retried on the normal schedule. A receipt that fails its signature or hash check is different: that is permanent for the event, on the same footing as a terminal 4xx, because re-sending cannot make a forged or mismatched receipt valid.

The circuit breaker recovers automatically, and can reopen just as fast.A healthy endpoint delivers normally while individual failures retry on the backoff curve. Thirty consecutive failed deliveries trip the breaker; test events never count. While the breaker is open the platform skips deliveries to the endpoint rather than attempting them, and Console shows the endpoint as Disabled; test events still deliver and change nothing. The platform probes the open endpoint automatically by re-sending its most recent live event, each probe at least a minute apart with ten seconds to answer, and a failed probe resets the success count. Two consecutive probe successes move the endpoint to Recovering, where live deliveries resume immediately, and from there two things can happen. The failure count that tripped the breaker carries over unchanged: one failed live delivery while Recovering reopens the breaker at once, looping back to Open before a second probe or a delivered event ever gets the chance. Only if a live delivery succeeds first does the endpoint return to Healthy, with the failure streak reset to zero. A manual shortcut exists: Reactivate manually on the endpoint's Overview tab re-enables the endpoint and closes the breaker at once.The circuit breaker recovers automatically, and can reopen just as fast.The same lifecycle as the desktop variant, drawn portrait. Thirty consecutive failed deliveries trip the breaker, with test events never counting. While open, deliveries are skipped and Console shows Disabled, though test events still deliver. Automatic probes re-send the latest live event at least a minute apart; a failed probe resets the count. Two consecutive successes move the endpoint to Recovering, where live deliveries resume, and from there two things can happen. The failure count that tripped the breaker carries over: one failed live delivery there reopens the breaker at once, looping back to Open. Only a live delivery that succeeds first closes the breaker fully. Reactivate manually on the Overview tab closes it at once.

The breaker trips on 30 consecutive failed deliveries and skips further attempts rather than failing them. Automatic probes re-send the endpoint's latest live event at least a minute apart; two consecutive successes resume live deliveries. The failure count that tripped the breaker carries over, though, so one failed live delivery while Recovering reopens it at once; only a delivery that succeeds closes the breaker fully. Test events never count in either direction, and Reactivate manually on the Overview tab closes it immediately.

Actions

  • If the breaker tripped, fix the underlying reachability or response problem first. The platform resumes on its own once its probes confirm recovery: two consecutive successes, each at least a minute apart, so recovery typically takes close to two minutes after your fix, rarely less. When that wait matters, recover immediately instead: on the endpoint's Overview tab, the Circuit breaker card offers Reactivate manually after you type the endpoint's name, which re-enables the endpoint and closes the breaker at once. Use Send test event to confirm your fix either way; a test event delivers even while the breaker is open and never counts toward tripping or clearing it, so testing is free but does not by itself reopen anything.
  • If the endpoint was down long enough that events aged past the 3-day retry window, or lost events to terminal failures, replay them. The webhook replay call re-queues either one event by its id or every matching event in a block range. Each replayed delivery is flagged as a replay in its envelope, so your consumer can tell it from a first delivery. Replay is refused while the endpoint is disabled or the breaker is open, so recover the endpoint first, then replay. No log entry marks an event abandoned while the breaker stays open and no attempt runs against it; that entry appears only once the next attempt evaluates the event, typically after recovery. Check the delivery history directly for events approaching the 3-day window rather than waiting for an alert.
  • If signature verification was the failure, correct the consumer's secret, then replay. A rejected signature is permanent per event, so the events that failed while the secret was wrong stay failed. The same replay and retry calls cover both a window of them and a single delivery you want to re-queue on its own. Deliveries themselves are otherwise working, so no platform-side change is needed.
  • If your consumer sees a duplicate event, treat it as normal at-least-once delivery rather than a defect. The platform journals delivery attempts, and a retry reuses the same event id as its original delivery throughout. Deduplicate retries on the webhook-id header, which carries that id on every attempt. A replay is different: it mints a fresh event id for each event it re-queues, so the webhook-id header on a replayed delivery will not match the original and deduplicating on it does not work. Use is_replay to recognize the replay, then use stable domain identifiers from the event payload to avoid applying the same outcome twice.
  • Escalate with the endpoint id, the failure window, whether the breaker had tripped, and the failure reason shown in the delivery history. That last field distinguishes a consumer-side outage from a platform delivery defect faster than any retry count. A name that never resolved points at DNS or egress, a terminal 4xx points at the consumer's validation, and a run of timeouts points at the consumer's capacity.

Frequently asked questions

Does the 3-day retry window keep counting while the breaker is open?

Yes. The window is measured from when the platform recorded the event, and it does not pause while the breaker skips deliveries. A consumer that stays broken for days can therefore age events out without a single further attempt appearing in the history. That is why the right response to a long outage is a replay, not a wait: recovery reopens deliveries for new events, but the aged-out ones return only if you re-queue them.

Does rotating the signing secret break deliveries already in flight?

No, provided the consumer finishes its switch inside the 24-hour overlap described in check 4. After the overlap ends, the old secret stops signing, and a consumer still pinned to it starts rejecting deliveries as terminal 4xx failures, the same signature scenario check 4 covers.

On this page