Retries


Webhook retries are automatic re-attempts to deliver an event after a failed delivery. A robust retry strategy combines backoff timing (how long to wait between attempts), idempotent processing (so duplicates from retries are safe), and a dead-letter strategy (what happens when all retries are exhausted). Together with event replay for manual recovery and metrics for monitoring retry rates, retries are the foundation of reliable webhook delivery.

Retries can be triggered manually on any event, scheduled or automatically on failed events.

Retries

Events are limited to 50 automatic retries, but can be manually retried as many times as you like.

Manually retry events

Manually retrying events allows you to re-attempt delivery to a destination.

Manual retries are useful when troubleshooting, testing, or after resolving an issue on the destination. If a manual retry is successful, any further automatic retries on that event will be canceled – otherwise, future retries will continue as planned.

Manual retries can be triggered individually or in bulk.

Retry a single event

  1. Locate the event you wish to retry and click it to select it.
  2. In the right-hand panel that appears, click Retry.
POST
/2025-07-01/events/:id/retry
Response example
JSON
{
  "webhook_id": "web_FMKlTwAoGFRu",
  "team_id": "tm_lbhzBKgFOUnB",
  "source_id": "src_qa5626p6y5o79b",
  "destination_id": "des_TU9ioCk5EHUU",
  "event_data_id": "edt_zjQsVjdTqSMI0cNIPPXE",
  "request_id": "req_fpSzYE7G0Op42UkKvFOB",
  "cli_id": null,
  "attempts": 2,
  "status": "QUEUED",
  "id": "evt_EKbUbpGzNMIdfqnXzA",
  "last_attempt_at": "2026-01-14T13:36:31.820Z",
  "next_attempt_at": null,
  "response_status": 200,
  "error_code": null,
  "successful_at": "2026-01-14T13:36:06.675Z",
  "created_at": "2026-01-14T13:36:06.415Z",
  "updated_at": "2026-01-14T13:36:41.200Z"
}
curl -X POST "https://api.hookdeck.com/2025-07-01/events/evt_123456789/retry" \
  -H "Authorization: Bearer YOUR_API_KEY"

See the retry event API reference for more details.

Hookdeck will now attempt to deliver the event to its destination. If it succeeds, any scheduled automatic retries for that event will be canceled.

Retry many events

Bulk retrying events may impact your delivery latency, as retries are queued alongside new events.

  1. Locate a list of events you wish to retry, either by filtering your event list or opening a custom event view.
  2. Click Bulk Retry.
  3. Click Retry All.
  4. Optional: If you need to cancel a bulk retry, click Bulk Retry, click the Ongoing tab, select the retry you'd like to cancel, and click Cancel.
POST
/2025-07-01/bulk/requests/retry
Request body example
JSON
{
  "query": {
    "rejection_cause": [
      "UNSUPPORTED_HTTP_METHOD"
    ]
  }
}
Response example
JSON
{
  "code": "UNPROCESSABLE_ENTITY",
  "status": 422,
  "message": "Unprocessable Entity",
  "data": {
    "message": "The query filter for the batch operations does not include any requests. Please try a different query filter."
  }
}
curl -X POST "https://api.hookdeck.com/2025-07-01/bulk/requests/retry" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": {
      "status": "FAILED"
    }
  }'

See the bulk retry event API reference for more details.

Hookdeck will now attempt to deliver the events. For each event whose delivery succeeds, any scheduled automatic retries will be canceled.

Automatically retry events

With automatic retries, Hookdeck will continue to attempt to delivery events that have previously failed to be delivered.

Each automatic retry is counted as a new delivery attempt. Once an attempt succeeds, further automatic retries on that event are canceled.

Events are limited to 50 automatic retries, but can still be manually retried after that limit is hit.

When automatic retries occur

Automatic retries occur in the following scenarios:

  • Timeout: If a destination does not respond within 60 seconds.
  • Network error: If a destination is unreachable due to network issues.
  • HTTP status code: If a destination responds with an HTTP status code that has been configured to retry. By default, any non-2xx status code will trigger a retry, but you can configure this behavior to only retry specific status codes.

Configuring automatic retries

Configure a connection's automatic retries by setting its retry rule. There you can define the number of automatic retries Hookdeck will attempt after an event fails, the time interval between each attempt, the retry strategy and the response HTTP status codes to apply the retry rule to.

