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

# Run endpoints

> Create, inspect, cancel, and promote backtest and paper-trading runs — the core execution surface of Ithaca.

A **run** is a single execution of a strategy — either a backtest or a paper-trading deployment. Runs are created by agents (backtests) and promoted by humans (paper trading).

## List runs

```http theme={null}
GET /api/runs?kind=backtest
Authorization: Bearer <token>
```

| Query param | Type   | Description                                |
| ----------- | ------ | ------------------------------------------ |
| `kind`      | string | Optional. Filter by `backtest` or `paper`. |

### Response

```json theme={null}
{
  "runs": [
    {
      "id": "run_abc",
      "kind": "backtest",
      "status": "succeeded",
      "spec_id": "spec_xyz",
      "spec_version": 3,
      "tenant_id": "tnt_abc",
      "created_at": "2025-01-15T12:00:00Z"
    }
  ]
}
```

## Get a run

```http theme={null}
GET /api/runs/{id}
Authorization: Bearer <token>
```

Returns the full run record plus a **shaped trace** — the trace events for this run, ordered by `seq`, ready for the web UI to render.

### Response

```json theme={null}
{
  "id": "run_abc",
  "kind": "backtest",
  "status": "succeeded",
  "spec": { "spec_version": "1.0", "...": "..." },
  "result_hash": "sha256:9f2c...",
  "trace": [
    { "seq": 1, "type": "job_queued", "ts": "..." },
    { "seq": 2, "type": "run_transition", "ts": "...", "data": { "to": "running" } },
    { "seq": 3, "type": "run_progress", "ts": "...", "data": { "pct": 0.5 } },
    { "seq": 4, "type": "artifact_created", "ts": "..." }
  ],
  "created_at": "2025-01-15T12:00:00Z",
  "finished_at": "2025-01-15T12:00:12Z"
}
```

## Get paper positions

```http theme={null}
GET /api/runs/{id}/book
Authorization: Bearer <token>
```

Returns the current paper-trading positions for a promoted run. Only valid for runs with `kind: "paper"`.

### Response

```json theme={null}
{
  "run_id": "run_abc",
  "positions": [
    { "symbol": "NVDA", "weight": 0.32, "shares": 120, "cost_basis": 480.10 }
  ],
  "cash": 1234.56,
  "as_of": "2025-01-15T16:00:00Z"
}
```

## Create a backtest run

```http theme={null}
POST /api/runs
Authorization: Bearer <token>
Content-Type: application/json
```

```json theme={null}
{
  "kind": "backtest",
  "spec_id": "spec_xyz",
  "spec_version": 3
}
```

| Field          | Type    | Required | Description                                                                      |
| -------------- | ------- | -------- | -------------------------------------------------------------------------------- |
| `kind`         | enum    | yes      | `backtest` (agents can also create `paper` requests, but they require approval). |
| `spec_id`      | string  | yes      | The strategy spec to run.                                                        |
| `spec_version` | integer | yes      | The immutable version to pin.                                                    |

### Response

```json theme={null}
{
  "id": "run_abc",
  "kind": "backtest",
  "status": "queued",
  "spec_id": "spec_xyz",
  "spec_version": 3,
  "created_at": "2025-01-15T12:00:00Z"
}
```

Requires the `runs:write` scope.

## Cancel a run

```http theme={null}
POST /api/runs/{id}/cancel
Authorization: Bearer <token>
```

Cancels a run that is `queued` or `running`. Emits a `run_transition` event to `cancelled`. Requires the `runs:cancel` scope.

### Response

```json theme={null}
{ "id": "run_abc", "status": "cancelled" }
```

## Promote a run

```http theme={null}
POST /api/runs/{id}/promote
Authorization: Bearer <clerk-jwt>
Content-Type: application/json
```

```json theme={null}
{ "scope": "paper" }
```

<Callout type="warn">
  Promotion is **human-only**. An API key (agent) calling this endpoint is rejected with `403`. The endpoint checks `actor_kind === "human"`.
</Callout>

Promotion creates an approval record in the `pending` state and emits an `approval_requested` trace event. The actual deployment happens only after a human approves via [Approval endpoints](/api/approvals). See [Approval workflow](/strategy/approvals).

### Response

```json theme={null}
{
  "run_id": "run_abc",
  "approval_id": "apr_def",
  "state": "pending",
  "scope": "paper"
}
```

## Run state machine

```
draft → queued → running → succeeded
                         → failed
                         → timeout
                         → cancelled
```

For paper runs after approval:

```
pending_approval → paper_active → paper_stopped
```

| Transition                   | Trigger                           |
| ---------------------------- | --------------------------------- |
| `draft → queued`             | Run enqueued by `POST /api/runs`. |
| `queued → running`           | Worker leases the job.            |
| `running → succeeded`        | Kernel completes.                 |
| `running → failed`           | Kernel raises.                    |
| `running → timeout`          | Wall-clock budget exceeded.       |
| `queued/running → cancelled` | `POST /api/runs/{id}/cancel`.     |

Every transition emits a `run_transition` trace event. See [Trace events](/api/runs).

## Related

* [Backtest system](/strategy/backtest) — how the kernel works
* [StrategySpec](/strategy/spec) — the input to a run
* [Approval workflow](/strategy/approvals) — the promote flow
* [Events & SSE](/api/runs) — streaming run events live
