Docs menu

Retries and failures

A delivery counts as received only when your endpoint answers 2xx in time. Everything else is retried on a fixed schedule — except 410 Gone.

What your answer means

Your endpoint answersOfficeHero does
2xx within 15 secondsMarks the delivery delivered. The response body is ignored.
429 Too Many RequestsWaits for your Retry-After (at most one hour; 60 seconds if absent) and tries again without using up an attempt.
410 GoneStops: the delivery ends failed (error_class: gone) and is not retried. Three 410s within 24 hours disable the endpoint.
Any other 4xx or 5xx, a 3xx redirect, a timeout or a connection errorThe delivery stays pending and is retried on the schedule below. Redirects are never followed.

Timeouts

Your endpoint has 10 seconds to accept the connection and 15 seconds in total to answer. Acknowledge first and process afterwards — put the event on a queue and return 204.

Retry schedule

A delivery is tried up to 8 times. After a failed attempt it stays pending and the next attempt waits, with ±20 % jitter:

After attempt1234567
Next attempt in1 min5 min15 min1 h3 h6 h12 h

If the 8th attempt fails the delivery is marked dead. You can send it again any time with replay. Each attempt carries OH-Event-Attempt (1, 2, …) and is signed when it is sent, with a fresh t, so a retry passes the 300-second timestamp check.

Deliveries that are not retried

A delivery can also end failed without your endpoint being called when its attempt comes up:

error_classWhy
endpoint_disabledThe endpoint was paused, deleted or disabled. Pausing does not hold queued deliveries.
ssrf_rejectedThe endpoint’s host now resolves to a private or reserved address.
api_key_inactive, api_key_scope_insufficientThe API key that owns the endpoint was revoked, expired, or no longer has the event’s scope.
pii_capability_blockedThe event carries personal data and the endpoint is no longer enabled for it.

Fix the cause, then replay what you missed.

Automatic disabling

An endpoint is switched to disabled — and the company’s admins notified — when:

  • 50 attempts in a row have failed (auto_consecutive_failures). Every failed attempt counts, not every failed delivery: one event retried 8 times adds 8. A 2xx resets the count;
  • it has answered 410 Gone 3 times within 24 hours (auto_410_repeat);
  • every delivery created for it in the last 7 days has ended failed or dead (auto_7_day_all_dead). On a quiet endpoint this can be a single dead delivery, if it was the only one that week.

disabled_reason says which. Fix the receiver, then POST /v1/webhook_endpoints/{id}/resume (which takes a place in the endpoint quota again), and replay what you missed.

Duplicates and ordering

  • Deliveries can arrive more than once — after a timeout on your side, a replay, or a retry that raced your slow 2xx. Deduplicate on the envelope id (also sent as OH-Event-Id and Idempotency-Key).
  • Order is not guaranteed. A retried delivery can arrive after a later event. Use occurred_at and the resource’s updated_at, or fetch the current state from the API by id.

Watching deliveries

GET /v1/webhook_endpoints/{id}/deliveries lists deliveries newest first with their status, the attempt count, the status your endpoint answered, how long it took and the error class (http_5xx, http_4xx, redirect_blocked, timeout, connect_failed, tls, dns, transport, rate_limited, gone, and the ones in the table above).