hookdeck connection upsert my-connection \
  --source-name my-source --source-type WEBHOOK \
  --destination-name my-destination --destination-type HTTP \
  --destination-url https://example.com/webhooks \
  --rules '[{"type": "retry", "strategy": "linear", "interval": 60000, "count": 5, "response_status_codes": ["500", "501", "502", "503", "504"]}]'

See the CLI Connection Commands reference for all available options.

curl -X PUT "https://api.hookdeck.com/2025-07-01/connections" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "my-connection",
    "source": {
      "name": "my-source"
    },
    "destination": {
      "name": "my-destination"
    },
    "rules": [
      {
        "type": "retry",
        "strategy": "linear",
        "interval": 60000,
        "count": 5,
        "response_status_codes": ["500-599"]
      }
    ]
  }'

The retry strategy can be either linear or exponential. With a linear strategy, retries occur at regular intervals; with an exponential strategy, each retry is delayed twice as long as the previous (1 hour, 2 hours, 4 hours, etc.).

The response status codes can be used to specify which status codes should trigger a retry. For example, if you set the retry rule to apply to status codes 500-599, Hookdeck will retry events that receive any of those status codes. The status codes supports inclusion, exclusion, ranges and greater than/less than comparisons (>=, <=, >, <).

For example, to retry all 5xx errors, you can use 500-599 or >=500 and to retry all 5xx errors except 501 you can use 500-599, !501.

In the case of a conflicting HTTP status code, Hookdeck will take the last matching statement. For example, 500, !500 will not retry 500s.

Retry strategy examples

  • Linear: If the retry rule is set to retry 3 times with a 10 minute interval, Hookdeck will retry the event at 10, 20, and 30 minutes after the initial failure.
  • Exponential: If the retry rule is set to retry 3 times with a 10 minute interval, Hookdeck will retry the event at 10, 20, and 40 minutes after the initial failure.

Example retry policies for common scenarios

Payment webhooks — Use exponential backoff with more attempts over a longer window. Payment events are high-value and must eventually be processed, but the receiving service may need time to recover:

{
  "type": "retry",
  "strategy": "exponential",
  "interval": 3600000,
  "count": 5,
  "response_status_codes": [">=500"]
}

This retries at approximately 1h, 2h, 4h, 8h, and 16h — covering ~24 hours of recovery time.

Real-time notifications — Use linear backoff with fewer, faster retries. Notification events lose value over time, so retry quickly and move on:

{
  "type": "retry",
  "strategy": "linear",
  "interval": 30000,
  "count": 3,
  "response_status_codes": [">=500"]
}

This retries at 30s, 60s, and 90s — fast enough to catch transient failures without stale delivery.

Data sync webhooks — Use exponential backoff starting with a moderate interval. Data sync events need to arrive eventually but aren't time-critical:

{
  "type": "retry",
  "strategy": "exponential",
  "interval": 300000,
  "count": 5,
  "response_status_codes": [">=500"]
}

This retries at approximately 5m, 10m, 20m, 40m, and 80m — balancing persistence with back-off.

Identifying retries

When a HTTP request is made to your destination, Hookdeck will include a x-hookdeck-will-retry-after header in the request headers. This header indicates the number of seconds that the next retry will be scheduled in once your server responds, assuming that a retry is applicable. If there's no x-hookdeck-will-retry-after then the request is the last automatic retry.

Scheduling a automatic retry

Your destination can respond with a Retry-After header to indicate how long Hookdeck should wait before retrying the event. This can be useful to implement custom retry logic or scheduling of retries based on specific errors. The Retry-After header must be an integer value representing the number of seconds to wait before retrying the request, a valid date string as per the HTTP spec or a ISO string.

Returning a value of -1 will cancel any further automatic retries.

If your destination returns a Retry-After header, the value will take precedence over any retry rule. You don't need to set a retry rule in order to use the Retry-After header.

Using the Retry-After header, a retry can be scheduled up to 7 days in the future and at most 50 times.

Excluded URLs

Some URLs managed by a 3rd party service will always return a Retry-After even for successful responses. Hookdeck will ignore the header for these URLs. List of URLs:

  • https://discord.com/api/webhooks (Discord)

Viewing the next attempt

To determine when a specific event will be retried, locate the event and note its Next Attempt At property.

Cancel scheduled retries

Canceling an automatic retry will prevent all future scheduled retries from occurring on an event.

  1. Locate the event whose automatic retries you wish to cancel.
  2. On the event, click X to cancel the retry.
