# impartire API — Reference: Runs

Every path is under `https://impartire.com/api/v1`. The machine-readable contract is https://impartire.com/api/v1/openapi.json (OpenAPI 3.1).

#### GET /api/v1/runs

List workflow runs, most recently changed first

Every run of the org — started through the API, in the app, or by an upload. For an OAuth token, the runs on assets its person can read and the runs they started; a run of a team-private template they are not in is listed with `private: true` and no detail. Poll for progress with `updated_after`.

Scopes: `runs:read`

Parameters:

- `asset_id` (query, string (uuid)) — Only runs on this asset (any version of it).
- `workflow_id` (query, string (uuid)) — Only runs of this template (any version of it).
- `status` (query, "active" | "completed" | "cancelled" | "failed") — Only runs in this status.
- `updated_after` (query, string (date-time)) — Only runs whose state changed strictly after this instant, compared to the millisecond — poll with the newest `updated_at` you have seen (that run does not come back).
- `limit` (query, integer) — Page size, default 50. Values above 100 are treated as 100.
- `cursor` (query, string) — next_cursor from the previous page, with the other parameters unchanged.

Response 200 — `RunList`

- `data` (array of Run, required)
  - `id` (string (uuid), required)
  - `workflow` (object, required) — The template version the run is pinned to (any version's id names its template in GET /api/v1/workflows/{id}). `name` is null when the run is `private`.
    - `id` (string (uuid), required)
    - `name` (string or null, required)
  - `asset` (object, required) — The asset the run is about. `name` is null for an OAuth token whose person can no longer read the asset (a run they started).
    - `id` (string (uuid), required)
    - `name` (string or null, required)
  - `status` ("active" | "completed" | "cancelled" | "failed", required)
  - `private` (boolean, required) — True when the run's template is private to a team the token's person is not in: the run's existence, status, team and times are shown, its workflow name, steps, current step, incident and params are not (always false for an API key).
  - `team` (object or null, required) — The team that owns the run, snapshotted from its template at start; null for an unowned run.
    - `id` (string (uuid), required)
    - `name` (string, required)
  - `parent_run_id` (string (uuid) or null, required) — For a sub-workflow run, the run that started it.
  - `started_at` (string (date-time), required)
  - `updated_at` (string (date-time), required) — Moves on every change of state — poll on it with GET /api/v1/runs?updated_after=.
  - `completed_at` (string (date-time) or null, required)
  - `started_via` (string, required) — api (started through this API) | manual (in the app) | trigger (by an arrival trigger, e.g. an upload). More may be added.
  - `current_step` (object or null, required) — The first open step at the run's current gate, while the run is active; null otherwise.
    - `id` (string (uuid), required)
    - `name` (string, required)
    - `status` (string, required)
    - `awaiting` ("approval" | "completion" | "automation" or null, required) — What the step waits on: `approval` (a person's verdict), `completion` (a person marking it done), `automation` (the pipeline — an automated step, a gate or a sub-workflow); null while it is parked on an incident.
  - `steps` (array of RunStep, required)
    - `id` (string (uuid), required) — The template step's id (of the template version the run is pinned to).
    - `name` (string, required)
    - `status` (string, required) — pending | in_progress | submitted | approved | completed | failed | skipped | incident (more may be added).
  - `incident` (object or null, required) — Set while an active run is parked on a step that failed and waits for an operator to retry it or fail the run (in the app).
    - `message` (string, required)
  - `params` (object (any keys) or null, required) — The run's launch parameters, as validated against the template's param_schema.
- `next_cursor` (string or null, required) — Pass as `cursor` to get the next page; null means this is the last page.

Other responses:

- 401 (Problem) — unauthenticated — no key, or an unknown, revoked or expired one.
- 403 (Problem) — insufficient-scope — the key lacks a required scope.
- 404 (Problem) — not-found.
- 422 (Problem) — validation — a bad filter (`asset_id`, `workflow_id`, `status`, `updated_after`), `limit` or `cursor`.
- 429 (Problem) — rate-limited — the key's request budget is spent; wait Retry-After seconds.
- 500 (Problem) — internal.

#### POST /api/v1/runs

Start a workflow run on an asset

Runs the app's start checks — the template and the asset exist in the org, `params` match the template's `param_schema` — then hands the run to the orchestrator. 202: the run has started, not finished; poll GET /runs/{id} until `status` leaves `active`, or until `current_step.awaiting` is `approval` or `completion` (a person's turn, in the app). A template that can deliver — its own action, a step's, or a sub_workflow child's, recursively — is refused for every credential (403 `confirmation-required`, naming the step): deliver against a requirement with POST /delivery-requirements/{id}/deliver; a social publish is done in the app. For an OAuth token its person needs create_workflow in the org and read on the asset.

Scopes: `runs:write`

Parameters:

- `Idempotency-Key` (header, string) — Makes a retry safe: the same key and request within 24 hours replays the first response. 1–255 characters.

Request body — `StartRunRequest`

- `workflow_id` (string (uuid), required) — A template from GET /api/v1/workflows.
- `asset_id` (string (uuid), required) — The asset to run it on (its current version's id or its root id; the run is on the current version).
- `params` (object (any keys)) — Launch parameters, validated against the template's `param_schema`.

Response 202 — `Run`: A workflow run on an asset — one the API started, a person started in the app, or an upload set off.

- `id` (string (uuid), required)
- `workflow` (object, required) — The template version the run is pinned to (any version's id names its template in GET /api/v1/workflows/{id}). `name` is null when the run is `private`.
  - `id` (string (uuid), required)
  - `name` (string or null, required)
- `asset` (object, required) — The asset the run is about. `name` is null for an OAuth token whose person can no longer read the asset (a run they started).
  - `id` (string (uuid), required)
  - `name` (string or null, required)
- `status` ("active" | "completed" | "cancelled" | "failed", required)
- `private` (boolean, required) — True when the run's template is private to a team the token's person is not in: the run's existence, status, team and times are shown, its workflow name, steps, current step, incident and params are not (always false for an API key).
- `team` (object or null, required) — The team that owns the run, snapshotted from its template at start; null for an unowned run.
  - `id` (string (uuid), required)
  - `name` (string, required)
- `parent_run_id` (string (uuid) or null, required) — For a sub-workflow run, the run that started it.
- `started_at` (string (date-time), required)
- `updated_at` (string (date-time), required) — Moves on every change of state — poll on it with GET /api/v1/runs?updated_after=.
- `completed_at` (string (date-time) or null, required)
- `started_via` (string, required) — api (started through this API) | manual (in the app) | trigger (by an arrival trigger, e.g. an upload). More may be added.
- `current_step` (object or null, required) — The first open step at the run's current gate, while the run is active; null otherwise.
  - `id` (string (uuid), required)
  - `name` (string, required)
  - `status` (string, required)
  - `awaiting` ("approval" | "completion" | "automation" or null, required) — What the step waits on: `approval` (a person's verdict), `completion` (a person marking it done), `automation` (the pipeline — an automated step, a gate or a sub-workflow); null while it is parked on an incident.
- `steps` (array of RunStep, required)
  - `id` (string (uuid), required) — The template step's id (of the template version the run is pinned to).
  - `name` (string, required)
  - `status` (string, required) — pending | in_progress | submitted | approved | completed | failed | skipped | incident (more may be added).
- `incident` (object or null, required) — Set while an active run is parked on a step that failed and waits for an operator to retry it or fail the run (in the app).
  - `message` (string, required)
- `params` (object (any keys) or null, required) — The run's launch parameters, as validated against the template's param_schema.

Other responses:

- 401 (Problem) — unauthenticated — no key, or an unknown, revoked or expired one.
- 403 (Problem) — insufficient-scope, insufficient-permission, or confirmation-required — a template that reaches a delivery, with any credential (deliver with POST /delivery-requirements/{id}/deliver; publish a social delivery in the app).
- 404 (Problem) — not-found — the template's action needs a feature the org does not have.
- 409 (Problem) — idempotency-in-flight.
- 422 (Problem) — unknown-workflow, unknown-asset, validation (`params` against the template's `param_schema`), or idempotency-mismatch.
- 429 (Problem) — rate-limited — the key's request budget is spent; wait Retry-After seconds.
- 500 (Problem) — internal.
- 502 (Problem) — orchestration-unavailable — nothing was started; retry.

#### GET /api/v1/runs/{id}

Get one workflow run: its status, current step and steps

Scopes: `runs:read`

Parameters:

- `id` (path, string (uuid), required) — The run's id, from POST /api/v1/runs or GET /api/v1/runs.

Response 200 — `Run`: A workflow run on an asset — one the API started, a person started in the app, or an upload set off.

- `id` (string (uuid), required)
- `workflow` (object, required) — The template version the run is pinned to (any version's id names its template in GET /api/v1/workflows/{id}). `name` is null when the run is `private`.
  - `id` (string (uuid), required)
  - `name` (string or null, required)
- `asset` (object, required) — The asset the run is about. `name` is null for an OAuth token whose person can no longer read the asset (a run they started).
  - `id` (string (uuid), required)
  - `name` (string or null, required)
- `status` ("active" | "completed" | "cancelled" | "failed", required)
- `private` (boolean, required) — True when the run's template is private to a team the token's person is not in: the run's existence, status, team and times are shown, its workflow name, steps, current step, incident and params are not (always false for an API key).
- `team` (object or null, required) — The team that owns the run, snapshotted from its template at start; null for an unowned run.
  - `id` (string (uuid), required)
  - `name` (string, required)
- `parent_run_id` (string (uuid) or null, required) — For a sub-workflow run, the run that started it.
- `started_at` (string (date-time), required)
- `updated_at` (string (date-time), required) — Moves on every change of state — poll on it with GET /api/v1/runs?updated_after=.
- `completed_at` (string (date-time) or null, required)
- `started_via` (string, required) — api (started through this API) | manual (in the app) | trigger (by an arrival trigger, e.g. an upload). More may be added.
- `current_step` (object or null, required) — The first open step at the run's current gate, while the run is active; null otherwise.
  - `id` (string (uuid), required)
  - `name` (string, required)
  - `status` (string, required)
  - `awaiting` ("approval" | "completion" | "automation" or null, required) — What the step waits on: `approval` (a person's verdict), `completion` (a person marking it done), `automation` (the pipeline — an automated step, a gate or a sub-workflow); null while it is parked on an incident.
- `steps` (array of RunStep, required)
  - `id` (string (uuid), required) — The template step's id (of the template version the run is pinned to).
  - `name` (string, required)
  - `status` (string, required) — pending | in_progress | submitted | approved | completed | failed | skipped | incident (more may be added).
- `incident` (object or null, required) — Set while an active run is parked on a step that failed and waits for an operator to retry it or fail the run (in the app).
  - `message` (string, required)
- `params` (object (any keys) or null, required) — The run's launch parameters, as validated against the template's param_schema.

Other responses:

- 401 (Problem) — unauthenticated — no key, or an unknown, revoked or expired one.
- 403 (Problem) — insufficient-scope — the key lacks a required scope.
- 404 (Problem) — not-found.
- 429 (Problem) — rate-limited — the key's request budget is spent; wait Retry-After seconds.
- 500 (Problem) — internal.

#### POST /api/v1/runs/{id}/signals

Approve, reject, complete or skip a run's step, or cancel the run (guarded)

A guarded action (ADR 0081). The app's own checks run: the step must be one of the run's and still open, the run active; for a person, the step's completion authority (who may sign for it), a skip's director-or-above rule, and standing on any `output_asset_id`. On an asset under legal hold, approve, reject, complete and skip are 409 `legal-hold` (cancel is always allowed). **An API key may only `cancel`**: it runs at once and answers 200 with the run (poll it until `status` is `cancelled`); any other kind is 403 `insufficient-permission` — attesting to work must name a person. **An OAuth token's signal does not run**: it answers 202 with a Confirmation and its Location; show the person `confirm_url`, then poll GET /confirmations/{id} — once they confirm, the signal runs as them and the confirmation's `result` is the run. The same ask while one waits is 409 `confirmation-pending`. Audited: a `run.signalled` event on the run.

Scopes: `runs:signal`

Parameters:

- `id` (path, string (uuid), required) — The run's id, from POST /api/v1/runs or GET /api/v1/runs.
- `Idempotency-Key` (header, string) — Makes a retry safe: the same key and request within 24 hours replays the first response. 1–255 characters.

Request body — `SignalRunRequest`

- `kind` ("approve" | "reject" | "complete" | "skip" | "cancel", required) — `approve` / `reject` an approval step, `complete` a manual step, `skip` a step (a director-or-above act; never an automated step), `cancel` the run. With an API key only `cancel` is allowed: the others attest to work and must name a person (an OAuth token, confirmed by them).
- `workflow_step_id` (string (uuid)) — The step (from the run's `steps`): required for approve, reject, complete and skip.
- `output_asset_id` (string (uuid)) — For `complete` or `approve` of a step whose requirements need a deliverable: the asset that satisfies them (one of the org's, which the person may edit).
- `note` (string) — A note for the run's record (a skip's reason).

Response 200 — `Run`: A workflow run on an asset — one the API started, a person started in the app, or an upload set off.

- `id` (string (uuid), required)
- `workflow` (object, required) — The template version the run is pinned to (any version's id names its template in GET /api/v1/workflows/{id}). `name` is null when the run is `private`.
  - `id` (string (uuid), required)
  - `name` (string or null, required)
- `asset` (object, required) — The asset the run is about. `name` is null for an OAuth token whose person can no longer read the asset (a run they started).
  - `id` (string (uuid), required)
  - `name` (string or null, required)
- `status` ("active" | "completed" | "cancelled" | "failed", required)
- `private` (boolean, required) — True when the run's template is private to a team the token's person is not in: the run's existence, status, team and times are shown, its workflow name, steps, current step, incident and params are not (always false for an API key).
- `team` (object or null, required) — The team that owns the run, snapshotted from its template at start; null for an unowned run.
  - `id` (string (uuid), required)
  - `name` (string, required)
- `parent_run_id` (string (uuid) or null, required) — For a sub-workflow run, the run that started it.
- `started_at` (string (date-time), required)
- `updated_at` (string (date-time), required) — Moves on every change of state — poll on it with GET /api/v1/runs?updated_after=.
- `completed_at` (string (date-time) or null, required)
- `started_via` (string, required) — api (started through this API) | manual (in the app) | trigger (by an arrival trigger, e.g. an upload). More may be added.
- `current_step` (object or null, required) — The first open step at the run's current gate, while the run is active; null otherwise.
  - `id` (string (uuid), required)
  - `name` (string, required)
  - `status` (string, required)
  - `awaiting` ("approval" | "completion" | "automation" or null, required) — What the step waits on: `approval` (a person's verdict), `completion` (a person marking it done), `automation` (the pipeline — an automated step, a gate or a sub-workflow); null while it is parked on an incident.
- `steps` (array of RunStep, required)
  - `id` (string (uuid), required) — The template step's id (of the template version the run is pinned to).
  - `name` (string, required)
  - `status` (string, required) — pending | in_progress | submitted | approved | completed | failed | skipped | incident (more may be added).
- `incident` (object or null, required) — Set while an active run is parked on a step that failed and waits for an operator to retry it or fail the run (in the app).
  - `message` (string, required)
- `params` (object (any keys) or null, required) — The run's launch parameters, as validated against the template's param_schema.

Response 202 — `Confirmation`: A guarded action an OAuth token asked for, waiting for its person to confirm it in impartire (ADR 0081). A guarded endpoint answers 202 with this and a Location; poll it until `status` is executed, declined or expired.

- `id` (string (uuid), required)
- `status` ("pending" | "confirmed" | "declined" | "expired" | "executed", required) — pending: waiting for the person to confirm or decline it in impartire (at `confirm_url`). confirmed: they confirmed and the action is running — poll again. executed: it ran; `result` holds its answer, or `problem` why it failed. declined: they said no; it will never run. expired: nobody decided within 15 minutes; it will never run (GET /api/v1/confirmations/{id} answers 410 confirmation-expired instead of this body; the person still sees it in impartire).
- `action` (string, required) — The guarded action, e.g. `run.signal`.
- `resource` (object, required)
  - `type` (string, required) — The kind of resource the action is on, e.g. `run`.
  - `id` (string (uuid) or null, required)
  - `name` (string, required) — The resource as the person was shown it when the action was asked for.
- `summary` (string, required) — The action in words, as the person reads it on the confirmation page.
- `client_id` (string, required) — The OAuth client that asked.
- `confirm_url` (string, required) — Where the person confirms or declines it. Show it to them; the API cannot confirm.
- `created_at` (string (date-time), required)
- `expires_at` (string (date-time), required) — 15 minutes after it was asked for. A pending confirmation past it is expired.
- `decided_at` (string (date-time) or null, required) — When the person confirmed or declined it, or when it expired; null while pending.
- `result` (any, required) — When executed and the action succeeded: the action's answer (what the endpoint would have returned with a key). Null otherwise.
- `problem` (Problem or null, required) — When executed and the action failed: the Problem it failed with. Null otherwise.
  - `type` (string, required) — A stable URL naming the problem: https://impartire.com/problems/<code>. Branch on this.
  - `title` (string, required)
  - `status` (integer, required)
  - `detail` (string, required) — What went wrong and what to do about it, written for the caller.
  - `instance` (string, required) — The request path.
  - `request_id` (string, required) — Also sent as the Request-Id header. Quote it when reporting a problem.
  - `errors` (array of object) — On 422 validation: one entry per invalid field.
    - `path` (string, required) — The field or parameter, as a dotted path.
    - `message` (string, required)
  - `edit_seq` (integer) — On 412 precondition-failed: the resource's current edit_seq.
  - `etag` (string) — On 412 precondition-failed for a project, a collection, a playlist or a schedule slot: its current ETag.
  - `item_id` (string) — On 409 already-member: the existing item's id (in the collection or playlist).
  - `schema_version` (integer) — On 409 type-changed: the asset type's current schema_version.
  - `confirmation_id` (string) — On 409 confirmation-pending: the confirmation already waiting for its person (GET /api/v1/confirmations/{id}).
  - `confirm_url` (string) — On 409 confirmation-pending: where the person confirms or declines it, in impartire.

Other responses:

- 401 (Problem) — unauthenticated — no key, or an unknown, revoked or expired one.
- 403 (Problem) — insufficient-scope, or insufficient-permission — an API key's attesting signal, or (on confirm) a person who may not sign for the step.
- 404 (Problem) — not-found.
- 409 (Problem) — conflict — the run is not active, the step is already closed, or the run has not reached the orchestrator; legal-hold — the asset is held (not for cancel); confirmation-pending; or idempotency-in-flight.
- 422 (Problem) — validation (`workflow_step_id` missing or not a step of this run, an automated step to skip, a deliverable the step requires, `output_asset_id` with another kind), or idempotency-mismatch (an OAuth token may not send Idempotency-Key).
- 429 (Problem) — rate-limited — the key's request budget is spent; wait Retry-After seconds.
- 500 (Problem) — internal.
- 502 (Problem) — orchestration-unavailable — the signal did not reach the orchestrator; nothing happened.
