adachsoft / webhook-engine
Framework-agnostic engine routing a single event to many configured webhooks with per-target rules, payload mapping and signing.
Requires
- php: ^8.3
- adachsoft/collection: ^3.0
- adachsoft/rule-evaluator-contract: dev-main as 1.0.0
- guzzlehttp/guzzle: ^8.0
Requires (Dev)
- adachsoft/php-code-style: ^0.5.0
- friendsofphp/php-cs-fixer: ^3.95
- phpstan/phpstan: ^2.2
- phpunit/phpunit: ^13.3
- rector/rector: ^2.6
Suggests
- adachsoft/rule-evaluator-expression-language: Ready-to-use RuleEvaluatorInterface implementation based on Symfony ExpressionLanguage.
This package is not auto-updated.
Last update: 2026-08-13 02:04:02 UTC
README
Framework-agnostic PHP engine that routes one event to configured webhooks. Each target can define an evaluation rule, payload mapping, request headers, timeout and optional payload signing.
Requirements
- PHP 8.3 or newer
- A
RuleEvaluatorInterfaceimplementation - A
WebhookSenderInterfaceimplementation
Installation
composer require adachsoft/webhook-engine
The bundled GuzzleWebhookSender adapter is available through the package runtime dependency on guzzlehttp/guzzle. Install a package that implements adachsoft/rule-evaluator-contract for rule evaluation.
Quick start
Implement EventInterface for the events emitted by your application:
use AdachSoft\WebhookEngine\Contract\EventInterface;
final readonly class OrderCreatedEvent implements EventInterface
{
public function getEventName(): string
{
return 'order.created';
}
public function getPayload(): array
{
return ['order' => ['id' => 42, 'total' => 1999]];
}
}
Create a sender, a rule evaluator, and the engine through WebhookEngineFactory. Pass the event with a WebhookConfigDtoCollection to processEvent().
use AdachSoft\WebhookEngine\Collection\WebhookConfigDtoCollection;
use AdachSoft\WebhookEngine\Dto\WebhookConfigDto;
use AdachSoft\WebhookEngine\Vo\TargetUrlVo;
use AdachSoft\WebhookEngine\WebhookEngineFactory;
$engine = (new WebhookEngineFactory())->createDefault($webhookSender, $ruleEvaluator);
$configurations = new WebhookConfigDtoCollection([
new WebhookConfigDto(new TargetUrlVo('https://example.test/webhooks/orders')),
]);
$results = $engine->processEvent(new OrderCreatedEvent(), $configurations);
The returned ExecutionResultDtoCollection contains one result per configured target. A result records whether a target was triggered, whether delivery succeeded, its HTTP status code, elapsed time, and an error message when available.
Webhook configuration
WebhookConfigDto defines one target:
targetUrlVo: required target URL.ruleExpressionVo: optionalRuleExpressionVo; a target is skipped when its rule evaluates tofalse.mapping: optional target-key to dot-path map for the outgoing JSON payload.headers: request headers.timeoutSeconds: per-request timeout; defaults to5.signingSecretVo: optional secret passed to the configured signer.httpMethod: HTTP method; defaults toPOST.
Use RuleExpressionVo from adachsoft/rule-evaluator-contract to activate conditional delivery:
use AdachSoft\RuleEvaluatorContract\Vo\RuleExpressionVo;
use AdachSoft\WebhookEngine\Dto\WebhookConfigDto;
use AdachSoft\WebhookEngine\Vo\TargetUrlVo;
$configuration = new WebhookConfigDto(
targetUrlVo: new TargetUrlVo('https://example.test/webhooks/orders'),
ruleExpressionVo: new RuleExpressionVo("event == 'order.created'"),
headers: ['X-Source' => 'storefront'],
);
The rule evaluator receives event and data in its context. event is the event name and data is the complete event payload.
Payload transformations
DotPathPayloadTransformer, used by the default factory, creates a payload from dot paths. The mapping key becomes an output key and its value selects a field from the event payload.
$mapping = [
'orderId' => 'order.id',
'amount' => 'order.total',
];
For an event payload containing ['order' => ['id' => 42, 'total' => 1999]], this mapping produces ['orderId' => 42, 'amount' => 1999]. An empty mapping forwards the whole payload.
Implement PayloadTransformerInterface and pass it to WebhookEngineFactory::create() for another transformation format.
Signing
The default NullPayloadSigner sends no signing headers. Configure HmacPayloadSigner when receivers require HMAC authentication:
use AdachSoft\WebhookEngine\Signing\HashAlgorithmEnum;
use AdachSoft\WebhookEngine\Signing\HmacPayloadSigner;
use AdachSoft\WebhookEngine\Vo\SigningSecretVo;
$signer = new HmacPayloadSigner(HashAlgorithmEnum::Sha256);
$secret = new SigningSecretVo('shared-secret');
Set the secret as signingSecretVo on each webhook configuration. Signing headers override equally named configured headers. Implement PayloadSignerInterface for a different signing scheme and provide it to WebhookEngineFactory::create().
Transport and custom senders
WebhookSenderInterface is the transport boundary. Implement it to integrate any HTTP client, queue, or delivery mechanism. Its send() method receives a WebhookRequestDto and returns a WebhookResponseDto; transport failures must be reported as WebhookTransportException.
GuzzleWebhookSender adapts Guzzle for HTTP delivery and accepts a PSR-compatible GuzzleHttp\ClientInterface. Provide a custom sender to either factory method when your application uses another transport.
Custom dispatch strategies
The factory uses SequentialDispatchStrategy by default, which processes configurations in order. Implement DispatchStrategyInterface and pass it to WebhookEngineFactory::create() to provide a different dispatch policy.
License
MIT