Retryx Docs

Delivery, retries & replay

At-least-once, with identifiers to de-duplicate

An event accepted by Retryx is delivered to each destination at least once. Network failures and timeouts can cause a request to be repeated even when your server already processed it, so make your handler idempotent. Every request carries stable identifiers:

HeaderMeaning
Retryx-Event-IdStable id of the accepted event. Identical across retries and replays.
Retryx-Delivery-IdId of this delivery (one per destination per attempt chain). A replay creates a new one.
Idempotency-KeyEqual to Retryx-Delivery-Id and stable across every retry of the delivery. Use it to de-duplicate.
Retryx-AttemptAttempt number, starting at 1.
Retryx-TimestampUnix seconds when this attempt was signed.
Retryx-Signaturet=<unix>,v1=<hmac-sha256 hex>[,v1=…]. See “Verify signatures”.

Your own original request headers (for example X-GitHub-Event) and any custom headers configured on the endpoint or destination are forwarded too. Retryx-reserved headers cannot be overridden.

What counts as success

Any 2xx response within the destination timeout (1–30 s, default 10 s). Everything else — non-2xx status, connection errors, timeouts — is a failed attempt and is retried.

Retry schedule

Retries use exponential backoff with jitter: the delay before retry n is 30 s × 2n−1, randomised to 50–100 % of that value and capped at 6 hours, for up to 8 attempts by default. Endpoints and destinations can set their own attempt count, initial delay or an explicit schedule. A Retry-After header on 429 / 503 responses is honoured (up to one hour).

These stop immediately and go to the dead-letter queue without retrying: 410 Gone, a destination URL that violates the outbound-security policy, a payload removed by retention, or a transform error.

Dead letters, failover and health

When retries are exhausted the delivery is dead-lettered and stays visible with every attempt. If the destination has a failover destination configured, the event is automatically routed there. Destination health (healthy / degraded / down) is tracked and you are notified when a destination goes down, recovers, or keeps failing.

Pause, rate limits and concurrency

Pausing a destination keeps accepting and queueing events without sending anything; resume and the backlog is delivered. Per-destination concurrency and requests-per-second limits protect fragile servers and never consume a retry attempt.

Replay

Replays re-send events after you fix a problem. History is immutable: a replay creates a replay operation and new deliveries linked to the originals; earlier deliveries and attempts are never changed. Replay one delivery, a selection, all failed events in a time range, or schedule it for later. A replayed delivery has the same Retryx-Event-Id but a new Retryx-Delivery-Id / Idempotency-Key. Every replay is recorded in the audit log with who started it and why.

Ordering

Events are delivered concurrently and retried independently, so ordering is not guaranteed. Use your event’s own timestamps or sequence numbers when order matters.

Outbound security

  • Destinations must be HTTPS and cannot point at private, loopback, link-local, carrier-grade NAT, multicast or cloud-metadata addresses (including IPv6 and IPv4-mapped forms).
  • The URL is validated when you save it and again before every delivery. DNS is resolved once and the connection is made to that validated address, which defeats DNS-rebinding.
  • Redirects are not followed by default. If you enable them, every hop is re-validated (max 3).
  • Response bodies are captured up to a size cap for debugging; they are shown in the dashboard and removed by the retention policy.
The source IP of deliveries is not fixed. Authenticate requests with the signature, not with IP allow-lists.