In April, Sanity made a small change to its webhook infrastructure that caught my attention. Sanity is a Norwegian content platform used by companies around the world to power websites, apps and other digital products.

Failed webhook deliveries returning 429 or 5xx had previously been retried with exponential backoff over 30 minutes. Sanity changed this to two retries, 30 seconds apart, to avoid deliveries piling up behind a receiver that wasn't working.

My first reaction was: what happens to the next event? If nothing has changed at the receiver, why should event number two have a better chance than event number one?

I reached out to Simen Svale Skogsrud, CTO and co-founder at Sanity, about it. He was kind enough to send a thoughtful reply, and he made a very good point about what webhooks should actually be responsible for.

The core of his argument was this: a webhook should not quietly turn into a hidden queue.

Sanity already does quite a lot around delivery. Their webhooks use at-least-once delivery and include an idempotency key for deduplication. They also provide attempts and message logs where customers can inspect deliveries and queued messages.

But that is different from giving the receiver full control of a durable backlog.

If Sanity keeps retrying failed deliveries for hours or days, it is effectively maintaining that backlog on behalf of the customer. The webhook contract itself doesn't give the receiver a way to manage and drain it, even if Sanity builds useful tooling around the delivery.

Seen that way, a conservative retry window makes sense. Sanity is setting a boundary around what its webhook service is responsible for rather than gradually turning it into a workflow engine.

For workloads that actually need durable synchronization, Simen's view is that the durability should live somewhere else. He mentioned tools such as Inngest and Temporal.

Sanity itself is heading further in that direction as well. Their newly announced Durable Functions are designed for long-running processes where state survives failures, individual steps can be retried, and a workflow can pick up where it left off.

Webhooks are useful for delivery, but they are a poor abstraction for a durable workflow or a queue that somebody needs to operate over time. The alternative to a short retry window isn't necessarily a longer retry window. It is often a different abstraction entirely.

This separation between a simple handoff and the durable work behind it is also close to how we think about Queuey.

We are not trying to make webhook providers retry forever. The application hands over an event, Queuey takes durable custody of it, and delivery can continue without the application having to carry the backlog itself.

Simen also described Queuey, while making it clear that he hasn't tried it (yet, editor's note), as something close to making a queue look like a webhook.

I think that is actually a pretty good description.

So for me, the more interesting question is not whether the correct retry window is one minute or thirty minutes, but where you want durability to live when one of the systems isn't available.

The interface can stay simple. The durability behind it doesn't have to be.

References