Triggers

The TYPO3 Core currently provides the following triggers for webhooks:

Page Modification
Triggers when a page is created, updated or deleted
File Added
Triggers when a file is added
File Updated
Triggers when a file is updated
File Removed
Triggers when a file is removed
Login Error Occurred
Triggers when a login error occurred

These triggers are meant as a first set of triggers that can be used to send webhooks. In most projects however, it is likely that custom triggers are required.

Custom triggers

Trigger by PSR-14 events

Custom triggers can be added by creating a Message for a specific PSR-14 event and by tagging that message as a webhook message.

The following example shows how to create a simple webhook message for the \TYPO3\CMS\Core\Resource\Event\AfterFolderAddedEvent :

EXT:my_extension/Webhooks/Message/FolderAddedMessage.php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\Webhooks\Message;

use TYPO3\CMS\Core\Attribute\WebhookMessage;
use TYPO3\CMS\Core\Messaging\WebhookMessageInterface;
use TYPO3\CMS\Core\Resource\Event\AfterFolderAddedEvent;

#[WebhookMessage(
    identifier: 'typo3/folder-added',
    description: 'LLL:EXT:webhooks/Resources/Private/Language/locallang_db.xlf:sys_webhook.webhook_type.typo3-folder-added'
)]
final class FolderAddedMessage implements WebhookMessageInterface
{
    public function __construct(
        private readonly int $storageUid,
        private readonly string $identifier,
        private readonly string $publicUrl
    ) {}

    public static function createFromEvent(AfterFolderAddedEvent $event): self
    {
        $folder = $event->getFolder();
        return new self($folder->getStorage()->getUid(), $folder->getIdentifier(), $folder->getPublicUrl());
    }

    public function jsonSerialize(): array
    {
        return [
            'storage' => $this->storageUid,
            'identifier' => $this->identifier,
            'url' => $this->publicUrl,
        ];
    }
}
Copied!
  1. Create a final class implementing the WebhookMessageInterface .
  2. Add the WebhookMessage attribute to the class. The attribute requires the following information:

    • identifier: The identifier of the webhook message.
    • description: The description of the webhook message. This description is used to describe the trigger in the TYPO3 backend.
  3. Add a static method createFromEvent() that creates a new instance of the message from the event you want to use as a trigger.
  4. Add a method jsonSerialize() that returns an array with the data that should be send with the webhook.

Use Services.yaml instead of the PHP attribute

Instead of the PHP attribute the Services.yaml can be used to define the webhook message. The following example shows how to define the webhook message from the example above in the Services.yaml:

EXT: my_extension/Configuration/Services.yaml
# ...

TYPO3\CMS\Webhooks\Message\FolderAddedMessage:
  tags:
    - name: 'core.webhook_message'
      identifier: 'typo3/folder-added'
      description: 'LLL:EXT:webhooks/Resources/Private/Language/locallang_db.xlf:sys_webhook.webhook_type.typo3-folder-added'
Copied!

Trigger by hooks or custom code

In case a trigger is not provided by the TYPO3 Core or a PSR-14 event is not available, it is possible to create a custom trigger - for example by using a TYPO3 hook.

The message itself should look similar to the example above, but does not need the createFromEvent() method.

Instead, the custom code (hook implementation) will create the message and dispatch it.

Example hook implementation for a datahandler hook (see \TYPO3\CMS\Webhooks\Listener\PageModificationListener ):

EXT:my_extension/Webhooks/Message/PageModificationListener.php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\Webhooks\Hook;

use Symfony\Component\Messenger\MessageBusInterface;
use TYPO3\CMS\Core\DataHandling\DataHandler;
use TYPO3\CMS\Core\Site\SiteFinder;
use TYPO3\CMS\Webhooks\Message\PageModificationMessage;

final class PageModificationListener
{
    public function __construct(
        private readonly MessageBusInterface $bus,
        private readonly SiteFinder $siteFinder,
    ) {}

    public function processDatamap_afterDatabaseOperations($status, $table, $id, $fieldArray, DataHandler $dataHandler)
    {
        if ($table !== 'pages') {
            return;
        }
        // ...
        $site = $this->siteFinder->getSiteByPageId($id);
        $message = new PageModificationMessage(
            'new',
            $id,
            $fieldArray,
            $site->getIdentifier(),
            (string)$site->getRouter()->generateUri($id),
            $dataHandler->BE_USER,
        );
        // ...
        $this->bus->dispatch($message);
    }
}
Copied!