# GET /v1/deployments/{deployment_id}/test-runs

> Past test runs.

In [Tests API](https://vestra.ai/developers/reference/api/tests.md): The scenarios a version must pass, drafted or written, and the runs that check it before your users see it.

Send `Authorization: Bearer vk_test_...` on every call.

Past test runs.

Your API key, scope `setup` or `all`. On the card: [`test`](https://vestra.ai/developers/test.md). Over HTTP it is made from the contract: fill in each {…} and every value.

## Request

Path:

- `deployment_id` (`string`, required): The deployment's id (`dep_...`). The /v1/deployments routes also take its name.

Query:

- `limit` (`integer`): How many items per page, 1 to 100. Default 20.
- `cursor` (`string`): Where to go on from: the `next_cursor` of the page before, unchanged. Absent: the first page.

## Answers 200

- `data` (`object[]`): The items on this page.
  - `id` (`string`): The test run's id. Example: `trun_8f2k`.
  - `object` (`"test_run"`): Always `test_run`.
  - `deployment_id` (`string`): The deployment it tests.
  - `version` (`integer`): The version it tests.
  - `status` (`"queued" | "running" | "passed" | "failed" | "error"`): `queued` or `running` while it plays. `passed`: every scenario passed. `failed`: one or more did not. `error`: it could not finish, as `error_code` says.
  - `error_code` (`string | null`): Why it ended in `error`: `interrupted` (a restart stopped it too often), `test_wallet_empty`, `judge_unreadable` (the grader's answer could not be read) or `internal`. Null otherwise.
  - `scenario_count` (`integer`): How many scenarios it plays.
  - `passed_count` (`integer`): How many have passed so far.
  - `resumes` (`integer`): How many times a restart interrupted it and it played on from where it was, at most 2.
  - `promoted` (`object | null`): What its pass promoted, for an apply that promotes after its tests; null when it promoted nothing (none asked, refused, or it did not pass).
    - `mode` (`"live" | "test"`): The mode the version went live in.
    - `version` (`integer`): The version that went live.
  - `became_default` (`boolean`): True when that promotion made the deployment the company's default: an ask with no deployment now reaches it.
  - `cost_usd` (`number`): What the run cost, in billed US dollars.
  - `created_at` (`string`): When it was asked for, as an ISO 8601 date and time in UTC.
  - `started_at` (`string | null`): When it began to play; null while queued.
  - `finished_at` (`string | null`): When it ended; null while it plays.
  - `results` (`object[]`, may be absent): Each scenario's result, on GET /v1/test-runs/{test_run_id}; absent in lists.
    - `object` (`"test_result"`): Always `test_result`.
    - `scenario_id` (`string | null`): The scenario it played; null when the scenario was deleted since.
    - `scenario` (`object`): The scenario as it was played.
    - `verdict` (`"passed" | "failed" | "error"`): `passed`: every line of success met and nothing it must never do. `failed`: not so. `error`: it could not be played to the end.
    - `reason` (`string`): Why, in a sentence or two.
    - `criteria` (`object[]`): Each line of success, graded.
    - `must_never` (`object[]`): Each thing it must never do, graded.
    - `approvals_asked` (`object[]`): What Bash asked the test user's yes for, and what it said.
    - `transcript` (`object[]`): The conversation, line by line.
    - `conversation_id` (`string | null`): The test conversation; null when it never started.
    - `cost_usd` (`number`): What playing it cost, in billed US dollars.
- `next_cursor` (`string | null`): Send it as `cursor` for the next page; null on the last page.

## Code

**HTTP**

```bash
curl "$VESTRA_BASE_URL/v1/deployments/{deployment_id}/test-runs" \
  -H "Authorization: Bearer $VESTRA_API_KEY"
```

**TypeScript, Python, CLI, MCP**: No sample in your language for this route, so here it is over HTTP.
