Retry Policy
XRNotify guarantees at-least-once delivery. If your endpoint does not return a 2xx status within 10 seconds, the delivery is retried automatically on an exponential backoff schedule.
Overview
Every event detected on the XRPL is delivered to your webhook endpoint at least once. In practice, the vast majority of deliveries succeed on the first attempt. The retry mechanism exists to handle transient failures — network blips, brief endpoint unavailability, or accidental non-2xx responses.
Because retries are a normal part of the delivery guarantee, your webhook handler must be idempotent. Use the X-XRNotify-Delivery-Id header or the deterministic event_id field to detect and safely skip duplicate deliveries.
Retry schedule
| Attempt | Delay after previous | Cumulative elapsed | Notes |
|---|---|---|---|
| 1 | Immediate | 0s | Initial delivery |
| 2 | 1 minute | ~1m | First retry |
| 3 | 5 minutes | ~6m | |
| 4 | 30 minutes | ~36m | |
| 5 | 2 hours | ~2.6h | |
| 6 | 6 hours | ~8.6h | |
| 7 | 12 hours | ~20.6h | |
| 8 | 24 hours | ~44.6h | Final attempt |
After 8 failed attempts, the delivery moves to dead status. No further automatic retries occur. You can still trigger a manual retry at any time.
What counts as a failure
A delivery attempt is marked as failed if any of the following occur:
- ✕HTTP status 3xx, 4xx, or 5xx returned by your endpoint
- ✕No response received within 10 seconds (connection timeout)
- ✕SSL/TLS handshake failure or expired certificate
- ✕DNS resolution failure for your endpoint's hostname
- ✕Connection refused (e.g., server is down or port not open)
A delivery is considered successful if:
Jitter
Each retry delay has ±10% random jitter applied. This prevents a thundering herd scenario where many deliveries that failed simultaneously all retry at exactly the same time, which could overwhelm your endpoint.
# Backoff formula with jitter: delay(attempt) = base_delay[attempt] × (1 + random(-0.1, 0.1)) # Example — attempt 3 base delay = 5 minutes: # Actual delay will be between 4m30s and 5m30s
Auto-disable behavior
Each webhook tracks a consecutive_failures counter. This counter increments each time a delivery reaches the final failed state (after all 8 attempts), and resets to zero on any successful delivery.
If consecutive_failures reaches 100, XRNotify automatically sets the webhook status to disabled and sends an email notification to your account's registered email address.
Re-enable a disabled webhook via the dashboard or the API:
curl -X PATCH https://api.xrnotify.io/v1/webhooks/wh_abc123 \
-H "X-XRNotify-Key: xrn_live_xxx" \
-H "Content-Type: application/json" \
-d '{ "status": "active" }'Delivery status values
| Status | Description |
|---|---|
pending | Queued for initial delivery or awaiting a scheduled retry. |
delivering | Currently being sent to your endpoint. |
succeeded | Your endpoint returned a 2xx status within the timeout. |
failed | All retry attempts have been exhausted. Manual action required. |
dead | Alias for failed — delivery will not be retried automatically. |
Manual retry
Even after a delivery reaches failed status, you can trigger an immediate re-attempt:
curl -X POST https://api.xrnotify.io/v1/deliveries/dlv_abc123/retry \ -H "X-XRNotify-Key: xrn_live_xxx"
The response includes the delivery object with the updated status, response_code, and last_error fields after the attempt completes.
Bulk recovery with Replay
For large-scale recovery — such as when your endpoint was down for several hours and hundreds of deliveries failed — use the Replay API to re-deliver all events matching a time window in one request, rather than retrying them individually.
curl -X POST https://api.xrnotify.io/v1/replay \
-H "X-XRNotify-Key: xrn_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"webhook_id": "wh_abc123",
"filters": {
"since": "2024-01-15T00:00:00Z",
"until": "2024-01-15T12:00:00Z"
}
}'The Replay API re-delivers events as new deliveries with fresh X-XRNotify-Delivery-Id values. Because the event_id in the body is deterministic and unchanged, you can use it as a stable idempotency key. See the Replay API reference for the full filter options.
X-XRNotify-Delivery-Id header or the event_id body field to detect and safely skip duplicate processing.