# Flows

A flow is a voice app of kind `flow`: a graph of nodes (say, gather, dial, AI agent, condition, HTTP request, ...)
that answers calls. You create and edit the flow's draft graph through [voice apps](/guides/voice-apps.md)
(`POST /voice-apps` with `kind: "flow"` and `flow: {...}`, then `PATCH /voice-apps/{id}`). The endpoints here
validate a graph and manage published versions: calls are answered by the published version, or by the draft
until the first publish.

Auth, errors, paging and idempotency work as described in the [overview](/guides/overview.md).

Base URL: `https://api.contactivity.io/v1/projects/{project_id}`

| Method | Path | Scope | Purpose |
|---|---|---|---|
| POST | `/flows/validate` | `apps:read` | Validate a graph without saving it |
| GET | `/flows/{app_id}/versions` | `apps:read` | List published versions |
| POST | `/flows/{app_id}/versions` | `apps:write` | Publish the draft as a new version |
| GET | `/flows/{app_id}/versions/{version}` | `apps:read` | Fetch a version with its graph |
| POST | `/flows/{app_id}/versions/{version}/rollback` | `apps:write` | Publish an older version again |

## The graph

| Field | Type | Notes |
|---|---|---|
| `start` | string | Id of the first node. Default: the first node. |
| `variables` | object | Initial variables (`name: value`). Names match `^[A-Za-z_][A-Za-z0-9_.]{0,63}$`. |
| `nodes` | array, required | 1-200 nodes `{id, type, config, position}`. `id`: 1-64 of `A-Z a-z 0-9 _ -`, unique. |
| `edges` | array, required | Up to 400 edges `{from, to, label, condition}`. |

Node types: `say`, `play`, `pause`, `gather`, `dial`, `record`, `enqueue`, `conference`, `ai_agent`, `redirect`,
`transfer`, `hangup`, `set`, `condition`, `http`, `conversation`, `tool`. `conversation`, `tool` and `condition`
nodes can form an AI region that one agent conversation runs. A graph is at most 256 KB of JSON.

Edge `condition`: `{var, op, value}` with `op` one of `eq`, `ne`, `gt`, `lt`, `contains`, `regex`, `empty`,
`not_empty`, or `{op: "schedule", tz, days, start, end}` (days `mon`..`sun`, times `HH:MM`).

## Validate a graph

`POST /flows/validate` takes a graph as the body and returns `{valid, errors, warnings}`. Each issue is
`{node?, edge?, message}`. It checks the structure, every node's settings, and references to this project's
voice apps, queues and numbers. A body that is not a graph comes back as `valid: false`, not as an error.

```sh
curl https://api.contactivity.io/v1/projects/$PROJECT_ID/flows/validate \
  -H "Authorization: Bearer $CONTACTIVITY_API_KEY" \
  -H "Content-Type: application/json" -H "Idempotency-Key: $(uuidgen)" \
  -d '{"nodes":[{"id":"hi","type":"say","config":{"text":"Hello"}},{"id":"bye","type":"hangup","config":{}}],
       "edges":[{"from":"hi","to":"bye"}]}'
```

```json
{"valid": true, "errors": [], "warnings": []}
```

Errors: `400 invalid_parameter` only when the body cannot be read.

## Versions

Version object:

| Field | Type | Notes |
|---|---|---|
| `version` | integer | 1, 2, 3, ... |
| `note` | string | Release note |
| `author` | string or null | User id, or `api-key` when published with an API key |
| `author_email` | string or null | |
| `created_at` | timestamp | |
| `graph` | object | Fetch only |

### List versions

`GET /flows/{app_id}/versions`, newest first, paged (`limit`, `starting_after`). Besides `data`, `has_more` and
`next_cursor`, the response carries `published` (the version answering calls, null before the first publish)
and `draft_changed` (the draft differs from the newest version).

```sh
curl https://api.contactivity.io/v1/projects/$PROJECT_ID/flows/app_us1_abc/versions \
  -H "Authorization: Bearer $CONTACTIVITY_API_KEY"
```

Errors: `400 invalid_parameter` (`limit`, `starting_after`), `404 not_found` (no flow app with this id).

### Publish

`POST /flows/{app_id}/versions` snapshots the draft as the next version and makes it answer calls. The body is
optional: `{"note": "..."}` (at most 500 characters). The graph is validated first; a graph with errors (for
example an AI agent app deleted since) is refused with the first error as the message.

```sh
curl https://api.contactivity.io/v1/projects/$PROJECT_ID/flows/app_us1_abc/versions \
  -H "Authorization: Bearer $CONTACTIVITY_API_KEY" \
  -H "Content-Type: application/json" -H "Idempotency-Key: $(uuidgen)" \
  -d '{"note": "New opening hours"}'
```

Returns `201` with the version. Errors: `400 invalid_parameter` (`note`, or `flow node <id>: ...`),
`400 unknown_parameter`, `400 invalid_json`, `404 not_found`.

### Fetch a version

`GET /flows/{app_id}/versions/{version}` returns the version with its `graph`. Errors: `404 not_found`.

### Roll back

`POST /flows/{app_id}/versions/{version}/rollback` publishes that version's graph as a new version (the draft is
unchanged). Optional body `{"note"}`; default note `Rollback to version N`. The graph is validated again.
Returns `201` with the new version. Errors as for publish.
