Delivery lifecycle
Every webhook subscription progresses through a small state machine, and every delivery attempt is logged and queryable. This page covers the states, the retry policy, and how to diagnose failures.
Subscription states
A subscription's current state is on the status field of the WebhookSubscription object.
validating
Newly-created subscriptions start here. Cirrus sends a developer.webhook.test event and waits for a 2xx response. On success, the subscription transitions to active. On repeated failure within 24 hours, it transitions to disabled.
active
Events matching the subscription's event list are delivered as they occur. This is the normal operating state.
disabled
No events are being delivered. Two ways to reach disabled:
- Explicit — the subscription was deleted via
DELETE /api/v1alpha1/webhook-subscriptions/{id}. Deleted subscriptions are soft-deleted; their delivery history remains queryable but no new events are sent. - Chronic failure — the endpoint failed delivery for 72 consecutive hours (see Chronic failure handling below).
There is no PATCH to re-enable a chronically-failed subscription. Delete it and create a new one — you'll get a fresh signing secret and start in validating again.
Retry policy
Cirrus considers a delivery successful if your endpoint returns a 2xx status within 30 seconds. Anything else — non-2xx, timeout, connection error, DNS failure — is a failure and triggers retries.
The retry schedule uses exponential backoff over a 24-hour window:
| Attempt | Roughly when | Cumulative time from initial event |
|---|---|---|
| 1 (initial) | Immediately | 0 |
| 2 | +5 min | 5 min |
| 3 | +30 min | 35 min |
| 4 | +2 hr | ~2.5 hr |
| 5 | +6 hr | ~8.5 hr |
| 6 (final) | +12 hr | ~20.5 hr |
After the final attempt, the event is considered permanently failed and is not retried again. The delivery record is preserved for at least 90 days and remains queryable via the delivery-log endpoint.
Every retry attempt carries the same eventId and correlationId. Use eventId to deduplicate on your side; use correlationId to correlate across your logs and Cirrus's delivery history.
Delivery headers
Every delivery — first attempt or retry — includes:
| Header | Description |
|---|---|
Content-Type | Always application/json. |
X-Cirrus-Signature | HMAC-SHA256 of the raw body, hex-encoded. See Security. |
X-Cirrus-Event-Type | Same value as body.eventType. Lets you route without JSON-parsing. |
X-Cirrus-Correlation-Id | Stable across all attempts for one event. |
X-Cirrus-Payload-Version | Always 2 for v1alpha1 subscriptions. |
Inspecting delivery history
Every delivery attempt — successful or failed — is recorded. Query via the Platform API:
The response is a paginated list of WebhookDelivery records with:
status: succeeded | failed | pendingresponseCode— the HTTP status your endpoint returned (ornullon connection failure)responseTimeMs— round-trip timeattemptNumber— 1-indexednextRetryAt— when the next attempt will fire;nullif this was the final attempt
Filter by ?status=failed&since=24h to diagnose "why did my webhook stop working" cases quickly. Or filter by ?correlationId=corr_... to see every attempt for one event's retry chain.
Full endpoint documentation is on GET /api/v1alpha1/webhook-subscriptions/{id}/deliveries.
curl -s "https://altus.cirrusinsight.com/api/v1alpha1/webhook-subscriptions/sub_.../deliveries?status=failed" \
-H "X-Cirrus-Api-Key: $TOKEN"Chronic failure handling
An endpoint that consistently fails for 72 hours is automatically transitioned to disabled to protect Cirrus's outbound queue from unbounded retries.
Timeline:
| Elapsed | State | What Cirrus does |
|---|---|---|
| 0 | active | Normal delivery. |
| First 24h of failure | active | Emails your org admin. Continues delivering; may recover here. |
| 24-72h of continued failure | active | Continues delivering; emails escalate. |
| 72h+ of continued failure | disabled | Stops delivery. Final email to admin. Delivery history is preserved. |
To recover a chronically-disabled subscription: delete it and create a new one. The new subscription's signingSecret will be different — update your endpoint's secret store before it goes into service.
Debugging checklist
If deliveries are failing:
- Query the delivery log.
GET /api/v1alpha1/webhook-subscriptions/{id}/deliveries?status=failed&limit=10shows the last 10 failures with response codes and timing. Look for patterns — always the same status code? Always timing out? - Check your endpoint's TLS certificate. Cirrus refuses plain HTTP and rejects self-signed / expired certificates.
- Verify signature verification. Run a delivery through your endpoint locally with logging on the signature-verification step; a mismatch means either the secret is wrong or the body is being modified before verification.
- Watch response times. A
responseTimeMsnear 30,000 means Cirrus is timing out. Move the heavy work into a background job and respond202 Acceptedimmediately. - Check
correlationIdin your logs. If you're loggingX-Cirrus-Correlation-Idper request, you can trace an event across your log pipeline and match Cirrus's delivery records. - If the subscription is
disabled— it's not coming back. Delete and recreate.