oriceon / laravel-n8n-bridge
Full-featured bidirectional Laravel 13+ bridge for n8n โ DB-driven workflows, inbound/outbound tools, queue, circuit breaker, webhook auth.
Requires
- php: ^8.5
- laravel/framework: ^13.0
- spatie/laravel-package-tools: ^1.93
Requires (Dev)
- laravel/pint: ^1.29
- orchestra/testbench: ^11.0
- pestphp/pest: ^4.4
- pestphp/pest-plugin-laravel: ^4.1
- pestphp/pest-plugin-type-coverage: ^4.0
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^12.5
README
๐ laravel-n8n-bridge
A full-featured, bidirectional Laravel 13+ bridge for n8n โ DB-driven workflows, secured outbound webhook, secured inbound webhook receiver, circuit breakers, delivery statistics, tools exposed to n8n, DB queue system with live progress tracking, and multi-channel failure notifications.
โจ What this package does
Unlike other n8n packages for Laravel โ which are simple outbound HTTP clients โ laravel-n8n-bridge is a complete bidirectional integration:
| Feature | Other packages | laravel-n8n-bridge |
|---|---|---|
| Trigger workflow outbound | โ | โ |
| Outbound auth (token / bearer / HMAC-SHA256) | โ | โ |
| Outbound rate limiting (global + per-workflow) | โ | โ |
| Webhook mode (test / production / auto) | โ | โ |
| Inbound webhook receiver | โ | โ |
| Webhook auth (one key, all routes) | โ | โ |
| Rotatable API keys with grace period | โ | โ |
| Circuit Breaker per workflow | โ | โ |
| DB-driven workflows (not config files) | โ | โ |
| DB Queue with priority, batches, DLQ | โ | โ |
| Live progress tracking + broadcasting | โ | โ |
| Estimated completion time (EMA) | โ | โ |
| Tool system โ GET/POST/PATCH/DELETE | โ | โ |
| OpenAPI schema auto-generated | โ | โ |
| Daily statistics with chart-ready data | โ | โ |
| Notifications Slack/Discord/Teams/Mail | โ | โ |
| Idempotency native | โ | โ |
| DLQ + replay | โ | โ |
| Artisan commands | โ | โ (20+) |
| Full Pest test suite | โ | โ (832 tests) |
๐ Requirements
- PHP 8.5+
- Laravel 13.x
- n8n (self-hosted or cloud)
๐ Installation
composer require oriceon/laravel-n8n-bridge
โ๏ธ Configuration
If you want to publish the config or migrations, you can do so with:
php artisan vendor:publish --tag="n8n-bridge-config" php artisan vendor:publish --tag="n8n-bridge-migrations"
Then, run the migrations
php artisan migrate
Set .env variables
# n8n instance (multiple supported via config) N8N_BRIDGE_N8N_DEFAULT_API_BASE_URL=https://n8n.myapp.com N8N_BRIDGE_N8N_DEFAULT_API_KEY=your-n8n-api-key N8N_BRIDGE_N8N_DEFAULT_WEBHOOK_BASE_URL=https://n8n.myapp.com/webhook # Optional: explicit test URL (null = auto-derived by replacing /webhook โ /webhook-test) N8N_BRIDGE_N8N_DEFAULT_WEBHOOK_TEST_BASE_URL=https://n8n.myapp.com/webhook-test # Table prefix (default: n8n โ n8n__workflows__lists etc.) N8N_BRIDGE_TABLE_PREFIX=n8n # Notifications N8N_BRIDGE_NOTIFY_ENABLED=true N8N_BRIDGE_NOTIFY_CHANNELS=slack,mail N8N_BRIDGE_NOTIFY_SLACK_WEBHOOK=https://hooks.slack.com/services/xxx N8N_BRIDGE_NOTIFY_DISCORD_WEBHOOK=https://discord.com/api/webhooks/xxx N8N_BRIDGE_NOTIFY_MAIL_TO=ops@myapp.com N8N_BRIDGE_NOTIFY_ERROR_RATE=20.0 # Outbound rate limiting (0 = unlimited) N8N_BRIDGE_OUTBOUND_RATE_LIMIT=0 # Queue system N8N_BRIDGE_QUEUE_DEFAULT=default N8N_BRIDGE_QUEUE_DELETE_CHECKPOINTS=true N8N_BRIDGE_QUEUE_DURATION_SAMPLES=50
๐ Authentication
All /n8n/* routes require an X-N8N-Key header. One credential key works across all modules โ inbound, tools, and queue progress.
# Create a credential + key php artisan n8n:credential:create "Production" --instance=default # โ outputs: n8br_sk_a3f9b2c1... # In n8n: Personal โ Credentials โ Create credential โ Header Auth # Name: X-N8N-Key # Value: n8br_sk_a3f9b2c1...
See docs/credentials.md for rotation, IP whitelisting, grace periods, and multi-webhook setups.
๐ฅ Inbound โ receive data from n8n
1. Create an endpoint
php artisan n8n:endpoint:create invoice-paid \
--handler="App\N8n\InvoicePaidHandler" \
--queue=high
2. Write the handler
namespace App\N8n; use Oriceon\N8nBridge\DTOs\N8nPayload; use Oriceon\N8nBridge\Inbound\N8nInboundHandler; final class InvoicePaidHandler extends N8nInboundHandler { public function handle(N8nPayload $payload): void { $invoice = Invoice::findOrFail($payload->required('invoice_id')); $invoice->update([ 'status' => 'paid', 'paid_at' => $payload->getCarbon('paid_at'), ]); } public function rules(): array { return [ 'invoice_id' => 'required|integer', 'paid_at' => 'required|date', ]; } }
3. Configure in n8n
URL: POST https://myapp.com/n8n/in/invoice-paid
Header: X-N8N-Key: n8br_sk_...
Header: X-N8N-Execution-Id: {{ $execution.id }}
Security pipeline
Every request passes through 6 layers automatically:
POST /n8n/in/{slug}
โ
โผ 1. RateLimiter โ 429 if exceeded
โผ 2. ApiKeyVerifier โ 401 if key invalid
โผ 3. IpWhitelist โ 403 if IP not allowed
โผ 4. HmacVerifier โ 401 if signature mismatch
โผ 5. IdempotencyCheck โ 200 skip if already processed
โผ 6. PayloadStore โ persist delivery to DB
โผ ACK 202 + dispatch job to queue
See docs/inbound.md for HMAC, rate limits, IP whitelist, DLQ, and handler validation.
๐ค Outbound โ trigger n8n from Laravel
use Oriceon\N8nBridge\Facades\N8nBridge; // By workflow name N8nBridge::trigger('order-shipped', [ 'order_id' => $order->id, 'shipped_at' => now()->toIso8601String(), ]); // Sync (waits for HTTP response) N8nBridge::trigger($workflow, $payload, async: false);
Automatic from Eloquent models
use Oriceon\N8nBridge\Concerns\TriggersN8nOnEvents; class Invoice extends Model { use TriggersN8nOnEvents; protected array $n8nTriggers = [ 'created' => 'invoice-created', 'updated' => [ 'workflow' => 'invoice-status-changed', 'only_when' => ['status', 'paid_at'], ], ]; }
Webhook mode (test vs production URL)
Each workflow has a webhook_mode that controls which n8n URL is called:
use Oriceon\N8nBridge\Enums\WebhookMode; N8nWorkflow::find($id)->update([ 'webhook_mode' => WebhookMode::Auto, // default โ /webhook-test in dev, /webhook in prod // 'webhook_mode' => WebhookMode::Production, // always /webhook // 'webhook_mode' => WebhookMode::Test, // always /webhook-test ]);
With Auto, the URL is selected based on APP_ENV: production โ /webhook, anything else โ /webhook-test.
See docs/outbound.md for full details.
Outbound authentication
Protect your n8n webhooks with a per-workflow secret (AES-256 encrypted at rest):
use Oriceon\N8nBridge\Auth\WebhookAuthService; use Oriceon\N8nBridge\Enums\WebhookAuthType; N8nWorkflow::where('name', 'order-shipped')->update([ 'auth_type' => WebhookAuthType::HmacSha256, // or HeaderToken / Bearer 'auth_key' => WebhookAuthService::generateKey(), ]);
Auth headers are added automatically by both the outbound dispatcher and the queue worker.
Outbound rate limiting
Prevent flooding n8n with too many requests per minute:
N8N_BRIDGE_OUTBOUND_RATE_LIMIT=30 # global: 30 req/min (0 = unlimited)
Per-workflow override:
N8nWorkflow::where('name', 'bulk-sync') ->update(['rate_limit' => 10]); // 10 req/min for this workflow
When the limit is exceeded: async triggers are re-dispatched after the window resets; sync triggers fail immediately; queue worker releases the job back to pending with a delay.
See docs/outbound.md for auth types, rate limiting, n8n credential setup, and the HMAC verification Code node.
๐ง Tool System โ n8n calls Laravel
Define typed Laravel endpoints that n8n nodes call as an internal API.
php artisan make:n8n-tool GetInvoiceTool
final class GetInvoiceTool extends N8nToolHandler { public function get(N8nToolRequest $request): N8nToolResponse { return N8nToolResponse::item( Invoice::findOrFail($request->required('id')), fn($i) => ['id' => $i->id, 'total' => $i->total, 'status' => $i->status] ); } }
GET /n8n/tools/schema โ full OpenAPI 3 spec (import into n8n)
GET /n8n/tools/{name} โ handler->get()
GET /n8n/tools/{name}/{id} โ handler->getById()
POST /n8n/tools/{name} โ handler->post()
PATCH /n8n/tools/{name}/{id} โ handler->patch()
DELETE /n8n/tools/{name}/{id} โ handler->delete()
See docs/tools.md for filters, pagination, rate limiting, and schema definition.
๐ Queue System โ async jobs with live progress
use Oriceon\N8nBridge\Enums\QueueJobPriority;use Oriceon\N8nBridge\Queue\QueueDispatcher; $job = QueueDispatcher::workflow('invoice-processing') ->payload(['invoice_id' => $invoice->id]) ->priority(QueueJobPriority::High) ->maxAttempts(5) ->idempotent("invoice-{$invoice->id}") ->dispatch();
n8n sends checkpoint progress back:
POST /n8n/queue/progress/{jobUuid}
{ "node": "send_email", "status": "completed", "progress_percent": 75 }
POST /n8n/queue/progress/{jobUuid}
{ "node": "__done__", "status": "completed" }
Real-time updates via Laravel Echo:
window.Echo.private(`n8n-job.${jobId}`) .listen('N8nQueueJobProgressUpdatedEvent', (e) => { updateTimeline(e.checkpoint); if (e.is_terminal) console.log('Done:', e.job_status); });
See docs/queue.md for full queue documentation โ priorities, batches, DLQ, worker setup, Supervisor config, and estimated completion time.
๐ Circuit Breaker
Closed โโ(5 consecutive failures)โโโ Open
โ โ
โ (2ร consecutive success) (60s cooldown)โ
โโโโโ HalfOpen โโโโโโโโโโโโโโโโโโโโโโโโโ
๐ Statistics
$overview = N8nBridge::stats()->overview(); // ['total_deliveries' => 14823, 'success_rate' => 98.4, 'avg_duration_ms' => 142] $chart = N8nBridge::stats() ->forWorkflow($workflow) ->lastDays(30) ->toChartData();
See docs/statistics.md.
๐ Notifications
Alerts sent automatically on DLQ, circuit breaker open, and high error rate:
N8N_BRIDGE_NOTIFY_CHANNELS=slack,discord,mail N8N_BRIDGE_NOTIFY_SLACK_WEBHOOK=https://hooks.slack.com/services/xxx N8N_BRIDGE_NOTIFY_MAIL_TO=ops@myapp.com
๐๏ธ Database Tables
With the default n8n prefix:
| Table | Description |
|---|---|
n8n__credentials__lists |
Credential identities (one per n8n instance) |
n8n__api_keys__lists |
Rotatable API keys (many per credential) |
n8n__workflows__lists |
Workflows synced from n8n |
n8n__endpoints__lists |
Inbound endpoints |
n8n__deliveries__lists |
Full delivery log |
n8n__circuit_breakers__lists |
Per-workflow circuit breaker state |
n8n__stats__lists |
Daily aggregated statistics |
n8n__tools__lists |
Tool definitions |
n8n__event_subscriptions__lists |
Laravel event โ workflow mappings |
n8n__queue__jobs |
DB queue jobs |
n8n__queue__batches |
Batch grouping |
n8n__queue__failures |
Per-attempt failure history |
n8n__queue__checkpoints |
Live progress nodes from n8n |
๐ ๏ธ Artisan Commands
# Webhook & endpoint management php artisan n8n:credential:create "Production" --instance=default php artisan n8n:credential:rotate {id} --grace=300 php artisan n8n:endpoint:create invoice-paid --handler="App\N8n\Handler" php artisan n8n:endpoint:list php artisan n8n:endpoint:rotate invoice-paid --grace=300 # Workflow sync php artisan n8n:workflows:sync --instance=default php artisan n8n:workflow:auth-setup "Workflow name" --type=header_token # Testing php artisan n8n:test-inbound invoice-paid --payload='{"invoice_id":42}' php artisan n8n:test-inbound invoice-paid --dry-run # DLQ php artisan n8n:dlq:list php artisan n8n:dlq:retry php artisan n8n:dlq:retry {delivery-id} # Queue php artisan n8n:queue:work php artisan n8n:queue:work --queue=critical --sleep=1 php artisan n8n:queue:status php artisan n8n:queue:retry php artisan n8n:queue:cancel {uuid} php artisan n8n:queue:prune --days=30 # Stats & health php artisan n8n:stats --last=30 php artisan n8n:health --instance=default # Generators php artisan make:n8n-tool GetInvoiceTool
๐งช Tests
composer test # 846 tests (Unit + Feature + Architecture) composer analyse # PHPStan level 8
๐ Documentation
| Guide | Description |
|---|---|
| docs/credentials.md | Credential keys, rotation, IP whitelist |
| docs/inbound.md | Inbound handler, pipeline, HMAC, idempotency |
| docs/outbound.md | Outbound triggers, Eloquent trait, event subscriptions, outbound auth, webhook mode |
| docs/tools.md | Tool handlers, routing, OpenAPI schema |
| docs/queue.md | DB queue, priorities, batches, DLQ, live progress |
| docs/circuit-breaker.md | State machine, configuration |
| docs/statistics.md | Stats aggregation, chart data |
| docs/notifications.md | Alert channels, thresholds |
| docs/security.md | Key hashing, HMAC, timing attacks |
| docs/multitenancy.md | Multi-tenant setup |
| docs/n8n-setup.md | Configuring n8n credentials and nodes |
| docs/testing.md | Testing handlers, tools, and queue jobs |
| docs/upgrade.md | Upgrade guide |
๐ License
MIT โ Copyright ยฉ 2026 Valentin Ivaศcu
