# run

Job-run history, reports, and tasks persisted by the Amfelt agent.

**Amfelt REST API** · v1.13.0 · `https://api.amfelt.com`

---
### GET `/v1/runs/metrics` {#getrunmetrics}

**Get run metrics aggregate.**

Returns aggregate metrics for job runs in the caller's organization within the specified time window, optionally filtered by project and environment.

#### Parameters

| Name | In  | Required | Type | Description |
| ---- | --- | -------- | ---- | ----------- |
| `X-Tenant-Slug` | header | Yes | string | Slug of the organization to scope the request to; required for user-authenticated requests. |
| `project` | query | No | string | Filter metrics by project uuid. |
| `env` | query | No | string | Filter metrics by DTAP environment slug. |
| `window` | query | No | string (enum: `24h`, `7d`, `30d`) | Time window for the aggregate. |

#### Responses

**200** — Run metrics aggregate for the requested window.

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `avg_duration_ms` | number | Yes | Average run duration in milliseconds (COALESCE 0 when no completed runs). |
| `failed` | integer | Yes | Number of runs that ended in failure. |
| `p95_duration_ms` | number | Yes | 95th-percentile run duration in milliseconds (COALESCE 0 when no completed runs). |
| `running` | integer | Yes | Number of runs currently in progress. |
| `succeeded` | integer | Yes | Number of runs that completed successfully. |
| `total` | integer | Yes | Total number of runs in the window. |
| `total_bytes` | integer | Yes | Sum of run telemetry bytes over the requested window/project/env scope. |
| `total_rows` | integer | Yes | Sum of run telemetry rows over the requested window/project/env scope. |


**400** — The request was malformed or failed validation.

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `code` | string | Yes | Stable, snake_case token identifying the error condition. See ErrorCode for the api's canonical named vocabulary — this field is deliberately not restricted to it, since handlers may emit other ad-hoc codes not listed there (e.g. not_implemented). Examples: `invalid_argument`. |
| `field` | string | No | Optional hint identifying the request field the error refers to, in snake_case (e.g. "slug", "display_name", "token"). Set by handlers that validate multiple fields and want to enable field-targeted UX in clients. Absent when the error does not map to a single field. Examples: `slug`. |
| `message` | string | Yes | Human-readable description of the error. Examples: `limit must be between 1 and 100`. |


**401** — The request lacks valid credentials.

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `code` | string | Yes | Stable, snake_case token identifying the error condition. See ErrorCode for the api's canonical named vocabulary — this field is deliberately not restricted to it, since handlers may emit other ad-hoc codes not listed there (e.g. not_implemented). Examples: `invalid_argument`. |
| `field` | string | No | Optional hint identifying the request field the error refers to, in snake_case (e.g. "slug", "display_name", "token"). Set by handlers that validate multiple fields and want to enable field-targeted UX in clients. Absent when the error does not map to a single field. Examples: `slug`. |
| `message` | string | Yes | Human-readable description of the error. Examples: `limit must be between 1 and 100`. |


#### Security

bearer_jwt

---

### GET `/v1/runs` {#listruns}

**List job runs.**

Returns a page of job runs for the caller's organization, optionally filtered by job name, status, project, environment, source, or time window.

#### Parameters

| Name | In  | Required | Type | Description |
| ---- | --- | -------- | ---- | ----------- |
| `X-Tenant-Slug` | header | Yes | string | Slug of the organization to scope the request to; required for user-authenticated requests. |
| `job` | query | No | string | Filter job runs by job name. |
| `status` | query | No | string | Filter job runs by status. |
| `cursor` | query | No | string | Opaque cursor for the next page; pass back the 'next_cursor' from a prior response. |
| `limit` | query | No | integer | Maximum number of items to return per page. |
| `project` | query | No | string | Filter runs by project uuid. |
| `env` | query | No | string | Filter runs by DTAP environment slug. |
| `source` | query | No | string | Filter runs by source name. |
| `window` | query | No | string (enum: `24h`, `7d`, `30d`) | Limit returned runs to a relative time window. When omitted, no time filter is applied. |

#### Responses

