SIGNALS Documentation
API Reference

Webhook Event Registry

Contract for registering outbound webhook event names, grouped discovery metadata, and metering weights.

Overview

App\Services\Api\WebhookEventRegistry is the runtime registry for outbound webhook event discovery metadata and metering weights.

Core binds it as a singleton in AppServiceProvider and seeds it by registering every name in WebhookEventRegistry::CORE_EVENT_NAMES. The catalogue is intentionally large, so this page documents the event-definition contract and discovery helpers rather than duplicating the entire event reference. For the exhaustive shipped list, use the Webhooks API reference.

Core's static REST subscription and audit-bridge allow-list is WebhookService::EVENTS, which aliases CORE_EVENT_NAMES. Boot-time registry contents therefore match that list, but runtime registrations do not extend the static allow-list.

Public surface

Method Purpose
register() Register one event definition
registerMany() Register multiple event definitions atomically
get() Return one event definition or null
all() Return the full keyed event map
groups() Return grouped discovery metadata
names() Return the flat list of currently registered event names
has() Check whether an event name is registered
weight() Return the event's outbound metering weight

This metadata registry does not publish a separate registered-value interface. Its current framework contract is the typed public surface on this page plus the documented registration shape and runtime behavior below.

Accepted registration shape

Each event is identified by its registration name. Core uses dotted names such as account.created, settings.updated, and document.pdf_generated, but the registry does not require event names to be non-empty or dotted. It only rejects a duplicate name; callers are responsible for choosing a meaningful name.

The accepted definition shape is:

[
    'label' => 'Created', // optional
    'group' => 'member', // optional
    'weight' => 1, // optional
]

Defaults are derived from the event name:

  • group defaults to the part before the first .
  • label defaults to a headline version of the suffix after the first .
  • weight defaults to 1

The definition shape is enforced by PHPDoc and static analysis, not by runtime registry validation. At runtime only duplicate event names are rejected. Empty label and group values are stored unchanged, and integer weights may be zero or negative. Callers remain responsible for supplying the documented types; for example, storing a non-integer weight can later violate the declared weight(): int return type.

Identity, collisions, and grouping

Event identity is the event name itself.

  • register() throws InvalidArgumentException when the name is already present
  • registerMany() performs duplicate checks before mutating state, so collisions leave the registry unchanged

groups() sorts event groups alphabetically by group key. Each group exposes a human-readable label plus a flat list of event names.

names() preserves the registry's registration order. It supports runtime discovery and the Livewire subscription picker, but it does not replace the static list used by the REST request DTOs and the audit bridge.

Current core registrations and discovery guidance

The shipped catalogue is seeded from CORE_EVENT_NAMES and surfaced to users through the API console, webhook forms, and delivery jobs.

Representative shipped events include:

Event Group Current meaning
account.created account Account lifecycle creation
settings.updated settings Settings API update completed
document.pdf_generated document Document pipeline rendered a PDF
vehicle.assigned vehicle Fleet assignment event

Use the registry helpers instead of copying the full list:

  • names() supports runtime discovery and Livewire webhook-form validation
  • groups() powers grouped selection UI in resources/views/livewire/api/webhooks.blade.php
  • all() exposes the normalized metadata when you need labels, groups, and weights together

Lookup and failure behavior

  • get($name) returns the normalized event definition or null
  • has($name) is the non-throwing existence check
  • weight($name) returns the warehoused weight, or 1 when the name is unknown

The registry itself does not dispatch events. It publishes the event catalogue that delivery and management flows consume.

Ordering and runtime consumption

The registry's weight value is about outbound metering, not delivery order.

App\Jobs\DeliverWebhook resolves get() and weight() on the first delivery attempt so it can:

  1. write price_weight and weighted_units to the webhook_logs row
  2. increment outbound daily usage on the webhook_sent channel using the event group as the metering resource

The management surfaces have two different validation boundaries:

  • the Livewire webhook form validates against the runtime registry's names() output
  • REST CreateWebhookData and UpdateWebhookData validate subscriptions against the static WebhookService::EVENTS allow-list

DispatchWebhookForAuditableEvent and the document audit bridge also guard audit actions with WebhookService::EVENTS. Registering an event at runtime therefore adds registry discovery and metering metadata, but does not make that event available as an explicit named REST subscription or eligible for those audit-to-webhook bridges. A REST-created wildcard (*) subscription can still receive a custom event when another caller dispatches that name because WebhookService::dispatch() does not apply the static allow-list.

Worked example

Core registers the shipped event catalogue during application boot:

$registry = new WebhookEventRegistry;

foreach (WebhookEventRegistry::CORE_EVENT_NAMES as $name) {
    $registry->register($name);
}

With that registration in place:

  • names() includes settings.updated and document.pdf_generated
  • groups()['document']['events'] exposes the document events for the picker UI
  • weight('settings.updated') returns the default metering weight used by outbound usage recording