Skip to main content
Version: 2026.2

Custom Processors

A webhook processor gathers the payload for an event and sends the request to every subscriber. Replacing the processor for an event is the way to change what is sent, to whom, and what happens with the answer.

How an Event Reaches a Processor

Three event listeners are registered in services.yml, each listening to a set of Pimcore events. A listener does not send the request itself. It checks that a processor is tagged for the event, writes an entry into the bundle_data_hub_webhooks_queue table and dispatches a message. The Symfony Messenger worker then hands the entry to the processor, which calls fire().

ElementEventListener

Handles the add and update events for Data Objects, Documents and Assets.

Pimcore\Bundle\DataHubWebhooksBundle\EventListener\ElementEventListener:
tags:
- { name: kernel.event_listener, event: pimcore.dataobject.postAdd, method: processEvent }
- { name: kernel.event_listener, event: pimcore.dataobject.postUpdate, method: processEvent }
- { name: kernel.event_listener, event: pimcore.dataobject.postUpdateFailure, method: processEvent }
- { name: kernel.event_listener, event: pimcore.asset.postAdd, method: processEvent }
# ...

ElementDeleteEventListener

Handles the delete events. It is separate because the element no longer exists once the worker runs, so this listener extracts the payload while the element is still available and stores it as context information on the queue entry.

Pimcore\Bundle\DataHubWebhooksBundle\EventListener\ElementDeleteEventListener:
tags:
- { name: kernel.event_listener, event: pimcore.dataobject.postDelete, method: processEvent }
- { name: kernel.event_listener, event: pimcore.dataobject.postDeleteFailure, method: processEvent }
- { name: kernel.event_listener, event: pimcore.asset.postDelete, method: processEvent }
# ...

WorkflowEventListener

Handles the workflow events. It stores the workflow name, the transition and the marking as context information.

Pimcore\Bundle\DataHubWebhooksBundle\EventListener\WorkflowEventListener:
tags:
- { name: kernel.event_listener, event: workflow.entered, method: processEvent }
- { name: kernel.event_listener, event: workflow.completed, method: processEvent }

The element listeners skip events on data object folders and events carrying the isAutoSave argument.

The Shipped Processors

Every processor implements Processors\WebhookProcessorInterface:

ClassAdds
AbstractWebhookProcessorThe behaviour shared by all processors.
AssetWebhookProcessorAsset specifics, such as embedding binary data.
DataObjectWebhookProcessorData object specifics, such as including unpublished objects.
DocumentWebhookProcessorDocument specifics, such as userModification.
WorkflowWebhookProcessorWorkflow specifics, such as transitions and markings.

Each event is wired to a processor by a tagged service. The $httpMethod argument decides the verb of the request:

pimcore.webhooks.processor.dataobject.postAdd:
class: Pimcore\Bundle\DataHubWebhooksBundle\Processors\DataObjectWebhookProcessor
arguments:
$httpMethod: 'POST'
tags:
- { name: pimcore.datahub.webhooks_event, event: pimcore.dataobject.postAdd}

pimcore.webhooks.processor.dataobject.postUpdate:
class: Pimcore\Bundle\DataHubWebhooksBundle\Processors\DataObjectWebhookProcessor
arguments:
$httpMethod: 'PUT'
tags:
- { name: pimcore.datahub.webhooks_event, event: pimcore.dataobject.postUpdate}

pimcore.webhooks.processor.dataobject.postDelete:
class: Pimcore\Bundle\DataHubWebhooksBundle\Processors\DataObjectWebhookProcessor
arguments:
$httpMethod: 'DELETE'
tags:
- { name: pimcore.datahub.webhooks_event, event: pimcore.dataobject.postDelete}

Writing Your Own Processor

warning

AssetWebhookProcessor, DataObjectWebhookProcessor, DocumentWebhookProcessor and WorkflowWebhookProcessor are final and cannot be subclassed. AbstractWebhookProcessor is not final, but it is marked @internal, so its behaviour may change without a deprecation path.

The stable contract is the interface Processors\WebhookProcessorInterface.

Implement WebhookProcessorInterface and register the class as a tagged service, exactly as shown above. The interface requires three methods:

  • fire(): executes the webhook based on the Datahub configuration.
  • matchByEvent(): reports whether this processor handles the current event.
  • matchBySchema(): reports whether the event and its element match the Datahub configuration, meaning workspaces, types and the rest of the schema.

Overridable Hooks

Extending AbstractWebhookProcessor gives you the shared behaviour and these hooks. Accept the @internal caveat above before relying on them.

MethodPurposeDefault
mustSkipWebhookRequest()Skip sending the request to a subscriber.Returns false.
updateRequestBodyForSubscriber()Adjust the payload per subscriber.Returns the payload unchanged.
getHttpMethodForSubscriber()Choose the HTTP method per subscriber.Returns the $httpMethod of the service definition.
getAdditionalOptionsForSubscriber()Add request options per subscriber, for example authentication headers.Returns the custom headers configured on the Subscribers tab.
handleResponse()React to the subscriber's response, for example by updating the element.Does nothing.