For AI agents: a documentation index is available at https://docs.coverbase.com/llms.txt — this page is also available in markdown by appending .md to the URL.
Webhooks are the outbound half of an integration. This page documents how events are delivered, how to verify signatures, retry behavior, and the event catalog. To register, list, update, delete, test, or inspect the delivery history of a subscription, see the Webhooks API. For the audit trail of every attempt, see Webhook delivery history.
When deliveries happen
When a subscribed event occurs, Coverbase POSTs a JSON envelope to every active webhook subscribed to that event type. Deliveries originate from three sources, and all of them are recorded in delivery history:- Domain-event fan-out — a domain event (e.g. a vendor is created) fans out to every subscription for that event type.
- Workflow
send_webhookaction — a workflow automation explicitly delivers its triggering event. See Workflow engine → Actions. - Manual test — the test endpoint sends a one-off delivery to a single subscription.
event_id is shared across all webhooks in the fan-out. Receivers can use it to dedupe a fan-out and to correlate a multi-subscription delivery.
Delivery format
A delivery is an HTTPPOST with a JSON body in this exact envelope:
| Field | Type | Notes |
|---|---|---|
event_id | string | Shared delivery/event identifier (cbevt_...). The same value for every webhook in one fan-out. |
event_type | string | The event type string (see the event catalog). |
occurred_at | integer | Unix timestamp in seconds, generated at send time. |
data | object | Event-specific payload. For real events these are the catalog fields for that event type (and data echoes event_type). For a manual test, data is your custom payload (default {"test": true}). |
workflow_run_id or any other field.
Request headers
| Header | Value |
|---|---|
Content-Type | application/json |
Coverbase-Signature | Lowercase hex HMAC-SHA256 of the raw request body, keyed by your webhook secret. |
X-Coverbase-Event-Id | Same value as event_id. |
X-Coverbase-Event-Type | Same value as event_type. |
Signature verification
The signature isHMAC-SHA256(secret, raw_request_body) rendered as a lowercase hex string, sent in the Coverbase-Signature header. The key is the secret you registered with the subscription. Verify it against the raw bytes of the request body, before parsing JSON, with a constant-time comparison.
Python
Node.js
Delivery & retries
| Property | Value |
|---|---|
| HTTP method | POST |
| Connection timeout | 10 seconds per attempt |
| Retries | Up to 5 attempts on failure (timeout or connection error) |
| Retry backoff | None — Hatchet retries immediately; no exponential backoff, no jitter |
| Ordering | Not guaranteed — deliveries are unordered |
| Guarantee | At-least-once — the same event_id may be delivered more than once |
| Endpoint requirement | Public HTTPS endpoint (see URL restrictions) |
occurred_at and event_id are generated at send time. Make your receiver idempotent: dedupe on X-Coverbase-Event-Id and process the same event id at most once. Respond with a 2xx quickly to acknowledge; non-2xx, timeouts, and connection errors are retried up to 5 times in rapid succession.
Source IP
Coverbase does not publish a fixed egress IP range for outbound webhook deliveries. Authenticate the sender by HMAC signature verification (see Signature verification) — not by source IP. The compute fleet is autoscaled and the public IPs that originate deliveries change frequently. If you operate behind a network perimeter that requires a static allow-list, route deliveries through a customer-controlled HTTPS proxy with a stable egress IP and forward to the real receiver after re-verifying the signature.Delivery history retention
Every delivery attempt is recorded in delivery history for 90 days. Older rows are deleted by a daily background job; the API still serves the window inside retention viaGET /v1/webhooks/{id}/deliveries. Capture deliveries you need beyond that window from your receiver side at delivery time.
URL restrictions
Webhook URLs must be public HTTPS endpoints. A URL is rejected at create/update time (400 invalid_url) if it is not HTTPS, carries credentials, uses a non-standard port, or resolves to a private, loopback, link-local, or metadata address (e.g. 169.254.169.254).
The same check is re-applied with DNS resolution at delivery time, so a hostname that is repointed to an internal address after registration (DNS rebinding) is still blocked. A delivery blocked this way is recorded with status error in delivery history.
Event catalog
These are the only values valid in a subscription’sevents array and the only event types emitted. The events field is strictly validated against this set — see the behavior change below. Use the exact, case-sensitive strings.
event_type | data fields |
|---|---|
Assessment.Created | assessment_id |
Assessment.AssigneeChanged | assessment_id, old_assignee_id (nullable), new_assignee_id (nullable) |
Assessment.StatusChanged | assessment_id, old_status, new_status |
QuestionnaireResponse.Created | questionnaire_response_id |
QuestionnaireResponse.StatusChanged | questionnaire_response_id, old_status, new_status |
Review.StatusChanged | review_id, old_status_id (nullable), new_status_id (nullable) |
WorkQueueItem.Created | work_queue_item_id |
WorkQueueItem.Completed | work_queue_item_id |
Vendor.Created | vendor_id |
Vendor.Updated | vendor_id |
Procurement.Created | procurement_id |
Procurement.StatusChanged | procurement_id, old_status_id (nullable), new_status_id |
Service.Created | service_id |
Service.Updated | service_id |
OrgIntake.QuestionnaireRemoved | questionnaire_id, intake_disabled (bool) |
OrgIntake.Disabled | removed_questionnaire_id |
IntakeSession.Created | intake_session_id |
IntakeSession.Submitted | intake_session_id |
RadarEvent.Created | radar_event_id |
RadarEvent.Updated | radar_event_id, field_diffs |
RadarEvent.Deleted | radar_event_id |
RadarDetectorResult.Created | radar_detector_result_id |
RadarDetectorResult.Updated | radar_detector_result_id, field_diffs |
RadarDetectorResult.Deleted | radar_detector_result_id |
Reassessment.Created | reassessment_id |
Reassessment.Updated | reassessment_id, field_diffs |
Reassessment.Deleted | reassessment_id |
A radar alert is a
RadarDetectorResult — subscribe to RadarDetectorResult.Created to be notified of new alerts and RadarDetectorResult.Updated (whose field_diffs will include is_dismissed) for triage activity. *.Updated events carry a field_diffs object mapping each changed field to its { "old_value", "new_value" }. A soft-archive (is_archived → true) surfaces as *.Deleted, not *.Updated. See the Radar and Reassessments APIs.cbvndr_..., cbqsrw_...); see API conventions → IDs. Every event’s data also echoes its own event_type.
webhook.test is a valid value only for the test endpoint’s event_type field. It is not a subscribable event type — it will be rejected if used in a subscription’s events array.