Installation:
composer require shelfwood/laravel-n8n
php artisan vendor:publish --tag=n8n-config
Configure .env with N8N_URL and N8N_API_KEY.
First Use Case:
HasN8nTrigger trait:
use Shelfwood\N8n\Traits\HasN8nTrigger;
class UserRegistered
{
use HasN8nTrigger;
// ...
}
event(new UserRegistered($user));
app:user-registered) and sends the payload to n8n.n8n Setup:
app:user-registered (or the auto-generated tag).Event-Driven Integration:
HasN8nTrigger on all relevant events (e.g., OrderCreated, PaymentFailed).class InvoiceGenerated
{
use HasN8nTrigger;
public function __construct(public string $invoiceId) {}
public function toArray(): array { return ['invoice_id' => $this->invoiceId]; }
}
app:account-*) for n8n workflow organization.Payload Customization:
toArray() to shape data for n8n:
public function toArray(): array {
return [
'user' => $this->user->toJson(),
'metadata' => ['source' => 'web'],
];
}
Arrayable or Jsonable interfaces for consistency.Conditional Dispatching:
shouldDispatchToN8n():
public function shouldDispatchToN8n(): bool {
return config('n8n.skip_in_dev') || $this->isTestMode;
}
Bulk Events:
foreach ($orders as $order) {
event(new OrderProcessed($order));
}
Webhook Validation:
Environment Awareness:
config/n8n.php for local/dev:
'enabled' => env('APP_ENV') !== 'local',
public function shouldDispatchToN8n(): bool {
return app()->environment(['staging', 'production']);
}
Error Handling:
AppServiceProvider:
N8n::failed(function ($event, $exception) {
Log::error("n8n dispatch failed for {$event::class}", [
'exception' => $exception,
'payload' => $event->toArray(),
]);
});
Testing:
N8n::shouldReceive('dispatch')
->once()
->andReturn(true);
Http::fake() to verify webhook calls:
Http::fake([
'your-n8n-instance.com' => Http::response([], 200),
]);
Dynamic Tags:
class OrderShipped
{
use HasN8nTrigger;
public function getN8nTag(): string {
return "app:order-shipped:{$this->orderId}";
}
}
app:user-*-activity).Payload Enrichment:
public function toArray(): array {
return array_merge([
'user_id' => auth()->id(),
'ip_address' => request()->ip(),
], $this->defaultPayload());
}
Tag Mismatches:
app:class-name-snake) matches the n8n workflow tag.getN8nTag() or ensure n8n tags are lowercase/snake_case.Payload Size Limits:
toJson() with JSON_UNESCAPED_UNICODE:
public function toArray(): array {
return json_decode($this->rawData, true);
}
Rate Limiting:
event(new LargeBatchProcessed($data))->delay(now()->addSeconds(5));
Circular Dependencies:
processed_at field to events and skip if recently processed.API Key Exposure:
N8N_API_KEY in .env may not be secure for shared environments.env() with a fallback or a dedicated secrets manager.Timeouts:
config/n8n.php:
'timeout' => 30, // seconds
Log Payloads:
config/n8n.php:
'log_payloads' => true,
storage/logs/laravel-n8n.log.Verify Webhook URLs:
https://your-n8n-instance.com/webhook/123).Check n8n Execution:
401 Unauthorized → API key or URL is wrong.404 Not Found → Webhook URL mismatch.Payload Validation:
$input.all()
toArray() output.Queue Monitoring:
jobs table for stuck N8nDispatchJob records.Custom Dispatch Logic:
dispatchToN8n() to add pre/post-processing:
protected function dispatchToN8n(): void {
$this->enrichPayload();
parent::dispatchToN8n();
}
Multiple n8n Instances:
N8n::setInstance('staging', 'https://staging-n8n.com', 'key-staging');
N8n::dispatch($event, 'staging');
Webhook Signatures:
// In config/n8n.php
'validate_signature' => true,
'signature_key' => env('N8N_SIGNATURE_KEY'),
X-Signature header.Event Retries:
N8n::failed(function ($event, $exception) {
if ($exception instanceof \GuzzleHttp\Exception\ConnectException) {
$this->retryAfter(10); // seconds
}
});
Dynamic Webhook URLs:
How can I help you explore Laravel packages today?