Opbox

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/:id and DELETE /api/workflows/:id require admin role and return standardized error envelopes.
  • Automation update payloads are validated before writes.

Endpoints

MethodEndpointDescription
GET/api/workflowsList all automations
POST/api/workflowsCreate an automation
GET/api/workflows/:idGet automation details
PATCH/api/workflows/:idUpdate an automation
DELETE/api/workflows/:idDelete an automation
POST/api/workflows/:id/executeExecute an automation
GET/api/workflows/:id/runsList automation runs (paginated)
GET/api/workflows/:id/runs/:runIdGet run detail with full execution state and per-step JSON
GET/api/workflows/:id/runs/exportExport single or all runs as downloadable JSON
POST/api/workflows/runs/:runId/resumeResume a paused workflow run (approval, delay, webhook)
GET/api/workflows/callback/:tokenPublic approval confirmation page (read-only, no side effects)
POST/api/workflows/callback/:tokenExecute approval/rejection decision (rate-limited, 7-day expiry)
GET/api/workflows/statsGet automation statistics
POST/api/workflows/send-emailSend 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

FieldTypeRequiredDescription
namestringYesAutomation name
statusstringNoDRAFT, ACTIVE, PAUSED, or ARCHIVED
triggerobjectNoTrigger type and config (form_submission, webhook, schedule, event)
stepsarrayNoArray of step definitions
formIdstringNoLink to a form for trigger

Step Types

Automations support various step types that execute sequentially:

TypeDescription
emailSend an email (to, subject, body, cc, bcc, attachments)
http_requestMake an HTTP request to an external service
conditionConditional branching based on data
delayWait for a specified duration
codeExecute sandboxed JavaScript
aiAI-powered text generation
slackSend a Slack message
table_operationsCreate, update, or query table rows
loopIterate over a collection
generate_documentGenerate documents via the Document Engine (workspace-scoped template pack, PDF/DOCX output)
send_documentSend a generated document to recipients
evidence_snapshotCapture compliance evidence from TABLE_ROWS, AUDIT_LOGS, SECURITY_EVENTS, or ORG_MEMBERS
create_matterCreate a matter from a board template with title, tags, and priority
run_workflowExecute a child workflow (supports wait-for-completion chaining)
notificationSend an in-app notification to the workflow owner or specified users
approvalPause workflow and wait for human approval (resumes via callback)
send_formSend 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

StatusDescription
RUNNINGCurrently executing steps
COMPLETEDAll steps finished successfully
FAILEDTerminated with an error
PAUSEDWaiting for approval, delay expiry, or webhook callback
CANCELLEDUser-cancelled
WAITING_FOR_CHILDParent 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": {}
}
  • variables holds workflow-scoped context variables.
  • stepOutputs stores per-node JSON output (full, not truncated).
  • logs[].output is truncated to 500 chars in logs.
  • retryCount tracks 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

FieldTypeRequiredDescription
tostring | string[]YesRecipient email address(es)
subjectstringYesEmail subject line
bodystringYesPlain text body
htmlstringNoHTML body (takes priority over plain text in email clients)
ccstring | string[]NoCC recipients
bccstring | string[]NoBCC recipients
attachmentsarrayNoFile 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 TypeCategoryDescriptionFilter
MATTER_STEP_COMPLETEDMatterA matter step was completedfilterMatterTemplateId
MATTER_STEP_REJECTEDMatterA matter step was rejectedfilterMatterTemplateId
FORM_APPROVEDFormA form submission was approvedfilterFormId
FORM_REJECTEDFormA form submission was rejectedfilterFormId
ROW_ADDEDTableA new row was created in a tablefilterTableId
RECORD_UPDATEDTableA table row was updatedfilterTableId

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.