# Get a test run (/docs/api/voice-agents/agent-tests/getAgentTestRun)

> For the complete documentation index, see [llms.txt](https://docs.tandemcx.ai/llms.txt). Any page on this site can be fetched as Markdown by appending `.md` to its URL.

`GET /v1/agent-media/agents/{agentId}/test-runs/{runId}`

Get a test run

The run with every case result recorded so far. A case appears in `results` once it finishes; `run.counts.done` counts them.

## Request

**Base URL:** `https://api.tandemcx.ai`

**Authentication:** `Authorization: Bearer <token>` — A Tandem bearer token. Requests are scoped to the organization the token belongs to; no organization header is required.

### Path parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `agentId` | string | Yes | The agent's unique ID. |
| `runId` | string | Yes | The test run's unique ID. |

## Responses

### 200 — The run and its results.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `run` | object | No | — |
| `run.runId` | string | No | — |
| `run.agentId` | string | No | — |
| `run.version` | string | No | — |
| `run.configHash` | string | No | SHA-256 of the version's configuration when the run started. A version whose current hash differs was edited since. |
| `run.testIds` | array of string | No | — |
| `run.repeats` | object | No | Attempts queued per test id. Invalid tests are absent. |
| `run.status` | enum: `queued` \| `running` \| `passed` \| `failed` \| `errored` \| `cancelled` | No | A finished run is `failed` when any case failed, else `errored` when any case errored, else `passed`. `invalid` cases never fail a run. |
| `run.counts` | object | No | Cases, where a case is one attempt of one test. |
| `run.counts.total` | integer | No | — |
| `run.counts.done` | integer | No | — |
| `run.counts.pass` | integer | No | — |
| `run.counts.fail` | integer | No | — |
| `run.counts.error` | integer | No | — |
| `run.counts.invalid` | integer | No | — |
| `run.usage` | object | No | — |
| `run.usage.inputTokens` | integer | No | — |
| `run.usage.outputTokens` | integer | No | — |
| `run.simulatorModelId` | string | No | The Bedrock model id the run's simulated caller uses. |
| `run.judgeModelId` | string | No | The Bedrock model id the run's judge uses. |
| `run.agentTemperature` | number | No | — |
| `run.triggeredBy` | object | No | — |
| `run.triggeredBy.kind` | enum: `user` \| `sparky` | No | — |
| `run.triggeredBy.userId` | string | No | — |
| `run.createdAt` | string (date-time) | No | — |
| `run.finishedAt` | string (date-time) | No | — |
| `run.ttl` | integer | No | Epoch seconds when the run expires, 90 days after it started. |
| `results` | array of object | No | — |
| `results[].runId` | string | No | — |
| `results[].testId` | string | No | — |
| `results[].attempt` | integer | No | — |
| `results[].outcome` | enum: `pass` \| `fail` \| `error` \| `invalid` | No | `pass` when every check and criterion passed; `fail` when one did not. `error` means the case could not finish (a failed turn, simulator, or judge, or the version changed mid-run) and says nothing about the agent. `invalid` means the test does not fit the version and never ran. |
| `results[].endReason` | enum: `script_done` \| `agent_ended` \| `handed_off` \| `caller_done` \| `max_turns` \| `error` | No | — |
| `results[].checks` | array of object | No | — |
| `results[].checks[].index` | integer | No | — |
| `results[].checks[].pass` | boolean | No | — |
| `results[].checks[].detail` | string | No | — |
| `results[].criteria` | array of object | No | — |
| `results[].criteria[].index` | integer | No | — |
| `results[].criteria[].pass` | boolean | No | — |
| `results[].criteria[].reason` | string | No | — |
| `results[].criteria[].turnIndex` | integer | No | The transcript line the judge cited, when it cited one. |
| `results[].transcriptKey` | string | No | — |
| `results[].error` | string | No | Why the case is `error` or `invalid`, in words a user can read. |
| `results[].usage` | object | No | — |
| `results[].usage.inputTokens` | integer | No | — |
| `results[].usage.outputTokens` | integer | No | — |
| `results[].createdAt` | string (date-time) | No | — |
| `results[].ttl` | integer | No | Epoch seconds when the result expires. |

### 400 — The request was malformed. `error` names the reason, such as `invalid_agentId`, `invalid_version`, `invalid_slot`, or `invalid_prompt`.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `error` | string | No | A stable machine-readable code. |
| `message` | string | No | A human-readable explanation, safe to show to an end user. Present on errors an operator can act on; browser clients display this field in preference to a generic fallback. |
| `limit` | integer | No | Present on some errors (e.g. `prompt_too_long`) that reject a value against a fixed bound: the bound itself. |
| `length` | integer | No | Present on some errors (e.g. `prompt_too_long`) that reject a value against a fixed bound: the measured size of the rejected value. |
| `reason` | string | No | Present on some errors (e.g. `invalid_avatar_image`) that have more than one cause: which one applied. |

### 401 — Missing, malformed, or expired bearer token.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `error` | string | No | A stable machine-readable code. |
| `message` | string | No | A human-readable explanation, safe to show to an end user. Present on errors an operator can act on; browser clients display this field in preference to a generic fallback. |
| `limit` | integer | No | Present on some errors (e.g. `prompt_too_long`) that reject a value against a fixed bound: the bound itself. |
| `length` | integer | No | Present on some errors (e.g. `prompt_too_long`) that reject a value against a fixed bound: the measured size of the rejected value. |
| `reason` | string | No | Present on some errors (e.g. `invalid_avatar_image`) that have more than one cause: which one applied. |

### 404 — `error` is `not_found`: the resource does not exist.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `error` | string | No | A stable machine-readable code. |
| `message` | string | No | A human-readable explanation, safe to show to an end user. Present on errors an operator can act on; browser clients display this field in preference to a generic fallback. |
| `limit` | integer | No | Present on some errors (e.g. `prompt_too_long`) that reject a value against a fixed bound: the bound itself. |
| `length` | integer | No | Present on some errors (e.g. `prompt_too_long`) that reject a value against a fixed bound: the measured size of the rejected value. |
| `reason` | string | No | Present on some errors (e.g. `invalid_avatar_image`) that have more than one cause: which one applied. |
