---
title: "List run iterations"
method: GET
path: "/projects/{projectId}/eval-runs/{runId}/iterations"
tags: ["Eval runs"]
---

# List run iterations

`GET /projects/{projectId}/eval-runs/{runId}/iterations`

Per-iteration results: actual tool calls, structured token usage, and latency. Cursor-paginated.

## Path parameters

- `projectId` string, required
- `runId` string, required

## Query parameters

- `limit` integer
- `cursor` string

## Response `200`

One page of iterations.

- EvalIterationPage
  - `items` EvalIteration[], required
    - `id` string, required
    - `testCaseId` string, nullable
    - `title` string, nullable
    - `iterationNumber` integer, required
    - `status` 'pending' | 'running' | 'completed' | 'failed' | 'cancelled', required
    - `result` 'passed' | 'failed' | 'null', nullable
    - `model` string, nullable
    - `provider` string, nullable
    - `startedAt` number, nullable — Epoch milliseconds.
    - `durationMs` number, nullable — Wall-clock duration; `null` until terminal.
    - `tokensUsed` number, nullable
    - `usage` object, nullable — Structured token usage (input/output/cached/reasoning) when available.
    - `actualToolCalls` object[], required
    - `expectedToolCalls` object[], required
    - `error` string, nullable
    - `scores` ScoreResult[], nullable — Per-scorer verdicts for this iteration. `null` when the run predates scoring, or when the stored payload failed validation at the boundary — partially-trusted score data is never projected.
      - `scorerId` string, required
      - `scorerVersion` string, required
      - `definitionHash` string, required — Joins this result to its definition in `evaluationConfig.definitions`.
      - `status` 'scored' | 'error' | 'skipped' | 'not_applicable', required — `error` is never a low score — a crashed judge is not a disagreeing judge. `not_applicable` never gates and is excluded from aggregation denominators, which is what distinguishes it from `skipped`.
      - `value` number — Present only when `status` is `scored`.
      - `passThreshold` number, required
      - `passed` boolean — Derived as `value >= passThreshold`; present only when `status` is `scored`.
      - `rationale` string
      - `evidence` string[]
      - `deterministic` boolean, required
      - `model` string
      - `promptHash` string
      - `error` string — Present only when `status` is `error`.
      - `scope` object — Absent means case-level; `{kind:"turn",promptIndex}` means the check was authored on a single turn.
    - `evaluationConfig` EvaluationConfigSnapshot — The scorer definitions a run graded with, plus their hash. Changing scorer configuration changes this hash but NOT the case identity — a threshold edit must not fork a scenario's history.
      - `hash` string, required — `evaluationConfigHash` over the resolved definitions. Order-independent — the hash sorts internally.
      - `definitions` ResolvedScoreDefinition[], required
        - `scorerId` string, required
        - `idSource` 'explicit' | 'generated', required — `generated` ids are positional and UNSTABLE across config edits; only `explicit` ids may be referenced by a gate policy or tracked across runs.
        - `scorerVersion` string, required
        - `implementationHash` string, required — Digest of what the scorer actually does — the canonicalized predicate, or the judge prompt plus template version. Required so two judges with different prompts cannot hash identically.
        - `label` string — Presentation only; deliberately excluded from the hash.
        - `deterministic` boolean, required
        - `passThreshold` number, required
        - `role` 'gating' | 'advisory', required — Only `gating` scorers decide the iteration's verdict.
        - `onError` 'fail' | 'ignore', required — What an `error` status does to a gating iteration. Defaults to `fail`.
        - `onSkipped` 'fail' | 'ignore', required — What a `skipped` status does to a gating iteration. Separate from `onError`: a crashed judge and a judge that never ran are different failures.
        - `model` string
        - `scope` object
    - `scoreIntegrity` 'score_integrity_invalid' | 'null', nullable — Set when the backend downgraded this iteration's verdict because its gating score evidence was malformed.
  - `nextCursor` string — Opaque cursor for the next page. Omitted on the last page.

## Other responses

- `401` — Missing, invalid, revoked, or orphaned key (`UNAUTHORIZED`) — or the **target MCP server** needs an OAuth grant (`OAUTH_REQUIRED`), which is a property of the server, not your key.
- `403` — Key is valid but not allowed to do this.
- `404` — Unknown project, server, or resource.
- `429` — Per-key rate limit exceeded (60 requests/minute sustained, bursts up to 10). Honor `Retry-After` and back off with jitter.
- `500` — Something failed on MCPJam's side.

---

[API](https://skmtc.net/mcpjam/apis/mcpjam-api.md) · [All operations](https://skmtc.net/mcpjam/apis/mcpjam-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/mcpjam/mcpjam-api/revisions/d3adfe49fbbf/schema)
