---
title: "List a journey's runs"
method: GET
path: "/projects/{projectId}/journeys/{journeyId}/runs"
tags: ["Swarm runs"]
---

# List a journey's runs

`GET /projects/{projectId}/journeys/{journeyId}/runs`

Newest first. Compact records — `attempts` is on the single-run read.

## Request body

- object
  - `cursor` string — Opaque pagination cursor from a previous response's `nextCursor`. Don't parse it.

## Response `200`

A page of runs.

- JourneyRunPage
  - `items` JourneyRun[], required
    - `id` string, required
    - `projectId` string, required
    - `journeyId` string, required
    - `waveId` string — The batch this run was launched with. Sibling runs of one co-launched wave share it; a solo relaunch is a wave of one. Absent on a run launched without one.
    - `status` 'running' | 'completed' | 'partial' | 'failed' | 'rate_limited', required — Poll until it leaves `running`.
    - `canceled` boolean, required — True when somebody STOPPED this run. **Check this before showing a run as a failure**: a cancelled run reports `status: "failed"`, because cancellation is recorded as a marker rather than a status of its own.
    - `stale` boolean, required — True when the runner went silent and the watchdog settled the run. Distinct from a run that failed while still reporting.
    - `error` string — Raw marker behind `canceled` / `stale`.
    - `summary` JourneyRunSummary, required
      - `total` integer, required — Targets × `sessionsPerTarget`, fixed at launch.
      - `succeeded` integer, required
      - `failed` integer, required
      - `rateLimited` integer, required
    - `targets` JourneyRunTarget[], required
      - `hostId` string, required
      - `hostName` string
      - `targetId` string — Execution identity. TWO TARGETS CAN SHARE A `hostId` — two environments may resolve to the same host with different servers — so this, not `hostId`, is what identifies a target within a run.
      - `modelId` string
    - `persona` object — The persona AS PINNED AT LAUNCH, from the run's immutable snapshot — not the persona's current values, which may have been edited since.
      - `personaId` string, nullable
      - `name` string, nullable
      - `role` string, nullable
    - `attempts` JourneyRunAttempt[] — Per-session execution records. Present on the single-run read only — lists stay compact.
      - `chatSessionId` string, nullable, required — `null` until the attempt claims a session.
      - `hostId` string, required
      - `targetId` string, nullable, required
      - `sessionIndex` integer, required
      - `status` 'pending' | 'running' | 'succeeded' | 'failed' | 'rate_limited', required — `pending` → `running` → terminal. A `pending` attempt cannot jump straight to a terminal state.
      - `errorCode` string, nullable, required
      - `errorMessage` string, nullable, required — Capped and redacted before it reaches this response.
    - `targetSummaries` object[] — The same counts as `summary`, broken down per target.
      - `hostId` string, required
      - `targetId` string
      - `total` integer, required
      - `succeeded` integer, required
      - `failed` integer, required
      - `rateLimited` integer, required
    - `createdAt` number, required — Epoch milliseconds.
    - `lastHeartbeatAt` number — Epoch milliseconds of the runner's last check-in. A long-stale heartbeat on a `running` run is what the watchdog acts on.
    - `insights` InsightsEnvelope — The common insights envelope, shared by eval runs, swarm waves and user-testing windows. One shape for three producers, so a caller writes the reading code once. An ABSENT envelope and `status: "not_available"` mean the same thing and both are normal: the field is an enrichment, and a caller who may not have it gets the resource without it rather than an error.
      - `schemaVersion` 1, required
      - `scope` InsightScope, required — What this envelope is about. The extra fields depend on `kind`.
        - `kind` 'eval_run' | 'swarm_wave' | 'user_testing_window', required
        - `id` string, required
        - `runId` string — `swarm_wave` only.
        - `scenarioId` string — `user_testing_window` only.
        - `windowStartAt` integer — `user_testing_window` only.
        - `windowEndAt` integer — `user_testing_window` only.
      - `status` 'not_available' | 'not_requested' | 'pending' | 'completed' | 'failed', required — `not_available` means this deployment cannot produce insights at all — treat an ABSENT envelope the same way. `not_requested` means nobody has asked. `pending` means one is running: poll, do not re-request.
      - `reasonCode` string, nullable, required
      - `retryable` boolean, required — Whether asking again could produce a different answer. False on a `failed` envelope means the input, not the attempt, was the problem.
      - `error` object, nullable, required
        - `code` string, required
        - `message` string, required
      - `generatedAt` integer, nullable, required
      - `updatedAt` integer, nullable, required
      - `summary` string, nullable, required
      - `coverage` object, required — READ THIS BEFORE QUOTING ANY FINDING. `truncated` and `lowConfidence` are the difference between "this happens" and "this happened in the part we looked at".
        - `unit` 'iterations' | 'sessions', required
        - `analyzed` integer, required
        - `total` integer, required
        - `gradedCount` integer
        - `feedbackCount` integer
        - `truncated` boolean, required — The analysis saw `analyzed` of `total`, not all of it.
        - `lowConfidence` boolean, required — Too little was analyzed to generalize. Findings still stand as observations of what WAS seen.
      - `findings` ActionableFinding[], required
        - `id` string, required — Stable remediation id (`rf_<16 hex>`). Survives dynamic error values, so the same problem keeps the same id across runs — dismiss it once and it stays dismissed.
        - `signalFingerprint` string, required — The registry signal this derives from. Several findings can share one.
        - `title` string, required
        - `category` 'unknown' | 'tool_contract' | 'tool_runtime' | 'capability_gap' | 'workflow' | 'agent_behavior' | 'test_design' | 'environment', required
        - `attribution` 'unknown' | 'server_contract' | 'server_runtime' | 'server_capability' | 'agent_or_prompt' | 'test_design' | 'environment', required — WHOSE problem this is. `server_*` points at the MCP server; `agent_or_prompt` and `test_design` point back at the caller.
        - `actionTarget` 'investigate' | 'mcp_server' | 'agent_configuration' | 'eval_case' | 'environment', required — What you would change to fix it.
        - `actionability` 'informational' | 'investigate' | 'ready', required — `ready` means the finding names a specific target and change. `investigate` means it does not yet. `informational` means there is nothing to do.
        - `severity` 'info' | 'low' | 'medium' | 'high', required
        - `confidence` 'low' | 'medium' | 'high', required
        - `observed` string, required — DETERMINISTIC observation — counts and identities, never model prose. This is the part you can verify yourself.
        - `rootCause` string
        - `recommendation` string, required
        - `acceptanceCriteria` string[], required — How you would know the fix worked.
        - `affected` object, required — How much of the analyzed population hit this. Read it as a ratio — `1/40` and `38/40` are different problems.
          - `count` integer, required
          - `total` integer, required
          - `unit` 'iterations' | 'sessions', required
        - `patternSlug` string
        - `target` object — Present only when a server (and, for tool surfaces, a tool) resolved against the pinned snapshot. Required for `mcp_server` / `ready`.
          - `serverId` string, required
          - `toolName` string
          - `surface` 'description' | 'input_schema' | 'output_schema' | 'handler' | 'server_instructions' | 'capability', required
          - `fieldPath` string
          - `snapshotHash` string, required — The pinned snapshot the target resolved against, so a finding cannot silently re-point at a definition that changed after it was written.
          - `currentDefinition` object
            - `description` string
            - `inputSchemaJson` string
            - `outputSchemaJson` string
            - `truncated` boolean, required
        - `evidence` ActionableFindingEvidence[], required
          - `sessionId` string
          - `iterationId` string
          - `kind` 'tool_error' | 'transcript' | 'feedback' | 'judge' | 'contrast', required
          - `excerpt` string, required — Scrubbed and clipped at the producer. Never a full transcript.
          - `toolName` string
          - `errorCode` string
      - `runHealth` object — Swarm only. Launch outcomes never appear as findings — a run that could not start is an operational fact, not something the server under test did.
        - `targets` object[], required
          - `subjectKind` 'environment' | 'host', required
          - `subjectId` string, required
          - `subjectLabel` string, required
          - `attempted` integer, required
          - `succeeded` integer, required
          - `failed` integer, required
          - `rateLimited` integer, required
      - `truncation` object, required — What this RESPONSE dropped to stay a sane size, as distinct from what the ANALYSIS did not look at (`coverage`).
        - `truncated` boolean, required
        - `omittedFindings` integer, required
        - `omittedEvidence` integer, required
        - `contractTruncated` boolean, required
  - `nextCursor` string — Present only when another page exists.

## 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)
