Skip to content

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

  1. Event Creation: A business operation triggers event emission
  2. Event Storage: The canonical event is stored in the events table
  3. Subscription Matching: The dispatcher identifies subscriptions matching the event type
  4. Delivery Attempt: HTTP POST sent to each matching subscription URL
  5. Response Handling: Success (2xx) or failure logged
  6. 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.