Retries and replay
Concrete retry schedule, status-code semantics, dead-letter behavior, and how to manually redeliver after a fix.
What BlendFi does when your endpoint isn't reachable, what your endpoint can return to control the retry behavior, and how to recover deliveries that failed.
The retry schedule
Linear, ~30 seconds between attempts. Not exponential.
| Attempt | Fires at (cumulative) |
|---|---|
| 1 | t = 0 |
| 2 | ~30 s |
| 3 | ~60 s |
| 4 | ~90 s |
| 5 | ~120 s |
| (DLQ) | ~150 s |
Per-attempt HTTP timeout: 5 seconds. Beyond that the attempt is treated as a network failure and counts as a retry.
After 5 attempts the delivery message moves to a dead-letter queue inside BlendFi. The corresponding org_webhook_deliveries row stays in dispatched status, operational quirk in v1; partner-visible via GET /v1/webhook_deliveries/{id}.
The endpoint stays active
Even after a delivery exhausts retries, the endpoint itself is not auto-disabled. It continues receiving new events. Disabling an endpoint is a partner-driven action: PATCH /v1/webhook_endpoints/{id} with status: "disabled", or permanent removal via DELETE.
What your response controls
How BlendFi treats each HTTP status your endpoint returns:
| Your response | BlendFi treats it as | Notes |
|---|---|---|
2xx (200, 201, 204, …) | Success | Delivery acked. No more retries. |
5xx (500, 502, 503, …) | Retry | Transient infra failure on your end. |
408 Request Timeout | Retry | Slow processing; BlendFi will try again. |
409 Conflict | Retry | Race in your handler. |
425 Too Early | Retry | Specific HTTP status meant for "I'm not ready yet." |
429 Too Many Requests | Retry | Even if you're rate-limited yourself. |
Other 4xx (400, 401, 403, 404, 410, …) | Terminal failure | Delivery marked failed. No auto-disable. |
3xx (any redirect) | Terminal failure | BlendFi does not follow redirects. Code http_redirect_blocked. |
| Network / TCP / TLS / DNS error | Retry | Counts as a normal retry. |
The most common mistake: returning non-2xx for a duplicate. BlendFi will keep retrying. Always 2xx for duplicates (use X-Blendfi-Event-Id to dedup); only fail for genuine processing errors.
Replay window (server-side)
Independent of the retry schedule. Every signed delivery carries a X-Blendfi-Timestamp; BlendFi treats deliveries with a timestamp older than 300 seconds at the moment of receipt as replay attempts and rejects them. This is enforced in your verifier (see Signature verification), BlendFi doesn't replay old payloads, but a leaked-signature attacker might try.
Practical implication: if your endpoint is down for over 5 minutes and BlendFi's last retry exhausts, the original delivery is gone from the live signing window. You can still recover by manually redelivering the event (which mints a fresh timestamp + signature), see below.
Manual redelivery
When a delivery exhausted retries (or you just want to re-process for any reason), redeliver:
curl -X POST $BLENDFI_BASE/v1/webhook_deliveries/del_01J.../redeliver \
-H "Authorization: Bearer $BLENDFI_KEY" \
-H "Idempotency-Key: $(uuidgen)"This creates a new delivery row pointing at the original event. Fresh timestamp, fresh signature, fresh retry budget. The original event ID stays the same, your dedup key still works, so a successful redelivery should be a no-op replay on your side.
The deliveries dashboard:
curl $BLENDFI_BASE/v1/webhook_endpoints/we_01J.../deliveries \
-H "Authorization: Bearer $BLENDFI_KEY"Shows every recent delivery's status, succeeded, failed, dispatched, with the last error message. Useful when a partner asks "did BlendFi try to reach us at this time?"
Recovery runbook (downtime → re-process)
What to do after a multi-hour outage on your endpoint:
- Confirm the endpoint is back. Curl your
/blendfi-webhooksURL with a synthetic payload + valid signature, verify your code path is healthy. - List failed deliveries.
GET /v1/webhook_endpoints/{id}/deliveries?status=failed, the time range filter is your friend. - Reconcile against your local state. For each failed delivery, decide whether you actually missed the event or whether other paths (polling, manual UI) caught it.
- Redeliver the ones you missed.
POST /v1/webhook_deliveries/{id}/redeliverper delivery. Idempotency-Key per call. - Watch the deliveries dashboard. Confirm each redelivery succeeds.
For very large windows (thousands of missed deliveries), reconcile via GET /v1/conversions and GET /v1/users first, your local state plus a fetch of the canonical state often resolves faster than per-event redelivery.
Read next
- Signature verification, the verifier code path
- Endpoint management, pause an endpoint cleanly during planned downtime
- Errors catalog,
webhook_delivery_not_found,invalid_webhook_delivery_state