**200** — A page of job runs.

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `data` | [Run](#run)[] | Yes | The page of job runs. |
| `next_cursor` | [string null] | No | Opaque cursor for the next page, or null when this is the final page. Examples: `eyJpZCI6OTk5fQ`. |


**400** — The request was malformed or failed validation.

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `code` | string | Yes | Stable, snake_case token identifying the error condition. See ErrorCode for the api's canonical named vocabulary — this field is deliberately not restricted to it, since handlers may emit other ad-hoc codes not listed there (e.g. not_implemented). Examples: `invalid_argument`. |
| `field` | string | No | Optional hint identifying the request field the error refers to, in snake_case (e.g. "slug", "display_name", "token"). Set by handlers that validate multiple fields and want to enable field-targeted UX in clients. Absent when the error does not map to a single field. Examples: `slug`. |
| `message` | string | Yes | Human-readable description of the error. Examples: `limit must be between 1 and 100`. |


**401** — The request lacks valid credentials.

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `code` | string | Yes | Stable, snake_case token identifying the error condition. See ErrorCode for the api's canonical named vocabulary — this field is deliberately not restricted to it, since handlers may emit other ad-hoc codes not listed there (e.g. not_implemented). Examples: `invalid_argument`. |
| `field` | string | No | Optional hint identifying the request field the error refers to, in snake_case (e.g. "slug", "display_name", "token"). Set by handlers that validate multiple fields and want to enable field-targeted UX in clients. Absent when the error does not map to a single field. Examples: `slug`. |
| `message` | string | Yes | Human-readable description of the error. Examples: `limit must be between 1 and 100`. |


#### Security

bearer_jwt

---

### POST `/v1/runs` {#createrun}

**Create a job run.**

Records a new job run. The organization is derived from the agent credentials; any organization_id in the body is ignored.

#### Request body _(required)_

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `agent_id` | string | Yes | Identifier of the agent executing the run. |
| `cmd_id` | string | No | Correlation key from the cmd.execute_flow dispatch that started this run. |
| `config_commit_sha` | [string null] | No | Full SHA of the configuration commit the run executes (ADR-129 decisions 1 and 11). Null with config_source draft means the agent did not hold a commit byte for byte. Absent or null with no config_source means unknown: the run was reported by an older agent that does not send its commit. Examples: `8f14e45fceea167a5a36dedd4bea2543c3a6f7b2`. |
| `config_source` | [string null] | No | Where the run's configuration came from. commit means the agent held the commit config_commit_sha byte for byte; draft means its configuration was written by a file-form deploy or a local edit, so it matches no commit and config_commit_sha is null. Absent or null means unknown: the run was reported by an older agent, never draft. Valid values are: `commit`, `draft`. Examples: `commit`. |
| `environment` | string | No | DTAP environment slug the run ran in; resolved to FK server-side. |
| `job_name` | string | Yes | Name of the job that produced the run. Examples: `sales-to-dwh`. |
| `object_count` | integer | No | Number of objects the run will process. |
| `run_id` | integer | Yes | Client-assigned unique identifier of the run. Examples: `20260412120000000`. |
| `source` | string | No | Name of the source the run processed; identifies the project server-side. |
| `started_at` | string | Yes | Timestamp when the run started. |
| `status` | string | No | Initial lifecycle status; defaults to 'started' when omitted. Examples: `started`. |


#### Responses

**201** — The job run was created.

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `run_id` | integer | Yes | Identifier of the run. Examples: `20260412120000000`. |


**400** — The request was malformed or failed validation.

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `code` | string | Yes | Stable, snake_case token identifying the error condition. See ErrorCode for the api's canonical named vocabulary — this field is deliberately not restricted to it, since handlers may emit other ad-hoc codes not listed there (e.g. not_implemented). Examples: `invalid_argument`. |
| `field` | string | No | Optional hint identifying the request field the error refers to, in snake_case (e.g. "slug", "display_name", "token"). Set by handlers that validate multiple fields and want to enable field-targeted UX in clients. Absent when the error does not map to a single field. Examples: `slug`. |
| `message` | string | Yes | Human-readable description of the error. Examples: `limit must be between 1 and 100`. |


**401** — The request lacks valid credentials.

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `code` | string | Yes | Stable, snake_case token identifying the error condition. See ErrorCode for the api's canonical named vocabulary — this field is deliberately not restricted to it, since handlers may emit other ad-hoc codes not listed there (e.g. not_implemented). Examples: `invalid_argument`. |
| `field` | string | No | Optional hint identifying the request field the error refers to, in snake_case (e.g. "slug", "display_name", "token"). Set by handlers that validate multiple fields and want to enable field-targeted UX in clients. Absent when the error does not map to a single field. Examples: `slug`. |
| `message` | string | Yes | Human-readable description of the error. Examples: `limit must be between 1 and 100`. |


**409** — The request conflicts with the current state of the resource.

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `code` | string | Yes | Stable, snake_case token identifying the error condition. See ErrorCode for the api's canonical named vocabulary — this field is deliberately not restricted to it, since handlers may emit other ad-hoc codes not listed there (e.g. not_implemented). Examples: `invalid_argument`. |
| `field` | string | No | Optional hint identifying the request field the error refers to, in snake_case (e.g. "slug", "display_name", "token"). Set by handlers that validate multiple fields and want to enable field-targeted UX in clients. Absent when the error does not map to a single field. Examples: `slug`. |
| `message` | string | Yes | Human-readable description of the error. Examples: `limit must be between 1 and 100`. |


#### Security

bearer_jwt

---

### DELETE `/v1/runs` {#purgeruns}

**Purge job runs.**

Permanently deletes every run, task, and checkpoint for the caller's organization.

#### Responses

**204** — The runs were purged.

**401** — The request lacks valid credentials.

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `code` | string | Yes | Stable, snake_case token identifying the error condition. See ErrorCode for the api's canonical named vocabulary — this field is deliberately not restricted to it, since handlers may emit other ad-hoc codes not listed there (e.g. not_implemented). Examples: `invalid_argument`. |
| `field` | string | No | Optional hint identifying the request field the error refers to, in snake_case (e.g. "slug", "display_name", "token"). Set by handlers that validate multiple fields and want to enable field-targeted UX in clients. Absent when the error does not map to a single field. Examples: `slug`. |
| `message` | string | Yes | Human-readable description of the error. Examples: `limit must be between 1 and 100`. |


#### Security

bearer_jwt

---

### GET `/v1/runs/{run_id}/tasks` {#listruntasks}

**List run tasks.**

Returns a page of tasks executed during a job run.

#### Parameters

| Name | In  | Required | Type | Description |
| ---- | --- | -------- | ---- | ----------- |
| `X-Tenant-Slug` | header | Yes | string | Slug of the organization to scope the request to; required for user-authenticated requests. |
| `run_id` | path | Yes | integer | Identifier of the job run. |
| `cursor` | query | No | string | Opaque cursor for the next page; pass back the 'next_cursor' from a prior response. |
| `limit` | query | No | integer | Maximum number of items to return per page. |

#### Responses

**200** — A page of run tasks.

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `data` | [Task](#task)[] | Yes | The page of tasks. |
| `next_cursor` | [string null] | No | Opaque cursor for the next page, or null when this is the final page. Examples: `eyJpZCI6OTk5fQ`. |


**401** — The request lacks valid credentials.

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `code` | string | Yes | Stable, snake_case token identifying the error condition. See ErrorCode for the api's canonical named vocabulary — this field is deliberately not restricted to it, since handlers may emit other ad-hoc codes not listed there (e.g. not_implemented). Examples: `invalid_argument`. |
| `field` | string | No | Optional hint identifying the request field the error refers to, in snake_case (e.g. "slug", "display_name", "token"). Set by handlers that validate multiple fields and want to enable field-targeted UX in clients. Absent when the error does not map to a single field. Examples: `slug`. |
| `message` | string | Yes | Human-readable description of the error. Examples: `limit must be between 1 and 100`. |


**404** — The specified resource was not found.

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `code` | string | Yes | Stable, snake_case token identifying the error condition. See ErrorCode for the api's canonical named vocabulary — this field is deliberately not restricted to it, since handlers may emit other ad-hoc codes not listed there (e.g. not_implemented). Examples: `invalid_argument`. |
| `field` | string | No | Optional hint identifying the request field the error refers to, in snake_case (e.g. "slug", "display_name", "token"). Set by handlers that validate multiple fields and want to enable field-targeted UX in clients. Absent when the error does not map to a single field. Examples: `slug`. |
| `message` | string | Yes | Human-readable description of the error. Examples: `limit must be between 1 and 100`. |


#### Security

bearer_jwt

---

### POST `/v1/runs/{run_id}/rerun` {#rerunfailedobjects}

**Rerun the objects of a finished run that did not succeed.**

Starts a new run of the same job in the same environment that loads only the objects that did not succeed in the given run: an object is skipped when all of its tasks in that run succeeded, so failed objects and objects the run never started are loaded again. Dispatches a cmd.execute_flow command to the environment's agent and returns immediately. The new run records trigger rerun and rerun_of_run_id. The rerun runs at the configuration commit the original run recorded; when it recorded none, it runs at the current commit, and commit_basis says which. One audit event is written per rerun: object type run, action create, detail operation rerun.

#### Parameters

| Name | In  | Required | Type | Description |
| ---- | --- | -------- | ---- | ----------- |
| `run_id` | path | Yes | integer | Identifier of the job run. |

#### Responses

**202** — Rerun dispatched to the environment's agent. When the agent is offline, status is queued_offline and the command is delivered when it reconnects, as for a manual run.

`application/json`

Child elements:

- [RunTriggerRef](#run-trigger-ref)


**401** — The request lacks valid credentials.

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `code` | string | Yes | Stable, snake_case token identifying the error condition. See ErrorCode for the api's canonical named vocabulary — this field is deliberately not restricted to it, since handlers may emit other ad-hoc codes not listed there (e.g. not_implemented). Examples: `invalid_argument`. |
| `field` | string | No | Optional hint identifying the request field the error refers to, in snake_case (e.g. "slug", "display_name", "token"). Set by handlers that validate multiple fields and want to enable field-targeted UX in clients. Absent when the error does not map to a single field. Examples: `slug`. |
| `message` | string | Yes | Human-readable description of the error. Examples: `limit must be between 1 and 100`. |


**403** — The caller is authenticated but not permitted to perform the request.

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `code` | string | Yes | Stable, snake_case token identifying the error condition. See ErrorCode for the api's canonical named vocabulary — this field is deliberately not restricted to it, since handlers may emit other ad-hoc codes not listed there (e.g. not_implemented). Examples: `invalid_argument`. |
| `field` | string | No | Optional hint identifying the request field the error refers to, in snake_case (e.g. "slug", "display_name", "token"). Set by handlers that validate multiple fields and want to enable field-targeted UX in clients. Absent when the error does not map to a single field. Examples: `slug`. |
| `message` | string | Yes | Human-readable description of the error. Examples: `limit must be between 1 and 100`. |


**404** — Code not_found: the run does not exist. Nothing is dispatched.

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `code` | string | Yes | Stable, snake_case token identifying the error condition. See ErrorCode for the api's canonical named vocabulary — this field is deliberately not restricted to it, since handlers may emit other ad-hoc codes not listed there (e.g. not_implemented). Examples: `invalid_argument`. |
| `field` | string | No | Optional hint identifying the request field the error refers to, in snake_case (e.g. "slug", "display_name", "token"). Set by handlers that validate multiple fields and want to enable field-targeted UX in clients. Absent when the error does not map to a single field. Examples: `slug`. |
| `message` | string | Yes | Human-readable description of the error. Examples: `limit must be between 1 and 100`. |


**409** — The run cannot be rerun in its current state. Nothing is dispatched. The causes are: every object of the run succeeded, answered with "nothing to rerun" (code conflict); the run has not finished, answered with "run is still running" (code conflict); another run of the same job is running, answered with "job is running" (code conflict); the agent is below the version that can skip objects, answered with "upgrade the agent to <floor> or later to rerun failed objects", where <floor> is that version (code agent_upgrade_required); the project is archived (code project_archived).

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `code` | string | Yes | Stable, snake_case token identifying the error condition. See ErrorCode for the api's canonical named vocabulary — this field is deliberately not restricted to it, since handlers may emit other ad-hoc codes not listed there (e.g. not_implemented). Examples: `invalid_argument`. |
| `field` | string | No | Optional hint identifying the request field the error refers to, in snake_case (e.g. "slug", "display_name", "token"). Set by handlers that validate multiple fields and want to enable field-targeted UX in clients. Absent when the error does not map to a single field. Examples: `slug`. |
| `message` | string | Yes | Human-readable description of the error. Examples: `limit must be between 1 and 100`. |


#### Security

bearer_jwt

---

### GET `/v1/runs/{run_id}/report` {#getrunreport}

**Get a run report.**

Returns the report and optional remedy attached to a job run.

#### Parameters

| Name | In  | Required | Type | Description |
| ---- | --- | -------- | ---- | ----------- |
| `X-Tenant-Slug` | header | Yes | string | Slug of the organization to scope the request to; required for user-authenticated requests. |
| `run_id` | path | Yes | integer | Identifier of the job run. |

#### Responses

**200** — The run report.

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `remedy` | object | No | Optional structured remedy describing how to resolve a failed run. |
| `report` | object | Yes | Structured report describing the run outcome. |


**401** — The request lacks valid credentials.

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `code` | string | Yes | Stable, snake_case token identifying the error condition. See ErrorCode for the api's canonical named vocabulary — this field is deliberately not restricted to it, since handlers may emit other ad-hoc codes not listed there (e.g. not_implemented). Examples: `invalid_argument`. |
| `field` | string | No | Optional hint identifying the request field the error refers to, in snake_case (e.g. "slug", "display_name", "token"). Set by handlers that validate multiple fields and want to enable field-targeted UX in clients. Absent when the error does not map to a single field. Examples: `slug`. |
| `message` | string | Yes | Human-readable description of the error. Examples: `limit must be between 1 and 100`. |


**404** — The specified resource was not found.

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `code` | string | Yes | Stable, snake_case token identifying the error condition. See ErrorCode for the api's canonical named vocabulary — this field is deliberately not restricted to it, since handlers may emit other ad-hoc codes not listed there (e.g. not_implemented). Examples: `invalid_argument`. |
| `field` | string | No | Optional hint identifying the request field the error refers to, in snake_case (e.g. "slug", "display_name", "token"). Set by handlers that validate multiple fields and want to enable field-targeted UX in clients. Absent when the error does not map to a single field. Examples: `slug`. |
| `message` | string | Yes | Human-readable description of the error. Examples: `limit must be between 1 and 100`. |


#### Security

bearer_jwt

---

### PUT `/v1/runs/{run_id}/report` {#setrunreport}

**Set a run report.**

Attaches a report and optional remedy to a job run.

#### Parameters

| Name | In  | Required | Type | Description |
| ---- | --- | -------- | ---- | ----------- |
| `run_id` | path | Yes | integer | Identifier of the job run. |

#### Request body _(required)_

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `remedy` | object | No | Optional structured remedy describing how to resolve a failed run. |
| `report` | object | Yes | Structured report describing the run outcome. |


#### Responses

**200** — The run report was stored.

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `run_id` | integer | Yes | Identifier of the run. Examples: `20260412120000000`. |


**400** — The request was malformed or failed validation.

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `code` | string | Yes | Stable, snake_case token identifying the error condition. See ErrorCode for the api's canonical named vocabulary — this field is deliberately not restricted to it, since handlers may emit other ad-hoc codes not listed there (e.g. not_implemented). Examples: `invalid_argument`. |
| `field` | string | No | Optional hint identifying the request field the error refers to, in snake_case (e.g. "slug", "display_name", "token"). Set by handlers that validate multiple fields and want to enable field-targeted UX in clients. Absent when the error does not map to a single field. Examples: `slug`. |
| `message` | string | Yes | Human-readable description of the error. Examples: `limit must be between 1 and 100`. |


**401** — The request lacks valid credentials.

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `code` | string | Yes | Stable, snake_case token identifying the error condition. See ErrorCode for the api's canonical named vocabulary — this field is deliberately not restricted to it, since handlers may emit other ad-hoc codes not listed there (e.g. not_implemented). Examples: `invalid_argument`. |
| `field` | string | No | Optional hint identifying the request field the error refers to, in snake_case (e.g. "slug", "display_name", "token"). Set by handlers that validate multiple fields and want to enable field-targeted UX in clients. Absent when the error does not map to a single field. Examples: `slug`. |
| `message` | string | Yes | Human-readable description of the error. Examples: `limit must be between 1 and 100`. |


**404** — The specified resource was not found.

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `code` | string | Yes | Stable, snake_case token identifying the error condition. See ErrorCode for the api's canonical named vocabulary — this field is deliberately not restricted to it, since handlers may emit other ad-hoc codes not listed there (e.g. not_implemented). Examples: `invalid_argument`. |
| `field` | string | No | Optional hint identifying the request field the error refers to, in snake_case (e.g. "slug", "display_name", "token"). Set by handlers that validate multiple fields and want to enable field-targeted UX in clients. Absent when the error does not map to a single field. Examples: `slug`. |
| `message` | string | Yes | Human-readable description of the error. Examples: `limit must be between 1 and 100`. |


#### Security

bearer_jwt

---

### GET `/v1/runs/{run_id}/detail` {#getrundetail}

**Get run detail.**

Returns the projected checkpoint tree for a job run as a flat phase/task viewer model (ADR-050/ADR-057). Roots are parent_id IS NULL checkpoints; phases are each root's direct children; tasks are each phase's children.

#### Parameters

| Name | In  | Required | Type | Description |
| ---- | --- | -------- | ---- | ----------- |
| `X-Tenant-Slug` | header | Yes | string | Slug of the organization to scope the request to; required for user-authenticated requests. |
| `run_id` | path | Yes | integer | Identifier of the job run. |

#### Responses

**200** — The run detail projection.

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `config_commit_sha` | [string null] | No | Full SHA of the configuration commit the run executed (ADR-129 decisions 1 and 11). Null with config_source draft means the agent did not hold a commit byte for byte. Absent or null with no config_source means unknown: the run was reported by an older agent that does not send its commit. Examples: `8f14e45fceea167a5a36dedd4bea2543c3a6f7b2`. |
| `config_source` | [string null] | No | Where the run's configuration came from. commit means the agent held the commit config_commit_sha byte for byte; draft means its configuration was written by a file-form deploy or a local edit, so it matches no commit and config_commit_sha is null. Absent or null means unknown: the run was reported by an older agent, never draft. Valid values are: `commit`, `draft`. Examples: `commit`. |
| `id` | string | Yes | Run identifier (string representation of run_id). |
| `phases` | [RunPhase](#run-phase)[] | Yes | Ordered list of run phases projected from the checkpoint tree. |
| `status` | string | Yes | Viewer status of the run. Valid values are: `pending`, `running`, `done`, `failed`, `warning`. |
| `strategy` | [string null] | No | Load strategy the run was dispatched with; the strategy actually applied per object is reported on its tasks. null = not reported (older agent or older run). Valid values are: `full`, `incremental`, `window`, `full_reload`. Examples: `incremental`. |


**401** — The request lacks valid credentials.

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `code` | string | Yes | Stable, snake_case token identifying the error condition. See ErrorCode for the api's canonical named vocabulary — this field is deliberately not restricted to it, since handlers may emit other ad-hoc codes not listed there (e.g. not_implemented). Examples: `invalid_argument`. |
| `field` | string | No | Optional hint identifying the request field the error refers to, in snake_case (e.g. "slug", "display_name", "token"). Set by handlers that validate multiple fields and want to enable field-targeted UX in clients. Absent when the error does not map to a single field. Examples: `slug`. |
| `message` | string | Yes | Human-readable description of the error. Examples: `limit must be between 1 and 100`. |


**404** — The specified resource was not found.

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `code` | string | Yes | Stable, snake_case token identifying the error condition. See ErrorCode for the api's canonical named vocabulary — this field is deliberately not restricted to it, since handlers may emit other ad-hoc codes not listed there (e.g. not_implemented). Examples: `invalid_argument`. |
| `field` | string | No | Optional hint identifying the request field the error refers to, in snake_case (e.g. "slug", "display_name", "token"). Set by handlers that validate multiple fields and want to enable field-targeted UX in clients. Absent when the error does not map to a single field. Examples: `slug`. |
| `message` | string | Yes | Human-readable description of the error. Examples: `limit must be between 1 and 100`. |


#### Security

bearer_jwt

---

### POST `/v1/runs/{run_id}/cancel` {#cancelrun}

**Request cancellation of an in-flight run.**

Dispatches a cmd.stop_job command to the run's assigned agent. The run status transitions to cancelled asynchronously via the agent's run_finished telemetry; the endpoint returns immediately.

#### Parameters

| Name | In  | Required | Type | Description |
| ---- | --- | -------- | ---- | ----------- |
| `run_id` | path | Yes | integer | Identifier of the job run. |

#### Responses

**202** — Cancellation dispatched to the run's agent.

**401** — The request lacks valid credentials.

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `code` | string | Yes | Stable, snake_case token identifying the error condition. See ErrorCode for the api's canonical named vocabulary — this field is deliberately not restricted to it, since handlers may emit other ad-hoc codes not listed there (e.g. not_implemented). Examples: `invalid_argument`. |
| `field` | string | No | Optional hint identifying the request field the error refers to, in snake_case (e.g. "slug", "display_name", "token"). Set by handlers that validate multiple fields and want to enable field-targeted UX in clients. Absent when the error does not map to a single field. Examples: `slug`. |
| `message` | string | Yes | Human-readable description of the error. Examples: `limit must be between 1 and 100`. |


**404** — The specified resource was not found.

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `code` | string | Yes | Stable, snake_case token identifying the error condition. See ErrorCode for the api's canonical named vocabulary — this field is deliberately not restricted to it, since handlers may emit other ad-hoc codes not listed there (e.g. not_implemented). Examples: `invalid_argument`. |
| `field` | string | No | Optional hint identifying the request field the error refers to, in snake_case (e.g. "slug", "display_name", "token"). Set by handlers that validate multiple fields and want to enable field-targeted UX in clients. Absent when the error does not map to a single field. Examples: `slug`. |
| `message` | string | Yes | Human-readable description of the error. Examples: `limit must be between 1 and 100`. |


**409** — Run already terminal; nothing to cancel.

#### Security

bearer_jwt

---

### GET `/v1/runs/{run_id}` {#getrun}

**Get a job run.**

Returns a single job run by identifier.

#### Parameters

| Name | In  | Required | Type | Description |
| ---- | --- | -------- | ---- | ----------- |
| `X-Tenant-Slug` | header | Yes | string | Slug of the organization to scope the request to; required for user-authenticated requests. |
| `run_id` | path | Yes | integer | Identifier of the job run. |

#### Responses

**200** — The job run.

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `agent_id` | string | Yes | Identifier of the agent that executed the run. |
| `cmd_id` | [string null] | No | Correlation key from the cmd.execute_flow dispatch that started the run. Always present on the wire; null means the run was agent-local or CLI-started rather than dispatched by the control plane. Present alongside a null schedule_name, it means the run was dispatched and no schedule was recorded for it — with no claim about why. Examples: `0f3a9b6c-1d24-4c9e-8a71-5b2f0c8d4e13`. |
| `config_commit_sha` | [string null] | No | Full SHA of the configuration commit the run executed (ADR-129 decisions 1 and 11). Null with config_source draft means the agent did not hold a commit byte for byte. Absent or null with no config_source means unknown: the run was reported by an older agent that does not send its commit. Examples: `8f14e45fceea167a5a36dedd4bea2543c3a6f7b2`. |
| `config_source` | [string null] | No | Where the run's configuration came from. commit means the agent held the commit config_commit_sha byte for byte; draft means its configuration was written by a file-form deploy or a local edit, so it matches no commit and config_commit_sha is null. Absent or null means unknown: the run was reported by an older agent, never draft. Valid values are: `commit`, `draft`. Examples: `commit`. |
| `created_at` | string | Yes | Timestamp when the run record was created. |
| `duration_ms` | integer | No | Total run duration in milliseconds; absent while in progress. |
| `environment` | [string null] | No | DTAP environment slug the run ran in. |
| `error_count` | integer | No | Number of errors recorded during the run. |
| `finished_at` | string | No | Timestamp when the run finished; absent while in progress. |
| `job_name` | string | Yes | Name of the job that produced the run. Examples: `sales-to-dwh`. |
| `object_count` | integer | No | Number of objects processed by the run. |
| `organization_id` | string | Yes | Identifier of the owning organization. |
| `project` | [string null] | No | Project uuid the run is scoped to; resolved server-side from the source. |
| `rerun_of_run_id` | [integer null] | No | Identifier of the run this run repeats; set only when trigger is rerun. Null on every other run, and when the original run no longer exists. Examples: `20260412120000000`. |
| `run_id` | integer | Yes | Unique identifier of the run. Examples: `20260412120000000`. |
| `schedule_name` | [string null] | No | Name of the scheduled entry that dispatched the run, resolved server-side at ingest. Joins to ScheduleState.run_name, not to ScheduleState.schedule, which is a cron expression. Always present on the wire; null means no schedule name is recorded for this run, which cmd_id disambiguates — a null cmd_id means the run was agent-local and genuinely had no schedule, while a cmd_id with no schedule name means the run was dispatched and no schedule was recorded for it. That second case carries no claim about why, and must not be rendered as one. Examples: `nightly`. |
| `source` | [string null] | No | Name of the source that produced the run; resolved from agent-emitted names. |
| `started_at` | string | Yes | Timestamp when the run started. |
| `status` | string | Yes | Lifecycle status of the run. Examples: `finished`. |
| `strategy` | [string null] | No | Load strategy the run was dispatched with; the strategy actually applied per object is reported on its tasks. null = not reported (older agent or older run). Valid values are: `full`, `incremental`, `window`, `full_reload`. Examples: `incremental`. |
| `tables_failed` | integer | No | Number of tables that failed. |
| `tables_ok` | integer | No | Number of tables that completed successfully. |
| `tables_waiting` | integer | No | Number of tables the run loaded to staging and then stopped there because their classification waits (ObjectWaitReason): for a person's approval of a proposal (awaiting_approval), for a person's confirmation of a history rebuild (awaiting_rebuild_confirmation), or for a classification (awaiting_classification). A waiting table is not a failure, so a run with waiting tables can still read finished; this count is what keeps that partial load visible. Absent when the run did not report it (an agent or api older than this field). |
| `total_bytes` | integer | No | Total bytes processed across all tasks. |
| `total_rows` | integer | No | Total rows processed across all tasks. |
| `trigger` | string | No | How the run was started: manual by an operator, schedule by the scheduler, or rerun of the failed objects of an earlier run. Absent when the api does not report it. Valid values are: `manual`, `schedule`, `rerun`. Examples: `manual`. |
| `warning_count` | integer | No | Number of warnings recorded during the run. |


**401** — The request lacks valid credentials.

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `code` | string | Yes | Stable, snake_case token identifying the error condition. See ErrorCode for the api's canonical named vocabulary — this field is deliberately not restricted to it, since handlers may emit other ad-hoc codes not listed there (e.g. not_implemented). Examples: `invalid_argument`. |
| `field` | string | No | Optional hint identifying the request field the error refers to, in snake_case (e.g. "slug", "display_name", "token"). Set by handlers that validate multiple fields and want to enable field-targeted UX in clients. Absent when the error does not map to a single field. Examples: `slug`. |
| `message` | string | Yes | Human-readable description of the error. Examples: `limit must be between 1 and 100`. |


**404** — The specified resource was not found.

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `code` | string | Yes | Stable, snake_case token identifying the error condition. See ErrorCode for the api's canonical named vocabulary — this field is deliberately not restricted to it, since handlers may emit other ad-hoc codes not listed there (e.g. not_implemented). Examples: `invalid_argument`. |
| `field` | string | No | Optional hint identifying the request field the error refers to, in snake_case (e.g. "slug", "display_name", "token"). Set by handlers that validate multiple fields and want to enable field-targeted UX in clients. Absent when the error does not map to a single field. Examples: `slug`. |
| `message` | string | Yes | Human-readable description of the error. Examples: `limit must be between 1 and 100`. |


#### Security

bearer_jwt

---

### PUT `/v1/runs/{run_id}` {#updaterun}

**Update a job run.**

Updates the status and metrics of an existing job run.

#### Parameters

| Name | In  | Required | Type | Description |
| ---- | --- | -------- | ---- | ----------- |
| `run_id` | path | Yes | integer | Identifier of the job run. |

#### Request body _(required)_

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `duration_ms` | integer | No | Total run duration in milliseconds. |
| `error_count` | integer | No | Number of errors recorded during the run. |
| `finished_at` | string | No | Timestamp when the run finished. |
| `status` | string | Yes | New lifecycle status of the run. Examples: `finished`. |
| `tables_failed` | integer | No | Number of tables that failed. |
| `tables_ok` | integer | No | Number of tables that completed successfully. |
| `tables_waiting` | integer | No | Number of tables the run loaded to staging and then stopped there, waiting on their classification (ObjectWaitReason). Read back as Run.tables_waiting. An agent older than this field omits it. |
| `total_bytes` | integer | No | Total bytes processed across all tasks. |
| `total_rows` | integer | No | Total rows processed across all tasks. |
| `warning_count` | integer | No | Number of warnings recorded during the run. |


#### Responses

**200** — The job run was updated.

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `run_id` | integer | Yes | Identifier of the run. Examples: `20260412120000000`. |


**400** — The request was malformed or failed validation.

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `code` | string | Yes | Stable, snake_case token identifying the error condition. See ErrorCode for the api's canonical named vocabulary — this field is deliberately not restricted to it, since handlers may emit other ad-hoc codes not listed there (e.g. not_implemented). Examples: `invalid_argument`. |
| `field` | string | No | Optional hint identifying the request field the error refers to, in snake_case (e.g. "slug", "display_name", "token"). Set by handlers that validate multiple fields and want to enable field-targeted UX in clients. Absent when the error does not map to a single field. Examples: `slug`. |
| `message` | string | Yes | Human-readable description of the error. Examples: `limit must be between 1 and 100`. |


**401** — The request lacks valid credentials.

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `code` | string | Yes | Stable, snake_case token identifying the error condition. See ErrorCode for the api's canonical named vocabulary — this field is deliberately not restricted to it, since handlers may emit other ad-hoc codes not listed there (e.g. not_implemented). Examples: `invalid_argument`. |
| `field` | string | No | Optional hint identifying the request field the error refers to, in snake_case (e.g. "slug", "display_name", "token"). Set by handlers that validate multiple fields and want to enable field-targeted UX in clients. Absent when the error does not map to a single field. Examples: `slug`. |
| `message` | string | Yes | Human-readable description of the error. Examples: `limit must be between 1 and 100`. |


**404** — The specified resource was not found.

`application/json`

| Property | Type | Required | Description |
|---|---|---|---|
| `code` | string | Yes | Stable, snake_case token identifying the error condition. See ErrorCode for the api's canonical named vocabulary — this field is deliberately not restricted to it, since handlers may emit other ad-hoc codes not listed there (e.g. not_implemented). Examples: `invalid_argument`. |
| `field` | string | No | Optional hint identifying the request field the error refers to, in snake_case (e.g. "slug", "display_name", "token"). Set by handlers that validate multiple fields and want to enable field-targeted UX in clients. Absent when the error does not map to a single field. Examples: `slug`. |
| `message` | string | Yes | Human-readable description of the error. Examples: `limit must be between 1 and 100`. |


#### Security

bearer_jwt

---

