# Workflow API

The Workflow API manages Automation definitions, immutable published versions, and queued Runs.
Use it when a service needs to provision or invoke repeatable evidence workflows without driving
the Workbench UI.

Base URL:

```text
https://api.provon.dev/v1
```

Public routes use a project API key. The key selects the project:

```http
Authorization: Bearer <PROVON_API_KEY>
Content-Type: application/json
```

| Capability        | Access                                                    |
| ----------------- | --------------------------------------------------------- |
| `workflows:read`  | List and read definitions, versions, Runs, and Step Runs  |
| `workflows:write` | Create, update, delete, publish, invoke, and control Runs |

The default project key includes `workflows:read`, not `workflows:write`.

## Route Forms

Every route has two forms:

| Caller                     | Form                                    |
| -------------------------- | --------------------------------------- |
| Project API key            | `/v1/workflows/...`                     |
| Signed-in Workbench client | `/v1/projects/:projectId/workflows/...` |

The same rule applies to `/workflow-runs`. Public integrations should use the shorter API-key form
and must not mix a path project ID with a key from another project.

## Endpoints

### Definitions

| Method   | Path                     | Purpose                                  |
| -------- | ------------------------ | ---------------------------------------- |
| `GET`    | `/workflows`             | List workflow definitions                |
| `POST`   | `/workflows`             | Create an editable definition            |
| `GET`    | `/workflows/:id`         | Read a definition and published versions |
| `PATCH`  | `/workflows/:id`         | Update the editable definition           |
| `DELETE` | `/workflows/:id`         | Delete a definition                      |
| `POST`   | `/workflows/:id/publish` | Validate and publish a new version       |
| `POST`   | `/workflows/:id/runs`    | Queue a manual Run                       |

### Runs

| Method | Path                        | Purpose                                        |
| ------ | --------------------------- | ---------------------------------------------- |
| `GET`  | `/workflow-runs`            | List Runs                                      |
| `GET`  | `/workflow-runs/:id`        | Read a Run with its definition and steps       |
| `POST` | `/workflow-runs/:id/cancel` | Cancel queued or running work                  |
| `POST` | `/workflow-runs/:id/retry`  | Requeue failed, dead-letter, or cancelled work |
| `POST` | `/workflow-runs/:id/resume` | Resume queued or failed work                   |

Paths in the tables are relative to `https://api.provon.dev/v1`.

## Definition Model

A workflow definition contains:

```json
{
  "id": "workflow_01J...",
  "name": "Review a risky run",
  "description": "Create a Finding from reviewed manual input.",
  "status": "draft",
  "graph": {
    "nodes": [],
    "edges": []
  },
  "owner": "Reliability",
  "activeVersionId": null,
  "createdAt": 1760000000000,
  "updatedAt": 1760000000000,
  "publishedAt": null
}
```

Status is `draft`, `active`, `paused`, or `archived`. The editable `graph` is not executed directly.
Publishing snapshots it into an immutable version and sets `activeVersionId`.

Each graph node requires:

| Field         | Purpose                              |
| ------------- | ------------------------------------ |
| `id`          | Unique node ID inside the graph      |
| `kind`        | `trigger`, `control`, or `operation` |
| `op`          | Implemented operation identifier     |
| `label`       | Human-readable label                 |
| `description` | Optional explanation                 |
| `params`      | Operation-specific configuration     |

Each edge requires `id`, `source`, and `target`. Branching edges also carry a typed `branch` such as
`true`, `false`, `case`, `default`, `success`, or `failure`.

See [Automations](./automations.md) for supported trigger and operation families. The Workbench
builder is the recommended way to discover operation parameters; the API graph is the persisted
contract, not a second user-facing workflow language.

## Create A Workflow

This minimal draft accepts manual input and creates a Finding:

```http
POST /v1/workflows
```

```json
{
  "name": "Manual risk review",
  "description": "Create a Finding from an explicit invocation.",
  "status": "draft",
  "owner": "Reliability",
  "graph": {
    "nodes": [
      {
        "id": "manual",
        "kind": "trigger",
        "op": "trigger.manual",
        "label": "Manual",
        "params": {
          "inputSchema": "{\"fields\":[{\"key\":\"summary\",\"label\":\"Summary\",\"type\":\"text\",\"required\":true}],\"allowExtraFields\":false}"
        }
      },
      {
        "id": "finding",
        "kind": "operation",
        "op": "diagnostics.finding.create",
        "label": "Create a finding",
        "params": {
          "title": "Manual review: {{input.summary}}",
          "severity": "medium",
          "summary": "{{input.summary}}"
        }
      }
    ],
    "edges": [
      {
        "id": "manual-to-finding",
        "source": "manual",
        "target": "finding"
      }
    ]
  }
}
```

