Orange Collar Media
Orange Collar Media
DOCS
OCMLABS/MODULE-WEBHOOK · ARCHITECTURE

How the Webhooks module is built - queue pipeline, database schema, and packaging

MAGENTO 2.4.7 - 2.4.8 PHP 8.2 - 8.4 LUMA + HYVÄ COMPOSER

The delivery pipeline

  1. Event capture. The ten curated events are wired to a single shared observer that snapshots entity data at observe time. Snapshotting is why delete events still carry full entity data at delivery, and why payloads reflect the state when the event fired rather than when the consumer ran. Custom events use a separate after plugin on the concrete event manager’s dispatch method, inert unless enabled in configuration.
  2. Payload building. The snapshot is converted to flat template variables. Orders are enriched with their lazy-loaded relations (items, billing and shipping addresses, payment) that a plain toArray() would miss; shipments with tracks and items. A key blacklist strips sensitive fields during conversion.
  3. Queueing. The observer publishes to the ocmlabs.webhook.trigger queue on the db connection. The synchronous work in the request path ends here.
  4. Dispatch. The consumer hands each message to a single dispatcher - the same entry point used by real deliveries, cron retries, and the admin Send Test. It validates the URL (SSRF guard), renders the payload and custom headers through sandboxed Smarty, signs the body (HMAC-SHA256, header omitted when no secret), applies Bearer/Basic auth, and POSTs via Guzzle with the configured timeout.
  5. Logging and retries. Every attempt writes a delivery log row. Retryable failures store the serialized message in the retry table with a next_attempt_at computed by exponential backoff; a per-minute cron re-publishes due retries without re-snapshotting. Template render errors are deterministic and never retried.

Database

Three tables:

  • ocmlabs_webhook - subscriptions: name, event, URL, payload template, content type, custom headers (JSON), HMAC secret and auth credentials (encrypted), status, store scope.
  • ocmlabs_webhook_delivery_log - one row per attempt: delivery UUID, attempt number, status (success / failed / retrying), HTTP code, error message, request body (only when payload logging is on, 64 KB cap), response body (4 KB cap), duration. Cascade-deletes with its webhook.
  • ocmlabs_webhook_retry - the pending-retry queue: serialized message plus the next_attempt_at timestamp the retry cron polls on.

Cron jobs

JobSchedulePurpose
ocmlabs_webhook_retryevery minuteRe-publish due retries
ocmlabs_webhook_prune_log02:30 dailyDelete delivery log rows older than the configured retention

Admin surface

Route frontName ocmlabs_webhook, menu under System > OCM Labs: a webhooks grid and form (with synchronous Send Test and a live template-variables endpoint), plus a read-only delivery log grid and detail view. ACL resources: OCMLabs_Webhook::manage (with a delete child), OCMLabs_Webhook::log, and OCMLabs_Webhook::config. A data patch installs ten disabled sample webhooks, one per curated event, each carrying that event’s default payload template.

Sample-data parity

The “Available Template Variables” preview and Send Test resolve their sample data through the same payload-building pipeline real deliveries use. What the preview documents, what a test renders against, and what production delivers cannot drift apart - including enriched order relations like order.billing_address.

Packaging

Distributed as two Composer packages from one repository:

PackageTypePurpose
ocmlabs/module-webhookmagento2-moduleThe module itself. Installs on Magento Open Source and Adobe Commerce.
ocmlabs/module-webhook-commercemetapackageAdobe Commerce licensing gate. Requires the community package plus magento/product-enterprise-edition.

Dependencies: smarty/smarty ^5.8, guzzlehttp/guzzle ^7.5, magento/framework 103.0.7 - 103.0.8. The module declares no REST or GraphQL API for managing subscriptions - webhooks are configured through the admin UI.