Delivery and retries

How Cavuno retries failed deliveries, what endpoint statuses mean, and how to handle duplicate events.

Webhook delivery is asynchronous and at least once. An event can arrive more than once, and events can arrive out of order. Your receiver needs to cope with both.

Respond quickly

Any 2xx response counts as success. Reply as soon as you have verified the signature and stored the event, then do the real work afterwards.

Cavuno gives each attempt 10 seconds in total before treating it as a timeout. Slow processing inside the request is the most common cause of avoidable retries.

How retries work

A delivery gets up to 10 attempts in total, including the first one. The first retry follows about 30 seconds later, and the gap roughly doubles each time up to a maximum of 6 hours. Cavuno varies each gap slightly so that many endpoints failing at once do not retry in lockstep.

Retries also stop 3 days after the first attempt, whichever limit is reached first. If your receiver recovers inside that window, the event still arrives.

If you return 429 or 503 with a Retry-After header, Cavuno waits at least that long before trying again.

Which responses retry

ResponseWhat happens
2xxDelivered. No further attempts.
408, 409, 425, 429, 5xxRetried on the schedule above.
Timeout or network errorRetried on the schedule above.
Other 4xxTreated as permanent. That delivery stops immediately.
410The endpoint is disabled straight away.
3xxCounted as a failure. Redirects are never followed.

Point the endpoint at its final URL. A redirect is treated as a broken destination, not something to follow.

Endpoint status

An endpoint is in one of three states, shown in the endpoint list.

StatusWhat it means
EnabledNormal. Events are being delivered.
FailingThree live attempts in a row failed. Delivery continues and you get one alert.
DisabledTen live attempts in a row failed, or the endpoint returned 410. No new events are delivered.

A successful delivery clears the failure streak and moves a Failing endpoint back to Enabled on its own.

A Disabled endpoint never re-enables itself. Fix the receiver, then either enable it yourself or send a successful test, which also recovers it. A failed test never makes an endpoint's status worse.

Handle duplicates and out-of-order events

Two rules cover both problems.

  1. Store each id you have processed and ignore an event whose id you have already seen. Retries and replays reuse the original event ID.
  2. Keep the last revision you applied for each record. Ignore any event whose revision is lower than or equal to it. Revisions only ever increase for a given record.

Without the second rule, a retried older update can arrive after a newer one and overwrite good data with stale data.

Delivery log and replay

The Deliveries panel lists real deliveries, newest first, and you can filter by endpoint and status. Opening one shows the attempt history with the response status, latency, and a short diagnostic for each attempt. Response bodies and event payloads are never shown.

Deliveries end in one of these states.

StatusMeaning
PendingWaiting for its first attempt.
RetryingAn attempt failed and another is scheduled.
DeliveredA 2xx response was received.
FailedA permanent response ended the delivery.
ExhaustedThe attempt limit or the 3 day window ran out.

Use Replay to send a delivery again. Replay reuses the original event ID and the exact original body, so a receiver that deduplicates correctly will recognise it. Only the timestamp and signature are new.

Deliveries can be replayed for 30 days after the event. After that the stored body is removed and replay is refused. If you need data that is older than the window, read the current state of the record from the API instead.

Limits

LimitValue
Endpoints per board50
Endpoint URLHTTPS only, up to 2048 characters
Credentials in the URLNot allowed
Private, loopback, and internal addressesNot allowed
Attempt timeout10 seconds
Delivery history and replay30 days

Cavuno re-checks the destination address at delivery time, not just when you save the endpoint. A public hostname that later resolves to a private address is blocked when the attempt is made.