curl -X PUT "https://api.hookdeck.com/2025-07-01/events/evt_123456789/mute" \
  -H "Authorization: Bearer YOUR_API_KEY"

See the mute event API reference for more details.

Best practices when handling retries

Retries are a powerful feature, but they can also lead to unexpected behavior if not handled correctly. Here are some best practices to follow when handling retries:

Make endpoints idempotent

Your webhook handlers should be designed to safely process the same event multiple times without unintended side effects. This is crucial because webhook providers often guarantee "at least once" delivery, meaning duplicates are possible. Hookdeck has the same "at least once" guarantee.

For a detailed guide on achieving idempotency, see How to Implement Webhook Idempotency.

Respond within 60 seconds

Hookdeck times out requests that take longer than 60 seconds to respond, so ensure your webhook handler's logic can complete within that timeframe. Delivery attempts that take longer than 60 will be classified as failed and will be retried according to your retry rules.

In some cases, we can extend the timeout. If you need a longer timeout, please get in touch to discuss your requirements.

Monitor and alert failed deliveries

To effectively manage webhook delivery, set up monitoring and alerts for failed deliveries. Using Issues & Notifications, you can configure alerts that trigger on either the first failed attempt (to catch problems early) or the last failed retry attempt (to identify persistent issues after all retries are exhausted). This approach helps you distinguish between temporary hiccups and systemic problems requiring immediate attention.

Use Metrics to track retry rates over time. A rising retry rate often indicates a systemic issue with your destination (slow responses, resource exhaustion, or a bug in handler code) rather than transient failures.

Common retry mistakes

Not implementing idempotent handlers

Retries mean your handler will receive the same event more than once. Without idempotent processing, retries can cause duplicate charges, duplicate notifications, or corrupted data. Always use a unique event identifier to detect and safely skip duplicate deliveries.

Setting retry intervals too aggressively

Retrying too quickly (e.g., every 5 seconds) can overwhelm a destination that's already struggling. If your destination returned a 503 because it's overloaded, hammering it with retries makes the problem worse. Use exponential backoff to give the destination time to recover.

Not monitoring retry rates

A steady stream of retries can hide systemic issues. If your retry rate is climbing but events eventually succeed, it might feel fine — until the retry queue backs up and delivery latency spikes. Monitor retry rates with Metrics and set alerts for unusual patterns.

Retrying non-retryable errors

Not all failures are worth retrying. A 400 Bad Request or 401 Unauthorized response won't succeed on retry — the request itself is invalid. Configure your retry rule to only retry server errors (>=500) unless you have a specific reason to retry client errors. See configuring automatic retries for status code filtering.

Not having a dead-letter strategy

When all retries are exhausted, what happens to the event? Without a dead-letter strategy, failed events silently disappear. Use Issues to track events that exhaust retries, alert your team, and provide a path to manual investigation and bulk retry after the root cause is fixed.

Frequently Asked Questions

What is webhook retry backoff?

Backoff is the strategy for spacing out retry attempts after a failure. Linear backoff waits the same amount of time between each retry (e.g., 1 minute, 2 minutes, 3 minutes). Exponential backoff doubles the wait time with each attempt (e.g., 1 minute, 2 minutes, 4 minutes), giving the destination more time to recover. Hookdeck supports both strategies.

How many times should I retry a failed webhook?

It depends on the event's value and time sensitivity. For critical events like payments, use 5+ retries over 24 hours. For time-sensitive notifications, 2-3 quick retries are sufficient. Hookdeck supports up to 50 automatic retries, plus unlimited manual retries.

What is the difference between retry and replay?

A retry is an automatic re-attempt triggered when a delivery fails — Hookdeck schedules it based on your retry rules. A replay (also called bulk retry or manual retry) is a deliberate re-delivery that you trigger, typically after fixing a bug or recovering from an outage. Both re-deliver the same event, but retries are automatic and replays are intentional.

What happens when all webhook retries are exhausted?

When an event exhausts all automatic retry attempts, it's marked as failed. If you've configured Issues, an issue is opened to alert your team. The event remains stored in Hookdeck and can be manually retried or bulk retried at any time after the underlying problem is resolved.

How do I prevent duplicate processing from retries?

Implement idempotent webhook handlers. Use a unique identifier from the event (such as the x-hookdeck-eventid header or a provider-specific event ID) to check whether the event has already been processed before executing your business logic. This ensures retries are safe and don't cause duplicate side effects.