Workflow Alerts
Alert rules tell you when a workflow's run ends a certain way, on the channels you choose; the alert history keeps every alert they sent with each channel's outcome. Rules and alerts are always your own. See Workflow Alerts for how rules behave.
All endpoints require authentication via the X-API-Key header and the scope shown.
Alert Rule Object
{
"_id": "Kq3xT9mWzP2",
"name": "Invoice sync failures",
"workflowId": "wf_abc123",
"isEnabled": true,
"condition": "execution_failed",
"conditionConfig": {},
"channels": [
{ "type": "in_app", "config": {} },
{ "type": "email", "config": { "emailAddresses": ["ops@example.com"] } }
],
"throttle": { "enabled": true, "intervalMinutes": 60 },
"userId": "user_456",
"triggerCount": 4,
"lastTriggeredAt": "2026-10-08T12:00:00Z",
"createdAt": "2026-10-01T09:00:00Z",
"updatedAt": "2026-10-01T09:00:00Z"
}
| Field | Description |
|---|---|
workflowId | The workflow; omitted = all of your workflows |
condition | execution_failed (a run failed or errored), execution_timeout (a run timed out), execution_completed (a run ran to its end: completed, completed_with_gaps or partial_success), duration_exceeded, node_failed, consecutive_failures, dlq_threshold |
conditionConfig | durationThresholdMs (duration_exceeded), nodeTypes (node_failed; empty = any node), failureCount (consecutive_failures, default 3: failures since the last run that ran to its end), dlqCountThreshold (dlq_threshold, default 1: the workflow's unresolved Dead Letter Queue entries) |
channels | in_app (your bell), email (emailAddresses; none = your address), slack (slackWebhookUrl, slackChannel), webhook (webhookUrl, webhookHeaders: only X-Custom-*, X-Webhook-*, X-Strongly-*, Content-Type, Accept are sent) |
throttle | At most one alert per intervalMinutes when enabled |
A rule fires when a run's end is announced (once per run, after the workflow-controller finalizes it) and only while you may use the workflow. Stopped and cancelled runs fire nothing.
Alert Object
{
"_id": "Zt8pQ1",
"ruleId": "Kq3xT9mWzP2",
"ruleName": "Invoice sync failures",
"workflowId": "wf_abc123",
"workflowName": "Invoice sync",
"executionId": "exec_xyz789",
"condition": "execution_failed",
"message": "Workflow \"Invoice sync\" execution failed",
"details": { "status": "failed", "error": "node Parse failed", "durationMs": 1200 },
"channelsSent": ["in_app"],
"channelOutcomes": {
"in_app": { "sent": ["user_456"] },
"email": { "error": "Not sent: the platform has no mail server configured (MAIL_URL is not set)" }
},
"triggeredAt": "2026-10-08T12:00:00Z"
}
GET /api/v1/workflows/alert-rules
Your alert rules, newest first. With workflowId, the rules that apply to that workflow (its own and your rules for all your workflows). It pages with limit and cursor (Pagination).
Scope: workflows:read
| Query | Description |
|---|---|
workflowId | Only the rules that apply to this workflow |
Response 200 OK: {"data": [<alert rule>, ...]}
POST /api/v1/workflows/alert-rules
Create an alert rule. Saving refuses an email address that is not one, and a Slack or webhook URL that points inside the platform's network.
Scope: workflows:write
{
"name": "Invoice sync failures",
"workflowId": "wf_abc123",
"condition": "execution_failed",
"channels": [{ "type": "in_app", "config": {} }],
"throttle": { "enabled": false, "intervalMinutes": 0 }
}
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Rule name |
condition | string | Yes | See the rule object |
channels | array | Yes | See the rule object |
workflowId | string | No | A workflow you may use (omit for all your workflows) |
conditionConfig | object | No | The condition's settings |
throttle | object | No | {enabled, intervalMinutes} (default off) |
isEnabled | boolean | No | Default true |
description | string | No | What the rule is for |
Response 201 Created: the new rule.
GET /api/v1/workflows/alert-rules/:id
One of your alert rules.
Scope: workflows:read
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Alert rule id |
Response 200 OK: the rule, as the list shows it.
PATCH /api/v1/workflows/alert-rules/:id
Update one of your rules: any of name, description, workflowId, isEnabled, condition, conditionConfig, channels, throttle.
Scope: workflows:write
Response 200 OK: the updated rule.
DELETE /api/v1/workflows/alert-rules/:id
Delete one of your rules. Its alerts stay in the history.
Scope: workflows:write
Response 204 No Content
GET /api/v1/workflows/alerts
The alerts your rules sent, newest first.
Scope: workflows:read
| Query | Description |
|---|---|
workflowId | Only this workflow's alerts |
ruleId | Only this rule's alerts |
limit | 1 to 200 (default 50) |
Response 200 OK: {"data": [<alert>, ...]}