# REST API reference

URL: https://testmode.ai/docs/rest-api/

> Testmode's REST API at api.testmode.ai: authenticate with a project API key, list environments, test plans and test cases, start runs and poll their results. Endpoints, bodies, responses and errors.

The REST API starts runs and reads results for one project. It is what the GitHub Action uses, and works from any CI or script.

## Basics

- **Base URL:** `https://api.testmode.ai`
- **Authentication:** a [project API key](https://testmode.ai/docs/api-keys/), as `Authorization: Bearer tmk_…` (or `X-Api-Key: tmk_…`).
- **Format:** JSON in, JSON out.
- **Rate limit:** 60 requests a minute per key; over it, `429` with `Retry-After`.
- **Not for browsers:** the API answers no CORS requests. Call it from servers and pipelines, where the key stays secret.

## Endpoints

| Method and path | Returns |
| --- | --- |
| `GET /v1/project` | The project, its environments and its test plans |
| `GET /v1/environments` | `{ environments: [{ id, name, baseUrl, isDefault }] }` |
| `GET /v1/test-plans` | `{ testPlans: [{ id, name, description, testCaseCount }] }` |
| `GET /v1/test-cases?tag=&search=` | `{ testCases: [{ id, name, tags, enabled }], truncated }`: oldest first, at most 500 |
| `POST /v1/runs` | The new run, with HTTP 201 |
| `GET /v1/runs?limit=` | `{ runs: [...] }`: newest first, at most 100 |
| `GET /v1/runs/:id` | The run with its tests |

## Start a run

```bash
curl -X POST https://api.testmode.ai/v1/runs \
  -H "Authorization: Bearer $TESTMODE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "environment": "Staging", "testPlan": "Smoke", "name": "PR #42" }'
```

The body:

| Field | Meaning |
| --- | --- |
| `environment` | Environment id or name. Default: the project's default environment, else the first. |
| `testPlan` | Test plan id or name. |
| `testCaseIds` | An array of test case ids. |
| `tags` | An array of tags: every enabled test case with any of them, at most 500. |
| `name` | Optional run name, up to 200 characters. |

Give exactly one of `testPlan`, `testCaseIds` or `tags`. Names match exactly, ignoring case; an ambiguous name is refused, so pass the id. Tags ignore case.

`POST /v1/runs` is not idempotent: a retry starts, and counts, a second run. A `500` that still carries `id` and `url` means the run started but couldn't be read back: follow that run instead of posting again.

## Read a run

```bash
curl https://api.testmode.ai/v1/runs/$RUN_ID \
  -H "Authorization: Bearer $TESTMODE_API_KEY"
```

```json
{
  "id": "…", "name": "PR #42", "status": "RUNNING", "finished": false,
  "totalTests": 3, "passedTests": 1, "failedTests": 0,
  "startedAt": "…", "finishedAt": null, "durationMs": null, "skipReason": null,
  "url": "https://app.testmode.ai/results/…",
  "tests": [
    { "id": "…", "testCaseId": "…", "name": "Checkout", "status": "PASSED",
      "durationMs": 21000, "summary": "…", "url": "…" }
  ]
}
```

- `status` is `QUEUED`, `RUNNING`, `PASSED`, `FAILED` or `SKIPPED`, for the run and for each test.
- `finished` is `true` once the run can no longer change. Poll until then; every 15 seconds is plenty.
- `summary` is each test's one-line result. It names variables as <code>{"{{Name}}"}</code>, never their values.
- `url` opens the run, or the test, in the app.

## Errors

Errors are `{ "error": "…" }` with one of these statuses:

| Status | Meaning |
| --- | --- |
| `400` | The request is invalid, such as no or several of `testPlan`, `testCaseIds` and `tags`, or nothing to run. |
| `401` | No key, an unknown key, or an expired one. |
| `402` | Not enough test runs: `code: "insufficient_credits"`, with `required` and `available`. |
| `403` | The key's creator can no longer start runs. |
| `404` | No such environment, plan, test case or run in this project. |
| `429` | Over the rate limit; wait for `Retry-After` seconds. |
| `500` | Something failed on our side. |

## Related

- [Run tests from GitHub Actions and other CI](https://testmode.ai/docs/github-action/): A ready-made client for pipelines.
- [API keys](https://testmode.ai/docs/api-keys/): Create and revoke keys.
- [Run, test and exploration statuses](https://testmode.ai/docs/run-and-test-statuses/): What each status means.
