itmosoft / laravel-webhooks
Signed outbound webhook delivery, retries and delivery history for Laravel applications.
Requires
- php: ^8.3
- illuminate/bus: ^12.0|^13.0
- illuminate/console: ^12.0|^13.0
- illuminate/contracts: ^12.0|^13.0
- illuminate/database: ^12.0|^13.0
- illuminate/http: ^12.0|^13.0
- illuminate/queue: ^12.0|^13.0
- illuminate/support: ^12.0|^13.0
Requires (Dev)
- orchestra/testbench: ^10.0|^11.0
- phpunit/phpunit: ^11.0|^12.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Signed outbound webhook delivery for Laravel 12 and 13.
Features
- Register endpoint URLs and per-endpoint signing secrets.
- Subscribe endpoints to named event types (
*supported). - Queue event deliveries with a stable event UUID.
- Sign the exact JSON request body with HMAC-SHA256.
- Persist delivery attempts, HTTP response status and response excerpt.
- Retry failed deliveries manually or with the included retry command.
- Configurable table prefix, timeout and retry policy.
Install
composer require itmosoft/laravel-webhooks php artisan vendor:publish --tag=webhooks-config php artisan vendor:publish --tag=webhooks-migrations php artisan migrate
The service provider also loads package migrations automatically. Publishing is optional unless you need to customize them.
Register an endpoint
use ItmoSoft\Webhooks\Models\WebhookEndpoint; $endpoint = WebhookEndpoint::create([ 'url' => 'https://example.com/hooks/orders', 'secret' => bin2hex(random_bytes(32)), 'events' => ['order.created', 'order.paid'], 'is_active' => true, ]);
Store secrets securely and never expose them in API responses or logs.
Dispatch an event
use ItmoSoft\Webhooks\Facades\Webhooks; Webhooks::dispatch('order.created', [ 'order_id' => 123, 'total' => 4999, ]);
Matching active endpoints receive queued DeliverWebhookJob jobs. The request includes:
X-ItmoSoft-Event: stable event UUIDX-ItmoSoft-Event-Type: event nameX-ItmoSoft-Timestamp: Unix timestampX-ItmoSoft-Signature:sha256=followed by the HMAC-SHA256 digest of the exact raw JSON body
The signature is calculated as hash_hmac('sha256', $rawBody, $endpointSecret). Receivers should compare signatures with a timing-safe comparison and enforce a timestamp tolerance to mitigate replay attacks.
Retry failed deliveries
use ItmoSoft\Webhooks\Models\WebhookDelivery; use ItmoSoft\Webhooks\Jobs\DeliverWebhookJob; $delivery = WebhookDelivery::findOrFail($id); DeliverWebhookJob::dispatch($delivery->id);
A scheduled retry command is also provided:
php artisan webhooks:retry
It queues eligible failed deliveries whose next_attempt_at is due. Schedule it in your application scheduler, for example every minute.
Testing
composer install
composer test
GitHub Actions runs PHPUnit against Laravel 12 and 13. The dedicated PHPUnit step fails the workflow if any test fails.
Operational notes
- Configure a real queue worker; do not use the
syncdriver in production. - The package stores response excerpts, not complete response bodies.
- Use HTTPS endpoints only in production. Add endpoint URL allowlisting/SSRF protections appropriate to your environment before allowing untrusted users to register URLs.
- Retries are at-least-once, not exactly-once. Receivers must be idempotent using
X-ItmoSoft-Event. - Delivery jobs use the queue's normal retry/timeout configuration. The package retry command is a separate, explicit retry mechanism.
- This package sends outbound webhooks. It does not implement inbound webhook signature verification.