Successful creation returns `201`:

```json
{
  "workflow": {
    "id": "workflow_01J...",
    "name": "Manual risk review",
    "status": "draft"
  }
}
```

Client-supplied workflow IDs are ignored. Names must be unique inside the project.

## Update And Publish

`PATCH /workflows/:id` accepts any non-empty subset of:

```json
{
  "name": "Manual incident review",
  "description": "Updated purpose",
  "status": "paused",
  "owner": "Agent platform",
  "graph": {
    "nodes": [],
    "edges": []
  }
}
```

Publish after the draft graph is complete:

```http
POST /v1/workflows/workflow_01J.../publish
```

Publishing validates:

- graph structure and node IDs;
- trigger count and edge topology;
- required operation parameters;
- artifact compatibility between connected nodes;
- runtime support for every operation.

An invalid graph returns `400` with `error: "invalid_workflow_graph"` and an `issues` array. A
runtime that cannot report its workflow capabilities returns `503` with
`error: "workflow_runtime_unavailable"`.

## Queue A Manual Run

```http
POST /v1/workflows/workflow_01J.../runs
Idempotency-Key: incident-1842-review
```

```json
{
  "input": {
    "summary": "The agent claimed success after the refund tool returned HTTP 400."
  }
}
```

The API validates manual input against the trigger's input schema and enqueues execution. It does
not execute the graph inside the HTTP request. Successful enqueue returns `201` with the Run detail.

Use a stable `Idempotency-Key` for retried client requests. The key is scoped to the manual workflow
invocation and is stored as a stable trigger reference.

## List Definitions

```http
GET /v1/workflows?status=active&limit=50
```

Query parameters:

| Parameter | Values                                     |
| --------- | ------------------------------------------ |
| `status`  | `draft`, `active`, `paused`, or `archived` |
| `limit`   | Positive integer page size                 |
| `cursor`  | Opaque `pagination.nextCursor`             |

List items omit the complete graph and add `nodeCount`, `runCount`, and `triggerOp`. Read one
definition when graph or version detail is required.

## List And Inspect Runs

```http
GET /v1/workflow-runs?workflowId=workflow_01J...&status=failed&limit=50
```

Run filters:

| Parameter    | Values                                                                    |
| ------------ | ------------------------------------------------------------------------- |
| `workflowId` | One workflow ID                                                           |
| `status`     | `queued`, `running`, `completed`, `failed`, `dead_letter`, or `cancelled` |
| `limit`      | Positive integer page size                                                |
| `cursor`     | Opaque `pagination.nextCursor`                                            |

`GET /workflow-runs/:id` returns:

- the complete Run, including input and output;
- the current workflow definition when it still exists;
- the immutable version used by the Run;
- ordered Step Runs with node operation, attempts, input, output, and error.

## Run Control

| Action | Allowed source statuses              | Result                             |
| ------ | ------------------------------------ | ---------------------------------- |
| Cancel | `queued`, `running`                  | Run becomes `cancelled`            |
| Retry  | `failed`, `dead_letter`, `cancelled` | Run is requeued with more attempts |
| Resume | `queued`, `failed`                   | Existing Run is made runnable      |

Invalid transitions return `409`. Retry or resume only after correcting the dependency that caused
the failure; otherwise the same side effect can fail again.

## Pagination

Definition and Run lists return:

```json
{
  "pagination": {
    "limit": 50,
    "nextCursor": "1760000000000\tworkflow_01J..."
  }
}
```

Pass `nextCursor` unchanged. Do not parse it or derive a new cursor from timestamps.

## Errors

| Status | Meaning                                                  |
| ------ | -------------------------------------------------------- |
| `400`  | Invalid JSON, graph, field, cursor, or manual Run input  |
| `401`  | Public route did not receive a valid project API key     |
| `403`  | API key lacks `workflows:read` or `workflows:write`      |
| `404`  | Workflow, version, or Run was not found in the project   |
| `409`  | Name conflict, inactive workflow, or invalid transition  |
| `503`  | Queue or workflow runtime capability service unavailable |
| `504`  | A workflow node timed out                                |

Workflow-domain errors generally return a short machine-readable `error` string and optional
`message`. Authentication errors use the shared structured API error body.

## Related Docs

- [Automations](./automations.md)
- [Evals](./evals.md)
- [Datasets](./datasets.md)
- [Connectors](./connectors.md)
- [Diagnostics API](./diagnostics-api.md)
- [API reference](./api-reference.md)
