Retries & Replay
Repull automatically retries failed webhook deliveries with exponential backoff. You can also manually replay any delivery from the last 7 days — up to 3 times per hour per delivery.
Retry Schedule
When a delivery fails, Repull retries up to 5 times on the following schedule:
| Attempt | Delay | Cumulative |
|---|---|---|
| 1st retry | 1 minute | 1 minute |
| 2nd retry | 5 minutes | 6 minutes |
| 3rd retry | 30 minutes | 36 minutes |
| 4th retry | 2 hours | ~2.5 hours |
| 5th retry | 24 hours | ~26.5 hours |
What Triggers a Retry
A delivery is considered failed and will be retried if:
- Your endpoint returns a non-2xx status code (e.g. 500, 502, 503)
- Your endpoint does not respond within 10 seconds (request timeout)
- The connection is refused or the DNS lookup fails
Return 200 quickly
200 status immediately, then handle the event in a background job. This prevents timeouts and duplicate deliveries.Auto-Disable
After 20 consecutive failed deliveries (across any events), the webhook subscription is automatically disabled. You will receive an email notification when this happens. Re-enable it from the dashboard or via the API after fixing the issue.
Viewing Failed Deliveries
List recent deliveries for a webhook subscription, including status, response code, and timestamps:
curl https://api.repull.dev/v1/webhooks/wh_abc123/deliveries?status=failed \ -H "Authorization: Bearer sk_live_YOUR_KEY"
Manual Replay
Re-deliver any webhook from the last 7 days. The replayed delivery carries the exact same payload — and the same stable eventId — as the original. The path nests the delivery under the subscription it belongs to:
curl -X POST https://api.repull.dev/v1/webhooks/wh_abc123/deliveries/del_xyz789/replay \ -H "Authorization: Bearer sk_live_YOUR_KEY"
{
"id": "del_new456",
"webhook_id": "wh_abc123",
"original_delivery_id": "del_xyz789",
"status": "success",
"response_code": 200,
"replayed_at": "2026-06-15T14:30:00Z",
"replayNumber": 1,
"replaysRemaining": 2,
"nextWindowResetAt": "2026-06-15T15:30:00Z"
}Every successful replay reports where you stand against the budget described below: replayNumber is which replay this was in the current window, replaysRemaining is how many are left in it, and nextWindowResetAt is when the window clears.
A delivery about a listing that is inactive now is not re-sent. The replay returns 403 listing_inactive with the listing in listing_ids; activate the listing, then replay again. See listing_inactive.
A replay is a new delivery, but the same event
X-Repull-Delivery-Id (the id in the response above). The logical event id is unchanged — it arrives in the X-Repull-Event-Id header. Always dedupe on eventId, never on the delivery id, or a replay will be processed twice.Replay Limit
A delivery can be replayed at most 3 times per rolling 60-minute window. The window opens on the first replay and resets once it elapses, so a delivery you have not replayed for an hour starts fresh with all 3 again.
This is not a lifetime cap. An event whose endpoint was broken last week can still be replayed today, as long as it is inside the 7-day replay window.
The budget belongs to the original delivery
A replay produces a new delivery, and that new delivery can be named in a replay call of its own. It draws on the same budget: replaying a replay counts against the original delivery's 3 per hour. Chaining replays is not a way around the limit.
A delivery that already succeeded is refused
If your endpoint returned 2xx for a delivery, replaying it would only hand you a duplicate of an event you already processed. The call is refused with 409 delivery_already_succeeded. See delivery_already_succeeded.
To send one anyway — you dropped the event on your side, say, or you are rebuilding state — pass force:
curl -X POST https://api.repull.dev/v1/webhooks/wh_abc123/deliveries/del_xyz789/replay \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "force": true }'A forced replay still counts against the 3-per-hour budget.
When you are over the limit
The 4th replay inside the window returns 409 replay_limit_reached with a Retry-After header in seconds, and the same wait expressed as an ISO-8601 timestamp in the body:
HTTP/1.1 409 Conflict
Retry-After: 2280
{
"error": {
"code": "replay_limit_reached",
"message": "Delivery del_xyz789 has been replayed 3 times in the last hour.",
"docs_url": "https://repull.dev/docs/errors/replay_limit_reached",
"replays_made": 3,
"replay_limit": 3,
"next_replay_allowed_at": "2026-06-15T15:30:00Z"
}
}Why 409 and not 429
Before You Spend a Replay
Failed deliveries are already retried automatically on the schedule above. A manual replay is for after you have changed something — if the same delivery keeps failing, replaying it again will not fix it, because the receiver is what is broken. Check, in this order:
- Your endpoint returns a 2xx within the 10-second delivery timeout. Acknowledge first, process in a background job.
- Your signature check is not rejecting valid requests. See Verify Signatures.
GET /v1/webhooks/{id}/deliveriesrecords the response body and status code your endpoint returned for each failure — usually the fastest way to see what it is actually complaining about.- Send yourself a test event with
POST /v1/webhooks/{id}/test/{event_type}to confirm the endpoint accepts events, before you spend replays on real ones.
# What did the endpoint actually say? curl "https://api.repull.dev/v1/webhooks/wh_abc123/deliveries?status=failed" \ -H "Authorization: Bearer sk_live_YOUR_KEY" # Confirm the fix with a test event — this does not touch the replay budget curl -X POST https://api.repull.dev/v1/webhooks/wh_abc123/test/reservation.created \ -H "Authorization: Bearer sk_live_YOUR_KEY" # Only then replay the real delivery curl -X POST https://api.repull.dev/v1/webhooks/wh_abc123/deliveries/del_xyz789/replay \ -H "Authorization: Bearer sk_live_YOUR_KEY"