Workflows & Automation

Define automated workflows with trigger conditions, manage workflow states, create automation rules, schedule time-based triggers, and orchestrate campaigns.

Workflows

List Workflows

GET /v1/workflows

The organization is taken from your access token.

Query Parameters

ParameterTypeDescription
statusstringFilter: active, draft, archived
trigger_typestringFilter: manual, event, schedule, webhook, condition
searchstringFilter by name text
limitintegerMax results (1–100)
offsetintegerPagination offset

Response

{
  "data": {
    "workflows": [
      {
        "id": "...",
        "name": "New Member Onboarding",
        "description": "Triggered when a new member joins the organization",
        "trigger_type": "event",
        "status": "active",
        "created_at": "2026-03-01T10:00:00Z",
        "updated_at": "2026-03-15T14:30:00Z"
      }
    ],
    "pagination": {
      "total": 8,
      "limit": 20,
      "offset": 0
    }
  }
}

Create Workflow

POST /v1/workflows

A workflow is an approval flow whose steps are state transitions, each optionally gated by a required role or group.

Request Body

{
  "name": "Document Approval",
  "description": "Two-step review before publish",
  "entity_type_id": "...",
  "status": "active",
  "trigger_type": "manual",
  "steps": [
    {
      "from_state_id": "...",
      "to_state_id": "...",
      "required_role": "reviewer"
    }
  ]
}

Do not send id, org_id, created_at, or updated_at; these are assigned by the server, and the organization is taken from your access token.

Response

On success the complete created workflow (including its step graph) is returned.

{
  "success": true,
  "data": {
    "id": "...",
    "name": "Document Approval",
    "description": "Two-step review before publish",
    "entity_type_id": "...",
    "is_active": true,
    "status": "active",
    "trigger_type": "manual",
    "step_count": 1,
    "run_count": 0,
    "last_run_at": null,
    "steps": [
      {
        "id": "...",
        "workflow_id": "...",
        "from_state_id": "...",
        "to_state_id": "...",
        "required_role": "reviewer",
        "required_group_id": null,
        "sort_order": 1
      }
    ],
    "created_at": "2026-04-10T08:00:00Z",
    "updated_at": "2026-04-10T08:00:00Z"
  }
}

Response Codes

StatusMeaning
201 CreatedWorkflow created; the full record is returned
400 Bad RequestRequest body validation failure, or an invalid/duplicate step, status, trigger type, or entity type reference
401 UnauthorizedMissing or invalid access token
403 ForbiddenCaller lacks permission to create workflows
500 Internal Server ErrorUnexpected server error

Get Workflow

GET /v1/workflows/:id

Update Workflow

PUT /v1/workflows/:id

Update workflow definition, trigger configuration, or status.

Delete Workflow

DELETE /v1/workflows/:id

Trigger Types

TypeDescription
manualTriggered by a user action or API call
eventTriggered by a platform event (e.g., entity created, member joined)
scheduleTriggered on a cron schedule
webhookTriggered by an incoming webhook request
conditionTriggered when a data condition is met

Workflow Status

StatusDescription
draftUnder construction, will not execute
activeLive and responding to triggers
archivedDisabled, retained for reference

Workflow States

List Workflow States

GET /v1/workflows/states

Query Parameters

ParameterTypeDescription
project_idUUIDScope states to a project (optional)
limitintegerMax results (1–100)
offsetintegerPagination offset

Create Workflow State

POST /v1/workflows/states

Request Body

{
  "name": "Awaiting Approval",
  "description": "Pending reviewer sign-off",
  "color": "#FFA500",
  "position": 3,
  "is_initial": false,
  "is_terminal": false
}

Do not send id, org_id, created_at, or updated_at; these are assigned by the server, and the organization is taken from your access token. A state cannot be both initial and terminal.

Response

On success the complete created workflow state is returned.

{
  "success": true,
  "data": {
    "id": "...",
    "name": "Awaiting Approval",
    "category_id": null,
    "color": "#FFA500",
    "icon": null,
    "is_initial": false,
    "is_final": false,
    "sort_order": 3,
    "is_active": true,
    "created_at": "2026-04-10T08:00:00Z",
    "updated_at": "2026-04-10T08:00:00Z"
  }
}

Response Codes

StatusMeaning
201 CreatedWorkflow state created; the full record is returned
400 Bad RequestRequest body validation failure (e.g. missing name, invalid color, or a state marked both initial and terminal)
401 UnauthorizedMissing or invalid access token
403 ForbiddenCaller lacks permission to manage workflow states
500 Internal Server ErrorUnexpected server error

