> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Flows

## Worked sequences

The endpoint list below documents each operation's parameters, but three
calls define how a flow behaves once the graph is saved: the trigger
configuration you set at creation, a run with a real action payload, and
activation (publish + enrol a subject). These sequences show each one with
the body you send and the body the API returns.

### Sequence 1 — configure the trigger

Set the trigger when you create the flow. `trigger_type` is one of `manual`
(run on demand), `webhook`, `schedule`, `event`, or `workflow`. A schedule
trigger also needs a 5-field `cron_expr` and optionally an IANA `cron_tz`
(UTC otherwise) — create a schedule flow without a parseable expression and
the API rejects it with a 422.

```bash theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/flows/" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Weekly re-engagement",
    "description": "Message opted-in customers who went quiet this week.",
    "definition": {
      "nodes": [
        { "id": "trigger_1", "type": "trigger" },
        { "id": "sms_1", "type": "send_sms", "config": { "message": "Still interested? Reply YES." } }
      ],
      "edges": [
        { "source": "trigger_1", "target": "sms_1" }
      ]
    },
    "trigger_type": "schedule",
    "cron_expr": "0 9 * * 1",
    "cron_tz": "America/New_York"
  }'
```

```json 201 theme={null}
{
  "data": {
    "id": "flow_9c3f1a8e",
    "name": "Weekly re-engagement",
    "status": "draft",
    "version": 1,
    "trigger_type": "schedule",
    "cron_expr": "0 9 * * 1",
    "cron_tz": "America/New_York"
  },
  "meta": {
    "request_id": "req_flow_create",
    "timestamp": "2026-08-27T12:00:00Z"
  }
}
```

### Sequence 2 — run the flow with a real action payload

Trigger one run and pass the context your nodes read. `trigger_data` is
merged into the execution's trigger context, so a node template like
`{{order_total}}` resolves at run time. The run is accepted asynchronously
(202); poll the executions log when you need the outcome.

```bash theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/flows/flow_9c3f1a8e/execute" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "trigger_data": {
      "contact_id": "ctt_4d1e9a72",
      "order_total": "129.00",
      "currency": "USD"
    }
  }'
```

```json 202 theme={null}
{
  "data": {
    "id": "exec_7b2d1aa4",
    "flow_id": "flow_9c3f1a8e",
    "status": "running"
  },
  "meta": {
    "request_id": "req_flow_execute",
    "timestamp": "2026-08-27T12:01:00Z"
  }
}
```

<Note>
  When the fan-out you want is a contact or a list rather than raw context,
  use `POST /api/v1/flows/{id}/start` below — it merges your `context` the
  same way but also records which subject was enrolled.
</Note>

### Sequence 3 — publish, then enrol a subject

Nothing executes until the flow is published. Publish freezes the current
definition as an immutable version; from then on `/start` and inbound
triggers execute it. The publish response returns the flow with its new
`status` and current `version`.

```bash theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/flows/flow_9c3f1a8e/publish" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{}'
```

```json 200 theme={null}
{
  "data": {
    "id": "flow_9c3f1a8e",
    "name": "Weekly re-engagement",
    "status": "published",
    "version": 2
  },
  "meta": {
    "request_id": "req_flow_publish",
    "timestamp": "2026-08-27T12:02:00Z"
  }
}
```

Then enrol one contact (pass `list_id` instead to fan out across a small
list). The response tells you which mode ran and, for a single contact, the
execution row it created:

```bash theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/flows/flow_9c3f1a8e/start" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_id": "ctt_4d1e9a72",
    "context": { "order_total": "129.00" }
  }'
```

```json 202 theme={null}
{
  "data": {
    "mode": "single",
    "execution": {
      "id": "exec_51c8d320",
      "flow_id": "flow_9c3f1a8e",
      "status": "running"
    }
  },
  "meta": {
    "request_id": "req_flow_start",
    "timestamp": "2026-08-27T12:03:00Z"
  }
}
```

Send `list_id` instead and the response reports the list fan-out — how many
members were attempted and how many enrolled:

```json 202 theme={null}
{
  "data": {
    "mode": "list",
    "list_id": "lst_30f5b2c1",
    "attempted": 142,
    "enrolled": 141
  },
  "meta": {
    "request_id": "req_flow_start_list",
    "timestamp": "2026-08-27T12:04:00Z"
  }
}
```

<Note>
  To take the flow back out of live execution, `POST
      /api/v1/flows/{id}/unpublish` returns it to `draft`; only a `published`
  flow can be unpublished (409 otherwise).
</Note>
