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:

AttemptDelayCumulative
1st retry1 minute1 minute
2nd retry5 minutes6 minutes
3rd retry30 minutes36 minutes
4th retry2 hours~2.5 hours
5th retry24 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

Process webhook events asynchronously. Return a 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

Each replay is sent as a brand-new attempt: it gets a fresh 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

The conflict is with the state of that one delivery, not with the pace of your requests. Your key is not throttled: other endpoints keep working, and replays of other deliveries go through normally. Do not route this into the same backoff path as rate_limited.

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}/deliveries records 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"
AI