Workflow Steps

A workflow's steps are created with the workflow (see Create Workflow above). Individual steps can be edited or removed in place.

Update Workflow Step

PUT /v1/workflows/:workflowId/steps/:stepId

Delete Workflow Step

DELETE /v1/workflows/:workflowId/steps/:stepId

Automation Rules

List Automation Rules

GET /v1/automation-rules

Query Parameters

ParameterTypeDescription
is_enabledbooleanFilter by enabled state
trigger_typestringFilter by trigger type
action_typestringFilter by action type
pageintegerPage number (1-based)
page_sizeintegerResults per page (1–200)

Create Automation Rule

POST /v1/automation-rules

An automation rule pairs a trigger with an action.

Request Body

{
  "name": "Notify on critical task",
  "trigger_type": "event",
  "trigger_config": {
    "event": "task.created"
  },
  "action_type": "webhook",
  "action_config": {
    "url": "https://example.com/hook",
    "method": "POST"
  },
  "is_enabled": true
}

Do not send id, org_id, created_at, or updated_at; these are assigned by the server, and the organization is taken from your access token.

Response

On success the complete created automation rule is returned.

{
  "success": true,
  "data": {
    "id": "...",
    "name": "Notify on critical task",
    "description": null,
    "trigger_type": "event",
    "trigger_config": { "event": "task.created" },
    "action_type": "webhook",
    "action_config": { "url": "https://example.com/hook", "method": "POST" },
    "is_enabled": true,
    "last_run_at": null,
    "run_count": 0,
    "created_by": "...",
    "created_at": "2026-04-10T08:00:00Z",
    "updated_at": "2026-04-10T08:00:00Z"
  }
}

Response Codes

StatusMeaning
201 CreatedAutomation rule created; the full record is returned
400 Bad RequestRequest body validation failure (e.g. missing name/trigger/action, non-HTTPS webhook URL, or invalid cron expression)
401 UnauthorizedMissing or invalid access token
403 ForbiddenCaller lacks permission to manage automation rules
500 Internal Server ErrorUnexpected server error

Get Automation Rule

GET /v1/automation-rules/:ruleId

Update Automation Rule

PUT /v1/automation-rules/:ruleId

Delete Automation Rule

DELETE /v1/automation-rules/:ruleId

List Rule Executions

GET /v1/automation-rules/:ruleId/executions

Execute Rule Manually

POST /v1/automation-rules/:ruleId/execute

Time Triggers

List Time Triggers

GET /v1/time-triggers

Query Parameters

ParameterTypeDescription
is_enabledbooleanFilter by enabled state
action_typestringFilter by action type
pageintegerPage number (1-based)
page_sizeintegerResults per page (1–200)

Create Time Trigger

POST /v1/time-triggers

Fires a configured action on a cron schedule. cron_expression is a 5-field cron.

Request Body

{
  "name": "Weekly status report",
  "cron_expression": "0 9 * * 1",
  "action_type": "webhook",
  "action_config": {
    "url": "https://example.com/hook",
    "method": "POST"
  },
  "is_enabled": true
}

Do not send id, org_id, created_at, or updated_at; these are assigned by the server, and the organization is taken from your access token.

Response

On success the complete created time trigger is returned.

{
  "success": true,
  "data": {
    "id": "...",
    "name": "Weekly status report",
    "cron_expression": "0 9 * * 1",
    "action_type": "webhook",
    "action_config": { "url": "https://example.com/hook", "method": "POST" },
    "is_enabled": true,
    "next_run_at": null,
    "last_run_at": null,
    "created_by": "...",
    "created_at": "2026-04-10T08:00:00Z",
    "updated_at": "2026-04-10T08:00:00Z"
  }
}

Response Codes

StatusMeaning
201 CreatedTime trigger created; the full record is returned
400 Bad RequestRequest body validation failure (e.g. missing name/action, or an invalid cron expression)
401 UnauthorizedMissing or invalid access token
403 ForbiddenCaller lacks permission to manage automations
500 Internal Server ErrorUnexpected server error

Update Time Trigger

PUT /v1/time-triggers/:triggerId

Delete Time Trigger

DELETE /v1/time-triggers/:triggerId

List Trigger Logs

GET /v1/time-triggers/:triggerId/logs

Campaigns

List Campaigns

GET /v1/campaigns

Query Parameters

