Event Delivery Model¶
This document describes how events are delivered from the WhiteLabelCRO platform to external systems.
Delivery Methods¶
The platform supports two delivery methods that share the same underlying infrastructure:
Webhooks (Push)¶
When a qualifying business event occurs, the platform sends an HTTP POST request to each subscribed webhook endpoint.
Characteristics: - Near real-time delivery - Request signing with HMAC-SHA256 - Automatic retry on failure - Delivery logging for troubleshooting
Zapier REST Hooks (Push)¶
Zapier uses the REST Hooks pattern to receive events. When a user enables a Zap, Zapier automatically subscribes to a webhook endpoint. Events are pushed to Zapier in real-time using the same delivery infrastructure as custom webhooks.
Characteristics: - Real-time delivery (not polling) - Subscription managed automatically by Zapier - Same retry and delivery logic as custom webhooks
Delivery Flow¶
- Event Creation: A business operation triggers event emission
- Event Storage: The canonical event is stored in the events table
- Subscription Matching: The dispatcher identifies subscriptions matching the event type
- Delivery Attempt: HTTP POST sent to each matching subscription URL
- Response Handling: Success (2xx) or failure logged
- Retry Logic: Failed deliveries queued for retry
Webhook Delivery Details¶
Request Format¶
Webhook deliveries are HTTP POST requests with:
- Content-Type: application/json
- Signature headers for verification
- JSON body containing the event envelope
Request Signing¶
All webhook requests include an HMAC-SHA256 signature computed over the request body. The signing secret is established when the webhook subscription is created.
Recipients should verify the signature before processing the request to prevent spoofing.
Retry Behavior¶
Failed deliveries (non-2xx response or timeout) are retried with exponential backoff: - Maximum 10 retry attempts - Increasing delay between attempts - Total retry window up to 24 hours
Events are never lost. If webhook delivery fails after all retries, the event remains available via the events polling API.
Delivery Logging¶
Each delivery attempt is logged with: - Subscription ID - Event ID - HTTP response code - Response body (truncated if over 4000 characters) - Elapsed time
Delivery logs support troubleshooting and can be viewed in the Admin Portal.
Diagram¶
flowchart LR
Emit[Event Emitted] --> Store[Event Stored]
Store --> Match[Match Subscriptions]
Match --> Queue[Delivery Queue]
Queue --> Attempt[HTTP POST Attempt]
Attempt -->|2xx Response| Success[Success]
Attempt -->|Non-2xx/Timeout| Retry{Retry?}
Retry -->|Yes| Queue
Retry -->|Max Retries| Failed[Failed]
Success --> Log[Delivery Log]
Failed --> Log
Store -.->|Also accessible| Poll[Events API - Polling]
style Emit fill:#fff4e6
style Success fill:#e8f5e9
style Failed fill:#ffebee
style Log fill:#f3e5f5
Event Envelope Structure¶
Events are delivered in a standard envelope format:
| Field | Description |
|---|---|
id |
Unique event identifier (for deduplication) |
type |
Event type (e.g., client.created) |
createdUtc |
Timestamp when the event occurred |
companyId |
Tenant identifier |
payload |
JSON object with event-specific data |
metadata |
JSON object with additional context |
Idempotency¶
Event IDs are globally unique. Recipients should use the event ID to deduplicate in case of: - Retry deliveries - Multiple subscriptions receiving the same event - Network issues causing duplicate delivery
Implement idempotency checks by storing processed event IDs and skipping duplicates.
Delivery Guarantees¶
At-Least-Once Delivery¶
The platform guarantees at-least-once delivery for webhook events. An event may be delivered more than once in edge cases: - Network timeout after successful processing - Retry triggered before acknowledgment received
Recipients must handle duplicate deliveries gracefully using event IDs.
Event Ordering¶
Events are delivered in approximate chronological order but strict ordering is not guaranteed. Events for the same entity may arrive out of order in high-throughput scenarios.
If ordering matters, use the createdUtc timestamp to sequence events.
Subscription Management¶
Creating Subscriptions¶
Webhook subscriptions are created via:
- Admin Portal (Settings > Integrations > Webhooks)
- API (POST /api/v1/webhooks/subscriptions)
Each subscription specifies: - Target URL (HTTPS required in production) - Event types to receive - Signing secret (auto-generated if not provided)
Event Type Filtering¶
Subscriptions filter events by type. Specify one or more event types to receive only relevant events. Event types are case-insensitive and normalized to lowercase.
Disabling Subscriptions¶
Subscriptions can be disabled without deletion. Disabled subscriptions do not receive events but retain their configuration.
Security Requirements¶
HTTPS Required¶
Production webhook endpoints must use HTTPS (TLS 1.2+). HTTP endpoints are rejected except in development environments.
URL Validation¶
Webhook URLs are validated to prevent SSRF attacks: - Must be absolute URLs - Hostname resolved and checked against blocklist - Private/loopback IP addresses blocked in production
Timeout Handling¶
Webhook requests timeout after a configured duration. Endpoints should respond within the timeout window to avoid unnecessary retries.
Polling Fallback¶
For consumers unable to receive webhooks, the events API provides cursor-based pagination:
- GET /api/v1/events
- Filter by event type
- Paginate using cursor from X-Paging-Cursor header
Polling is less efficient than webhooks but provides a reliable fallback.