Events
Automation — Events
Real-time run updates come over Socket.IO, namespace /workflow/events.
Connect with the admin JWT in the handshake — auth.token, query.token, or the
Authorization: Bearer header. Pass the tenant database via the
x-tenant-database header or query.tenantDb.
On connect you join admin:{id} and tenant:{db}, and the server emits
connected. A missing/invalid token emits error with code AUTH_MISSING or
AUTH_INVALID, then disconnects. (Connection-state recovery is on — a
reconnecting client gets connected with { recovered: true }.)
Server → client
Events broadcast to your tenant:{db} room; the whole event object is the payload
(socket.on(type, event)):
| Event | Fires when | Key fields |
|---|---|---|
workflow:execution.completed | A run finishes successfully | workflowId, objectSlug, recordSlug, recordId, durationMs, timestamp |
workflow:execution.failed | A run errors | same + error |
workflow:execution.skipped | Trigger/filter didn't match | same as completed |
workflow:stats.updated | A workflow's counters change | workflowId, executionCount, lastExecutedAt |
workflow:execution.startedexists in the gateway API but the current engine emits only the three terminal events above — a run's lifecycle is queued → (completed | failed | skipped).
The gateway is broadcast-only: there are no client→server message handlers beyond the auth handshake. Subscribe and render; you don't emit run commands over the socket (use the REST API for that).
Internal domain events
The processor emits these on the in-process EventEmitter (server-side only, not
over the socket). WorkflowExecutionListener forwards the execution ones to the
WebSocket gateway:
| Event | Effect |
|---|---|
workflow.execution.completed / .failed / .skipped | Persisted as a workflow_executions row; broadcast to the gateway |
workflow.approval.resolved | Emitted by the approval service when a gate is approved/rejected |
The engine also consumes the CRM's data.created / data.updated events (to
know when to fire data-triggered workflows) and subscribes to the messaging
module's Redis pub/sub channels (for message-triggered workflows).