Tag-based n8n webhook integration for Laravel. Fire events in your app, auto-dispatch to matching n8n workflows. Zero configuration per workflow — just tag your n8n workflows and the package handles the rest.
HasN8nTrigger trait to any Laravel Event classOrderCompleted → app:order-completed)app:order-completedcomposer require shelfwood/laravel-n8n
The service provider auto-discovers. Publish the config:
php artisan vendor:publish --tag=n8n-config
Add to your .env:
N8N_URL=https://your-n8n-instance.com
N8N_API_KEY=your-api-key
use Illuminate\Foundation\Events\Dispatchable;
use Shelfwood\N8n\Traits\HasN8nTrigger;
class OrderCompleted
{
use Dispatchable, HasN8nTrigger;
public function __construct(
public string $orderId,
public float $total,
) {}
public function toArray(): array
{
return [
'order_id' => $this->orderId,
'total' => $this->total,
];
}
}
event(new OrderCompleted($order->id, $order->total));
In your n8n instance, create a workflow with:
app:order-completedThe package finds the workflow by tag and POSTs:
{
"event": "App\\Events\\OrderCompleted",
"timestamp": "2026-04-13T00:00:00+00:00",
"tags": ["app:order-completed"],
"data": {
"order_id": "abc-123",
"total": 99.95
}
}
Override the auto-generated tag:
$event = new OrderCompleted($id, $total);
$event->setN8nTags(['custom:high-value-order']);
event($event);
If your project uses Filament, register the status page in your AdminPanelProvider:
use Shelfwood\N8n\Filament\Pages\N8nStatus;
->pages([
N8nStatus::class,
])
This shows:
// config/n8n.php
return [
'api' => [
'url' => env('N8N_URL', ''),
'key' => env('N8N_API_KEY', ''),
],
'workflows' => [
'timeout' => (int) env('N8N_WORKFLOW_TIMEOUT', 10),
'retry_attempts' => 3,
'retry_delay' => 5,
// Cache TTL for the workflow list (seconds). Every event dispatch
// would otherwise refetch the full workflow set. 0 disables.
'cache_ttl' => (int) env('N8N_WORKFLOWS_CACHE_TTL', 60),
],
// Tag prefix for auto-generated event tags. Override per environment to
// discriminate workflows on a single shared n8n (`staging:`, `prod:`).
'tag_prefix' => env('N8N_TAG_PREFIX', 'app:'),
// Directories scanned by the Filament status page
'event_directories' => [
'app/Events',
],
];
If your application stores events outside app/ (e.g. a src/Domain/*/Events
layout under a Domain\ PSR-4 root), override event_directories:
'event_directories' => [
'src/Domain/*/Events',
],
The status page resolves class names from composer.json PSR-4, so any
namespace mapped there works — no extra registration needed.
Two apps sharing one n8n? Set N8N_TAG_PREFIX=staging: on staging and
N8N_TAG_PREFIX=prod: on production. Tag your workflows accordingly and the
two streams stay isolated without duplicated workflows.
N8N_URL → events fire normally but no webhooks are dispatchedIn your test suite, set N8N_URL to empty in phpunit.xml:
<env name="N8N_URL" value=""/>
This disables webhook dispatch. Your n8n-specific tests can override:
config(['n8n.api.url' => 'https://n8n.test']);
Queue::fake();
event(new OrderCompleted('123', 50.00));
Queue::assertPushed(DispatchN8nWebhook::class);
MIT
How can I help you explore Laravel packages today?