Delivery and retries

How delivery attempts are made, when they are retried, how backoff is calculated, and what your handler must guarantee.

Core Updated 8 October 2026

These pages describe ShellOrbit as it runs today. Breaking changes to the HTTP API are announced before they ship, and existing request and response shapes stay supported.

How is a delivery attempted?

After receipt, the event is queued. A worker takes it, POSTs the stored body and headers to your destination, and records the outcome: status code, response time, and a response body excerpt. Anything in the 2xx range counts as delivered. Everything else is a failure.

Which failures are retried?

  • A non 2xx status code.
  • A connection failure, DNS failure, or TLS failure.
  • A timeout. The default request timeout is 15 seconds.

A 410 response is treated as permanent and is not retried, because the destination is telling you the resource is gone.

What does the backoff look like?

The default policy is 5 attempts over roughly 15 minutes:

Delivery and retries: Attempt, Delay before it runs
AttemptDelay before it runs
1Immediate
28 seconds
332 seconds
42 minutes
512 minutes

On Starter and above you can change attempt count and the backoff curve per endpoint. A common production setting is 8 attempts tapering over 6 hours, which survives a long deploy without hammering a destination that is already struggling.

The ceiling is 50 attempts with a maximum gap of 24 hours between them, which is a retry window of over a month. A destination that goes down on a Friday evening is still being retried well after anyone has got back to it.

What if a destination stays down?

After ten consecutive events have failed every attempt, ShellOrbit stops trying for a while rather than continuing to run a full retry schedule against a destination that is plainly not there. New events are held, not dropped, and are attempted again after ten minutes.

The first success clears it immediately, so a destination that comes back is served straight away rather than waiting out a cooldown it no longer deserves. You will have heard about the problem before this happens: the failure alert fires at five consecutive failures by default, and the circuit opens at ten.

Delays carry jitter, so a burst of events that fail together does not retry in lockstep.

What happens after the last attempt?

The event moves to the dead letter queue. It stays inspectable and replayable for the rest of your retention window, and it counts as failed in alerts and in the event log. Nothing is discarded. See replay.

Is delivery ordered?

No. Events are delivered as workers pick them up, and a retried event lands after events that succeeded on their first attempt. If order matters to your handler, order by a field in the payload rather than by arrival.

Is delivery exactly once?

No. Delivery is at least once. A destination that returns 200 after your side already committed, but where the response is lost in transit, is indistinguishable from a failure, so the event is retried. Use the event id as an idempotency key.

How fast is the first attempt?

A healthy first attempt normally leaves within a second of receipt. Queue depth during a spike can add to that. The status page shows how each component is answering, checked every fifteen minutes.

What headers does my destination receive?

The provider’s original headers, plus ShellOrbit headers describing the delivery:

text
ShellOrbit-Event-Id: evt_9c41f0
ShellOrbit-Endpoint-Id: ep_7f3a91
ShellOrbit-Attempt: 3
ShellOrbit-Received-At: 2026-09-03T12:04:01.412Z
ShellOrbit-Signature: t=1788445441,v1=5f2b...

The signature header is described in signature verification.