Automations API
Create and manage automations with multi-step pipelines and per-step audit logs. Automations can be triggered by form submissions, webhooks, schedules, system events (including pipeline syncs), or manual execution. Supports pause/resume, workflow chaining, and matter integration.
Route Conventions
PATCH /api/workflows/:idandDELETE /api/workflows/:idrequire admin role and return standardized error envelopes.- Automation update payloads are validated before writes.
Endpoints
| Method | Endpoint | Description |
|---|---|---|
GET | /api/workflows | List all automations |
POST | /api/workflows | Create an automation |
GET | /api/workflows/:id | Get automation details |
PATCH | /api/workflows/:id | Update an automation |
DELETE | /api/workflows/:id | Delete an automation |
POST | /api/workflows/:id/execute | Execute an automation |
GET | /api/workflows/:id/runs | List automation runs (paginated) |
GET | /api/workflows/:id/runs/:runId | Get run detail with full execution state and per-step JSON |
GET | /api/workflows/:id/runs/export | Export single or all runs as downloadable JSON |
POST | /api/workflows/runs/:runId/resume | Resume a paused workflow run (approval, delay, webhook) |
GET | /api/workflows/callback/:token | Public approval confirmation page (read-only, no side effects) |
POST | /api/workflows/callback/:token | Execute approval/rejection decision (rate-limited, 7-day expiry) |
GET | /api/workflows/stats | Get automation statistics |
POST | /api/workflows/send-email | Send a transactional email |
List Automations
Returns all automations for your workspace, including steps and run counts.
GET /api/workflows
Response
[
{
"id": "cm...",
"name": "New Submission Notification",
"status": "ACTIVE",
"trigger": { "type": "form_submission", "formId": "cm..." },
"steps": [
{ "id": "cm...", "name": "Send Email", "type": "email", "order": 0 }
],
"_count": { "runs": 47 },
"createdAt": "2026-01-10T09:00:00.000Z"
}
]
Create an Automation
Creates a new automation with trigger configuration and step definitions. Requires ADMIN or OWNER role.
POST /api/workflows
Content-Type: application/json
{
"name": "Welcome Email on Signup",
"description": "Sends welcome email when a form is submitted",
"formId": "cm...",
"status": "ACTIVE",
"trigger": {
"type": "form_submission",
"config": { "formId": "cm..." }
},
"steps": [
{
"name": "Send Welcome Email",
"type": "email",
"config": {
"to": "{{submission.email}}",
"subject": "Welcome!",
"body": "Thank you for signing up."
},
"order": 0
}
]
}
Body Parameters
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Automation name |
status | string | No | DRAFT, ACTIVE, PAUSED, or ARCHIVED |
trigger | object | No | Trigger type and config (form_submission, webhook, schedule, event) |
steps | array | No | Array of step definitions |
formId | string | No | Link to a form for trigger |
Step Types
Automations support various step types that execute sequentially:
| Type | Description |
|---|---|
email | Send an email (to, subject, body, cc, bcc, attachments) |
http_request | Make an HTTP request to an external service |
condition | Conditional branching based on data |
delay | Wait for a specified duration |
code | Execute sandboxed JavaScript |
ai | AI-powered text generation |
slack | Send a Slack message |
table_operations | Create, update, or query table rows |
loop | Iterate over a collection |
generate_document | Generate documents via the Document Engine (workspace-scoped template pack, PDF/DOCX output) |
send_document | Send a generated document to recipients |
evidence_snapshot | Capture compliance evidence from TABLE_ROWS, AUDIT_LOGS, SECURITY_EVENTS, or ORG_MEMBERS |
create_matter | Create a matter from a board template with title, tags, and priority |
run_workflow | Execute a child workflow (supports wait-for-completion chaining) |
notification | Send an in-app notification to the workflow owner or specified users |
approval | Pause workflow and wait for human approval (resumes via callback) |
send_form | Send a form to recipients for completion |
Execute an Automation
Manually triggers an automation run. The execution happens asynchronously.
POST /api/workflows/:id/execute
Response
{
"runId": "cm...",
"status": "RUNNING",
"startedAt": "2026-02-11T10:30:00.000Z"
}
List Automation Runs
Returns paginated execution history for an automation.
GET /api/workflows/:id/runs?page=1&pageSize=20
Response
{
"runs": [
{
"id": "cm...",
"status": "COMPLETED",
"startedAt": "2026-02-11T10:30:00.000Z",
"completedAt": "2026-02-11T10:30:02.000Z",
"error": null
}
],
"pagination": { "page": 1, "pageSize": 20, "total": 47, "totalPages": 3 }
}
Get Run Detail
Returns full execution state for a single run, including per-step JSON input/output, variables, completed nodes, and child runs.
GET /api/workflows/:id/runs/:runId
Response
{
"run": {
"id": "cm...",
"status": "COMPLETED",
"startedAt": "2026-02-11T10:30:00.000Z",
"completedAt": "2026-02-11T10:30:02.000Z",
"error": null,
"logs": [
{
"stepId": "cm...",
"stepType": "evidence_snapshot",
"stepName": "Capture security events",
"status": "success",
"durationMs": 340,
"timestamp": "2026-02-11T10:30:00.500Z",
"output": "{ \"rowCount\": 42, \"source\": \"SECURITY_EVENTS\" }"
}
],
"state": {
"variables": { "triggerType": "scheduled" },
"stepOutputs": { "node-1": { "rowCount": 42 } },
"completedNodeIds": ["node-1", "node-2"],
"pendingNodeIds": []
},
"workflow": { "name": "Daily Security Monitor" },
"childRuns": []
}
}
Export Runs
Downloads execution data as a JSON file. Export a single run or all runs (up to 500).
GET /api/workflows/:id/runs/export
GET /api/workflows/:id/runs/export?runId=cm...
Response
Returns a downloadable JSON file with Content-Disposition: attachment header.
{
"workflow": { "id": "cm...", "name": "Daily Security Monitor" },
"exportedAt": "2026-03-01T12:00:00.000Z",
"runCount": 47,
"runs": [
{
"id": "cm...",
"status": "COMPLETED",
"startedAt": "...",
"completedAt": "...",
"logs": [],
"state": { "variables": {}, "stepOutputs": {} }
}
]
}
Resume a Paused Run
Resumes a workflow run that is paused (waiting for approval, delay, or webhook callback). Uses atomic status transition to prevent double-resume.
POST /api/workflows/runs/:runId/resume
Content-Type: application/json
{
"decision": "approved",
"data": { "notes": "LGTM" }
}
decision accepts approved or rejected for approval steps. data is optional context data.
Run Statuses
| Status | Description |
|---|---|
RUNNING | Currently executing steps |
COMPLETED | All steps finished successfully |
FAILED | Terminated with an error |
PAUSED | Waiting for approval, delay expiry, or webhook callback |
CANCELLED | User-cancelled |
WAITING_FOR_CHILD | Parent workflow waiting for a child workflow to complete |
Durable State Machine
Automations use a durable execution engine with persistent state. Execution state is saved after each step, enabling pause/resume, approval workflows, and long-running delayed operations.
Execution State
{
"variables": {},
"stepOutputs": {
"node-abc": { "rows": [] },
"node-def": { "status": "sent" }
},
"completedNodeIds": ["node-abc", "node-def"],
"pendingNodeIds": ["node-ghi"],
"logs": [
{
"stepId": "cm...",
"stepType": "evidence_snapshot",
"stepName": "Capture events",
"status": "success",
"durationMs": 240,
"timestamp": "2026-03-01T06:00:00.500Z",
"output": "{ ... }"
}
],
"retryCount": {}
}
variablesholds workflow-scoped context variables.stepOutputsstores per-node JSON output (full, not truncated).logs[].outputis truncated to 500 chars in logs.retryCounttracks per-node retry attempts.
Pipeline Sync Integration
When a pipeline sync completes (e.g. GitHub Dependabot alerts synced to the Vulnerability Register), automation triggers fire automatically for each affected table. Automations with ROW_ADDED or RECORD_UPDATED triggers and a matching filterTableId will fire automatically. One event fires per table (not per row) to avoid flooding on large syncs.
Automation Statistics
Returns aggregate counts of automations and runs.
GET /api/workflows/stats
Response
{
"workflows": { "total": 12, "active": 5, "draft": 4, "paused": 2, "archived": 1 },
"runs": { "total": 340, "running": 2, "completed": 310, "failed": 25, "cancelled": 3 }
}
Send Email
Send a transactional email via your configured email provider. Requires a site email provider to be configured in Integrations.
POST /api/workflows/send-email
Content-Type: application/json
{
"to": "client@example.com",
"subject": "Your document is ready",
"body": "Please review the attached document.",
"html": "<p>Please review the attached <strong>document</strong>.</p>",
"cc": ["manager@example.com"],
"attachments": [
{
"filename": "report.pdf",
"content": "base64-encoded-content...",
"contentType": "application/pdf"
}
]
}
Body Parameters
| Field | Type | Required | Description |
|---|---|---|---|
to | string | string[] | Yes | Recipient email address(es) |
subject | string | Yes | Email subject line |
body | string | Yes | Plain text body |
html | string | No | HTML body (takes priority over plain text in email clients) |
cc | string | string[] | No | CC recipients |
bcc | string | string[] | No | BCC recipients |
attachments | array | No | File attachments with filename, content (base64), and contentType |
Response
{
"messageId": "msg_abc123",
"provider": "email-provider",
"accepted": ["client@example.com"],
"rejected": []
}
Event Triggers
Automations can be triggered automatically by system events. When an event occurs (e.g. a matter step is completed or a table row is created), all active automations with a matching event trigger are executed asynchronously. Event data is passed as context variables to downstream automation steps.
Trigger Configuration
{
"trigger": {
"type": "event",
"config": {
"triggerType": "MATTER_STEP_COMPLETED",
"filterMatterTemplateId": "cm..."
}
}
}
Event Types
| Event Type | Category | Description | Filter |
|---|---|---|---|
MATTER_STEP_COMPLETED | Matter | A matter step was completed | filterMatterTemplateId |
MATTER_STEP_REJECTED | Matter | A matter step was rejected | filterMatterTemplateId |
FORM_APPROVED | Form | A form submission was approved | filterFormId |
FORM_REJECTED | Form | A form submission was rejected | filterFormId |
ROW_ADDED | Table | A new row was created in a table | filterTableId |
RECORD_UPDATED | Table | A table row was updated | filterTableId |
Context Variables
When an event trigger fires, the following context is passed to workflow steps:
// Matter events
{
"matterId": "cm...",
"stepId": "cm...",
"stepName": "KYC Review",
"stepType": "APPROVAL",
"templateId": "cm..."
}
// Form events
{
"submissionId": "cm...",
"formId": "cm...",
"formTitle": "Client Intake"
}
// Table events
{
"rowId": "cm...",
"tableId": "cm...",
"tableName": "Companies"
}
Event triggers are dispatched asynchronously. If the matching automation is not ACTIVE, or if the event does not match the configured filter, the trigger is silently skipped.