ParameterTypeDescription
campaign_typestringFilter: drip, sequence, one_shot
is_activebooleanFilter by active state
searchstringFilter by name text
limitintegerMax results (1–100)
offsetintegerPagination offset

Create Campaign

POST /v1/campaigns

Request Body

{
  "name": "Q2 Launch Campaign",
  "description": "Coordinated launch activities for Q2 release",
  "campaign_type": "sequence",
  "is_active": false,
  "starts_at": "2026-04-01T00:00:00Z",
  "ends_at": "2026-06-30T23:59:59Z"
}

Do not send id, org_id, status, created_at, or updated_at; these are assigned by the server (a new campaign always starts in draft status), and the organization is taken from your access token.

Response

On success the complete created campaign is returned.

{
  "success": true,
  "data": {
    "id": "...",
    "name": "Q2 Launch Campaign",
    "description": "Coordinated launch activities for Q2 release",
    "campaign_type": "sequence",
    "status": "draft",
    "config": {},
    "start_date": "2026-04-01T00:00:00Z",
    "end_date": "2026-06-30T23:59:59Z",
    "created_by": "...",
    "created_at": "2026-04-10T08:00:00Z",
    "updated_at": "2026-04-10T08:00:00Z"
  }
}

Response Codes

StatusMeaning
201 CreatedCampaign created in draft status; the full record is returned
400 Bad RequestRequest body validation failure (e.g. missing name/type, or an end date that is not after the start date)
401 UnauthorizedMissing or invalid access token
500 Internal Server ErrorUnexpected server error

Get Campaign

GET /v1/campaigns/:id

Update Campaign

PUT /v1/campaigns/:id

Delete Campaign

DELETE /v1/campaigns/:id

Campaign Steps

List Campaign Steps

GET /v1/campaigns/:id/steps

Create Campaign Step

POST /v1/campaigns/:id/steps

Add an ordered step to a campaign. position is a 0-based index; only name, step_type, and position are required. Do not send id, org_id, created_at, or updated_at; these are assigned by the server, and the organization and campaign are taken from your access token and the path.

Request Body
{
  "name": "Welcome email",
  "step_type": "email",
  "position": 0,
  "config": { ... },
  "delay_seconds": 0,
  "template_id": "...",
  "metadata": { ... }
}
Response

On success the complete created step is returned.

{
  "success": true,
  "data": {
    "id": "...",
    "campaign_id": "...",
    "step_number": 1,
    "name": "Welcome email",
    "action_type": "email",
    "action_config": { ... },
    "delay_minutes": 0,
    "conditions": { ... },
    "created_by": "...",
    "created_at": "2026-04-10T08:00:00Z",
    "updated_at": "2026-04-10T08:00:00Z"
  }
}
Response Codes
StatusMeaning
201 CreatedStep created; the full record is returned
400 Bad RequestInvalid campaign ID or request body validation failure
401 UnauthorizedMissing or invalid access token
404 Not FoundThe campaign does not exist in your organization
500 Internal Server ErrorUnexpected server error

Update Campaign Step

PUT /v1/campaigns/:id/steps/:stepId

Delete Campaign Step

DELETE /v1/campaigns/:id/steps/:stepId

Campaign Enrollments

List Enrollments

GET /v1/campaigns/:id/enrollments

Create Enrollment

POST /v1/campaigns/:id/enrollments

Enroll a target into a campaign. Both target_user_id and the campaign (from the path) are required. Do not send id, org_id, status, enrolled_at, or created_at; these are assigned by the server (a new enrollment starts active at step 0), and the organization is taken from your access token. The campaign must be in active status to accept enrollments.

Request Body
{
  "target_user_id": "...",
  "trigger_data": { ... },
  "metadata": { ... }
}
Response

On success the complete created enrollment is returned.

{
  "success": true,
  "data": {
    "id": "...",
    "campaign_id": "...",
    "entity_id": "...",
    "entity_type": "user",
    "current_step": 0,
    "status": "active",
    "enrolled_at": "2026-04-10T08:00:00Z",
    "metadata": { ... },
    "created_at": "2026-04-10T08:00:00Z"
  }
}
Response Codes
StatusMeaning
201 CreatedEnrollment created; the full record is returned
400 Bad RequestInvalid campaign ID or request body validation failure
401 UnauthorizedMissing or invalid access token
403 ForbiddenCaller lacks permission to enroll into campaigns
404 Not FoundThe campaign does not exist in your organization
409 ConflictThe campaign is not active, or the target is already actively enrolled
500 Internal Server ErrorUnexpected server error