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:
groupdefaults to the part before the first.labeldefaults to a headline version of the suffix after the first.weightdefaults to1
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()throwsInvalidArgumentExceptionwhen the name is already presentregisterMany()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 validationgroups()powers grouped selection UI inresources/views/livewire/api/webhooks.blade.phpall()exposes the normalized metadata when you need labels, groups, and weights together
Lookup and failure behavior
get($name)returns the normalized event definition ornullhas($name)is the non-throwing existence checkweight($name)returns the warehoused weight, or1when 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:
- write
price_weightandweighted_unitsto thewebhook_logsrow - increment outbound daily usage on the
webhook_sentchannel 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
CreateWebhookDataandUpdateWebhookDatavalidate subscriptions against the staticWebhookService::EVENTSallow-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()includessettings.updatedanddocument.pdf_generatedgroups()['document']['events']exposes the document events for the picker UIweight('settings.updated')returns the default metering weight used by outbound usage recording