Deliveries and retries
Response classification
Seção intitulada “Response classification”Webhook delivery is retry-capable best-effort. Capture, fan-out, lifecycle, or eligibility decisions can prevent an HTTP attempt, so use API reconciliation as the source of truth. The response and retry rules below apply after an eligible request reaches HTTP transport.
célula.in applies the following rules after starting a request:
| Result | Classification | What happens |
|---|---|---|
HTTP 200–299 |
Success | Delivery becomes delivered. Verification also requires the correct challenge. |
HTTP 408, 429, or 500–599 |
Retryable failure | Another attempt is scheduled while attempts and delivery lifetime remain. |
| Other HTTP statuses, including redirects | Permanent failure | Delivery becomes failed-permanent immediately. |
| Network, DNS, TLS, or 10-second wall timeout | Retryable failure | Another attempt is normally scheduled. |
| Response headers over 16 KiB or body over 4 KiB | Permanent failure | Delivery becomes failed-permanent. |
Return a small 2xx response as soon as you have safely accepted the event. Process long-running work asynchronously. célula.in does not follow redirects.
For 408, 429, and 5xx responses, Retry-After is honored when it contains either non-negative decimal seconds or an HTTP date. The requested delay is capped at 24 hours.
Automatic retry schedule
Seção intitulada “Automatic retry schedule”Production and manual-redelivery deliveries have up to eight consumer attempts:
| Attempt | Approximate time |
|---|---|
| 1 | Immediately |
| 2 | 1 minute after attempt 1 |
| 3 | 5 minutes after attempt 2 |
| 4 | 30 minutes after attempt 3 |
| 5 | 2 hours after attempt 4 |
| 6 | 6 hours after attempt 5 |
| 7 | 12 hours after attempt 6 |
| 8 | 24 hours after attempt 7 |
Scheduled delays have up to ±10% jitter unless a valid Retry-After value is used. A delivery becomes exhausted when no attempt remains or the next attempt would exceed its lifetime.
Verification uses at most three attempts—immediately, after about 1 minute, and after about 5 additional minutes—and expires after 15 minutes. Test deliveries use one attempt and also expire after 15 minutes.
Internal system failures use a separate recovery lane and do not consume the eight consumer attempts.
Delivery states
Seção intitulada “Delivery states”| State | Meaning |
|---|---|
pending |
Ready for its first attempt. |
processing |
Claimed by a delivery worker. |
retry-scheduled |
Waiting for the next consumer attempt. |
blocked-system |
Waiting for recovery from an internal failure; consumer attempt budget was not consumed. |
delivered |
Destination returned a successful response. |
failed-permanent |
A non-retryable failure occurred. |
exhausted |
Retry budget or delivery lifetime ended. |
suppressed |
Endpoint lifecycle, subscription, destination, or security state prevented delivery. |
expired |
Delivery lifetime ended before completion. |
Suppression reasons can include pending-verification, manual-pause, health-pause, security-policy, subscription-removed, destination-version-mismatch, url-changed, and deleted.
Endpoint health
Seção intitulada “Endpoint health”Only production attempts affect endpoint health. A success resets the consecutive-failure count. An active endpoint reports:
healthywith no consecutive failure;degradedafter one or more consecutive failures;failingafter at least five consecutive failures.
An endpoint can be automatically paused with pause-reason: health after a failure streak has reached at least five attempts and remained unresolved for seven days. Pending work is suppressed when that pause occurs. A full administrator can resume a health-paused endpoint after fixing the receiver; resuming resets its failure streak but does not restore suppressed events.
Inspect event history
Seção intitulada “Inspect event history”An event and all related delivery and attempt history expire 30 days after the original event was captured. The window is anchored to that original event, not to the creation time of each delivery.
GET /v1/webhook-events?filter[event-type]=person.updated&filter[from]=2026-08-01T00:00:00.000Z&filter[to]=2026-08-31T23:59:59.999Z&page[number]=1&page[size]=25 HTTP/1.1Host: api.celula.inAuthorization: Bearer YOUR_ACCESS_TOKENAccept: application/vnd.api+jsonGET /v1/webhook-events returns event metadata without the full snapshot. GET /v1/webhook-events/:id adds snapshot, truncation, and merge data when applicable.
Supported event filters are event-type, from, and to; dates apply to occurred-at.
Inspect delivery history
Seção intitulada “Inspect delivery history”GET /v1/webhook-deliveries?filter[endpoint]=ENDPOINT_ID&filter[status]=exhausted&page[number]=1&page[size]=25 HTTP/1.1Host: api.celula.inAuthorization: Bearer YOUR_ACCESS_TOKENAccept: application/vnd.api+jsonSupported filters are:
endpoint: webhook endpoint ID;event-type: one supported event type;status: one delivery state;fromandto: ISO 8601 bounds applied to the delivery’screated-atvalue.
Both event and delivery lists default to 25 records per page and allow at most 100. Their response metadata has page, size, and total.
GET /v1/webhook-deliveries/:id includes up to 100 most recent attempt summaries:
{ "data": { "type": "webhook-deliveries", "id": "66b000000000000000000001", "attributes": { "kind": "production", "event-type": "person.updated", "status": "retry-scheduled", "attempt-count": 2, "next-attempt-at": "2026-08-16T15:36:00.000Z", "attempts": [ { "id": "66c000000000000000000002", "state": "completed", "outcome": "retryable-failure", "attempt-number": 2, "http-status": 503, "duration-ms": 142, "started-at": "2026-08-16T15:06:00.000Z", "finished-at": "2026-08-16T15:06:00.142Z", "error-code": "http-503" } ] }, "relationships": { "endpoint": { "data": { "type": "webhook-endpoints", "id": "ENDPOINT_ID" } }, "event": { "data": { "type": "webhook-events", "id": "66a000000000000000000001" } }, "origin-delivery": { "data": null } } }}History can disappear before its normal retention deadline when required by account deletion, person deletion, or anonymization. In those cases, a previously visible event or delivery can return 404 Not Found.
Manually redeliver a failed event
Seção intitulada “Manually redeliver a failed event”Manual redelivery is available only when the original production delivery is exhausted, failed-permanent, or suppressed, the event is still retained, and the current endpoint is active, verified, and still subscribed to that event type.
curl --request POST 'https://api.celula.in/v1/webhook-redeliveries' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \ --header 'Content-Type: application/vnd.api+json' \ --header 'Idempotency-Key: redeliver-66b000000000000000000001' \ --data '{ "data": { "type": "webhook-redeliveries", "relationships": { "delivery": { "data": { "type": "webhook-deliveries", "id": "66b000000000000000000001" } } }, "attributes": {} } }'The API returns 202 Accepted with the new delivery. It uses the retained event snapshot and event ID, but the endpoint’s current verified URL and current signing secrets. The new delivery has its own X-Celulain-Delivery-Id, links to the original through origin-delivery, and receives the normal eight-attempt budget.
A manual redelivery inherits the original event’s expiration; it does not receive a new 30-day lifetime. When requested late in the event’s retention window, it may have only hours left for its attempts and history, even though the normal attempt budget contains eight attempts.
Exact replays using the same idempotency key return the same manual-delivery record for 24 hours. Reusing a key for a different original delivery returns 409 Conflict.
