# Cases and steps API

Source: https://docs.qualflare.com/docs/api/cases · Last updated: 2026-11-03

Read, create and update test cases and their steps over the Qualflare REST API, including a bulk create of up to 20 cases, with every parameter and field.

The Cases and steps API lets you read, create and update test cases and their steps in a Qualflare project over REST at `https://api.qualflare.com/api/v1`, authenticated with a project access token.

|               |                                                                                                                                                                                                                                         |
| ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Base path** | `/api/v1/suite/{suiteSeq}/cases`, `/api/v1/case/{caseSeq}` and `/api/v1/case/{caseSeq}/steps`                                                                                                                                           |
| **Reads**     | Any token. Token creator: (requires the Viewer role or higher in the project)                                                                                                                                                           |
| **Writes**    | Creating and updating cases and steps: a token created with **Allow writes**. Token creator: (requires the Editor role or higher in the project)                                                                                        |
| **Pages**     | None: a suite's cases and a case's steps come back whole                                                                                                                                                                                |
| **Limits**    | [Rate limits and request sizes](https://docs.qualflare.com/docs/api/limits)                                                                                                                                                             |
| **Errors**    | [Errors and status codes](https://docs.qualflare.com/docs/api/errors)                                                                                                                                                                   |
| **CLI**       | `qf <identifier> cases list --suite <seq>`, `qf <identifier> case get <seq>`, `qf <identifier> case steps <seq>` ([Cases commands](https://docs.qualflare.com/docs/cli/read-commands#cases))                                            |
| **MCP**       | `list_suite_cases`, `get_test_case`, `list_case_steps`, `create_test_case`, `update_test_case`, `bulk_create_cases`, `create_case_step`, `update_case_step` ([MCP server reference](https://docs.qualflare.com/docs/api/mcp-reference)) |

The eight endpoints, each with its own section below:

| Endpoint                                       | What it does                                                                                        |
| ---------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| **GET** `/api/v1/suite/{suiteSeq}/cases`       | [List a suite's cases](https://docs.qualflare.com/docs/api/cases#list-suite-cases)  |
| **GET** `/api/v1/case/{caseSeq}`               | [Get a case](https://docs.qualflare.com/docs/api/cases#get-case)                    |
| **POST** `/api/v1/suite/{suiteSeq}/cases`      | [Create a case](https://docs.qualflare.com/docs/api/cases#create-case)              |
| **PUT** `/api/v1/case/{caseSeq}`               | [Update a case](https://docs.qualflare.com/docs/api/cases#update-case)              |
| **POST** `/api/v1/suite/{suiteSeq}/cases/bulk` | [Create cases in bulk](https://docs.qualflare.com/docs/api/cases#bulk-create-cases) |
| **GET** `/api/v1/case/{caseSeq}/steps`         | [List a case's steps](https://docs.qualflare.com/docs/api/cases#list-steps)         |
| **POST** `/api/v1/case/{caseSeq}/steps`        | [Add a step](https://docs.qualflare.com/docs/api/cases#create-step)                 |
| **PUT** `/api/v1/case/{caseSeq}/step/{id}`     | [Update a step](https://docs.qualflare.com/docs/api/cases#update-step)              |

## List a suite's cases

List a suite's cases returns every case of one suite that matches your filters.

**GET** `/api/v1/suite/{suiteSeq}/cases`

Needs a project access token whose creator has the Viewer role or higher in the project.

| Name       | Type             | Default | Required | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| ---------- | ---------------- | ------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `suiteSeq` | `path`, integer  |         | Yes      | The suite number                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `q`        | `query`, string  |         | No       | Text to look for in case names, up to 255 characters                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `state`    | `query`, string  |         | No       | A state: `active`, `review`, `outdated` or `draft`. Repeat it for more, up to 20                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `priority` | `query`, string  |         | No       | A priority: `low`, `medium`, `high` or `critical`. Repeat it for more, up to 10                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `testType` | `query`, string  |         | No       | A test type: `unit`, `regression`, `integration`, `feature`, `e2e`, `component`, `contract`, `api`, `performance`, `ui`, `snapshot`, `accessibility`, `smoke`, `resilience`, `vulnerability`, `penetration`, `bdd`, `security`, `generic`, `junit`, `python`, `golang`, `jest`, `mocha`, `vitest`, `rspec`, `phpunit`, `testng`, `cucumber`, `karate`, `playwright`, `cypress`, `selenium`, `testcafe`, `maestro`, `xctest`, `espresso`, `webdriverio`, `appium`, `flutter`, `newman`, `k6`, `zap`, `trivy`, `snyk` or `sonarqube`. Repeat it for more, up to 10 |
| `sortBy`   | `query`, string  | `seq`   | No       | `seq`, `name`, `createdAt`, `updatedAt`, `flakyScore` or `position` (the order in the suite)                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `sortDir`  | `query`, boolean | `false` | No       | `true` sorts in descending order                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |

```bash
curl -sS "https://api.qualflare.com/api/v1/suite/12/cases?state=active&state=draft" \
  -H "Authorization: Bearer $QF_TOKEN"
```

Returns `200`: `items` and `total`: every matching case of the suite, with no pages.

* The answer is `items` and `total`, every matching case in the suite, with no pages.
* `suiteName` is empty in this list; [Get a case](https://docs.qualflare.com/docs/api/cases#get-case) fills it in.

## Get a case

Get a case returns one test case by its number.

**GET** `/api/v1/case/{caseSeq}`

Needs a project access token whose creator has the Viewer role or higher in the project.

| Name      | Type            | Default | Required | Description     |
| --------- | --------------- | ------- | -------- | --------------- |
| `caseSeq` | `path`, integer |         | Yes      | The case number |

```bash
curl -sS "https://api.qualflare.com/api/v1/case/101" \
  -H "Authorization: Bearer $QF_TOKEN"
```

Returns `200`: The case.

```json
{
  "seq": 101,
  "position": 4,
  "uid": "User can apply a coupon at checkout",
  "name": "User can apply a coupon at checkout",
  "description": "A 10% coupon lowers the order total before tax.",
  "state": "active",
  "priority": "high",
  "testType": "e2e",
  "automation": "manual",
  "isFavorite": false,
  "isFlaky": false,
  "flakyScore": 0,
  "mark": "none",
  "isArchived": false,
  "suiteSeq": 12,
  "suiteName": "Checkout",
  "createdAt": "2026-09-14T08:40:12Z",
  "updatedAt": "2026-10-21T16:05:57Z"
}
```

* A number that isn't a case of the project answers `404` with `case not found`.

## Create a case

Create a case adds a test case to a suite and sets only its name.

**POST** `/api/v1/suite/{suiteSeq}/cases`

Needs a project access token created with Allow writes, whose creator has the Editor role or higher in the project.

| Name       | Type            | Default | Required | Description                                                             |
| ---------- | --------------- | ------- | -------- | ----------------------------------------------------------------------- |
| `suiteSeq` | `path`, integer |         | Yes      | The suite number                                                        |
| `name`     | `body`, string  |         | Yes      | The case name, 1 to 255 characters, that no other case in the suite has |

```bash
curl -sS -X POST "https://api.qualflare.com/api/v1/suite/12/cases" \
  -H "Authorization: Bearer $QF_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "User can reset a forgotten password"}'
```

Returns `201`: The new case.

* Only `name` is set (1 to 255 characters); the case starts as a Draft, Low-priority, E2E, manual case. Set the rest with [Update a case](https://docs.qualflare.com/docs/api/cases#update-case).
* A name already in the suite answers `409`.
* Each case counts toward your plan's test cases; at the limit the API answers `402` with `Test Cases quota exceeded (<used>/<limit>)`.

## Update a case

Update a case changes the name, description, state or priority of a test case.

**PUT** `/api/v1/case/{caseSeq}`

Needs a project access token created with Allow writes, whose creator has the Editor role or higher in the project.

| Name          | Type            | Default | Required | Description                                       |
| ------------- | --------------- | ------- | -------- | ------------------------------------------------- |
| `caseSeq`     | `path`, integer |         | Yes      | The case number                                   |
| `name`        | `body`, string  |         | No       | Up to 255 characters                              |
| `description` | `body`, string  |         | No       | Up to 1,024 characters; longer text fails to save |
| `state`       | `body`, string  |         | No       | `active`, `review`, `outdated` or `draft`         |
| `priority`    | `body`, string  |         | No       | `low`, `medium`, `high` or `critical`             |

```bash
curl -sS -X PUT "https://api.qualflare.com/api/v1/case/101" \
  -H "Authorization: Bearer $QF_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"state": "active", "priority": "high"}'
```

Returns `200`: The updated case.

* Send only the fields to change: `name`, `description` (up to 1,024 characters; longer text fails to save), `state`, `priority`.
* A body with none of them changes nothing and returns the case.

## Create cases in bulk

Create cases in bulk adds up to 20 test cases to one suite in one request.

**POST** `/api/v1/suite/{suiteSeq}/cases/bulk`

Needs a project access token created with Allow writes, whose creator has the Editor role or higher in the project.

| Name       | Type            | Default | Required | Description                                                                                                                                             |
| ---------- | --------------- | ------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `suiteSeq` | `path`, integer |         | Yes      | The suite number                                                                                                                                        |
| `cases`    | `body`, array   |         | Yes      | 1 to 20 cases, each a `title` of 5 to 255 characters, an optional `description` of up to 1,024 characters and an optional `priority` (default `medium`) |

```bash
curl -sS -X POST "https://api.qualflare.com/api/v1/suite/12/cases/bulk" \
  -H "Authorization: Bearer $QF_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"cases": [{"title": "Reset link expires after one hour", "priority": "high"}, {"title": "Reset link works only once"}]}'
```

Returns `201`: `suiteSeq`, `count` and `caseSeqs`, the numbers of the new cases.

* 1 to 20 cases, each with a `title` of 5 to 255 characters, an optional `description` (up to 1,024 characters; longer text fails to save) and an optional `priority` (default `medium`). They start as Draft, Unit, manual cases.
* All or none: if the batch would pass your plan's test-case limit, nothing is created.
* The answer is `suiteSeq`, `count` and `caseSeqs`.

## List a case's steps

List a case's steps returns an array of every step of the case, in order; a shared step carries `sharedStep` with its own `items`.

**GET** `/api/v1/case/{caseSeq}/steps`

Needs a project access token whose creator has the Viewer role or higher in the project.

| Name      | Type            | Default | Required | Description     |
| --------- | --------------- | ------- | -------- | --------------- |
| `caseSeq` | `path`, integer |         | Yes      | The case number |

```bash
curl -sS "https://api.qualflare.com/api/v1/case/101/steps" \
  -H "Authorization: Bearer $QF_TOKEN"
```

Returns `200`: An array of every step of the case, in order.

## Add a step

Add a step appends a step to a test case.

**POST** `/api/v1/case/{caseSeq}/steps`

Needs a project access token created with Allow writes, whose creator has the Editor role or higher in the project.

| Name          | Type            | Default  | Required | Description                                                                                                         |
| ------------- | --------------- | -------- | -------- | ------------------------------------------------------------------------------------------------------------------- |
| `caseSeq`     | `path`, integer |          | Yes      | The case number                                                                                                     |
| `instruction` | `body`, string  |          | Yes      | The step text, up to 500 characters                                                                                 |
| `stepType`    | `body`, string  | `action` | No       | `precondition`, `action`, `expected_result`, `verification`, `navigation`, `api_request`, `data_input` or `cleanup` |
| `parentId`    | `body`, integer |          | No       | The `id` of a step to nest this one under                                                                           |
| `data`        | `body`, JSON    |          | No       | Any JSON value to keep with the step                                                                                |

```bash
curl -sS -X POST "https://api.qualflare.com/api/v1/case/101/steps" \
  -H "Authorization: Bearer $QF_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"instruction": "Open the sign-in page", "stepType": "navigation"}'
```

Returns `201`: The new step.

* `instruction` is required, up to 500 characters; `stepType` defaults to `action`; `parentId` nests the step under another; `data` is any JSON.

## Update a step

Update a step changes the `instruction`, `stepType` or `data` you send.

**PUT** `/api/v1/case/{caseSeq}/step/{id}`

Needs a project access token created with Allow writes, whose creator has the Editor role or higher in the project.

| Name          | Type            | Default | Required | Description                                                                                                         |
| ------------- | --------------- | ------- | -------- | ------------------------------------------------------------------------------------------------------------------- |
| `caseSeq`     | `path`, integer |         | Yes      | The case number                                                                                                     |
| `id`          | `path`, integer |         | Yes      | The step `id`                                                                                                       |
| `instruction` | `body`, string  |         | No       | Up to 500 characters                                                                                                |
| `stepType`    | `body`, string  |         | No       | `precondition`, `action`, `expected_result`, `verification`, `navigation`, `api_request`, `data_input` or `cleanup` |
| `data`        | `body`, JSON    |         | No       | Any JSON value to keep with the step                                                                                |

```bash
curl -sS -X PUT "https://api.qualflare.com/api/v1/case/101/step/7" \
  -H "Authorization: Bearer $QF_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"instruction": "Open /login"}'
```

Returns `200`: The updated step.

* A step `id` that isn't on the case answers `404` with `step not found`.

> **Warning:** A create can't be retried safely: if a `POST` succeeded but you didn't get the answer, a retry creates a second case or step.

## Case fields

Every case the Cases and steps API returns has these fields:

| Field                    | Type            | Notes                                                                                                                                                                                                                                                       |
| ------------------------ | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `seq`                    | integer         | The case number in the project                                                                                                                                                                                                                              |
| `position`               | integer         | The case's place in its suite                                                                                                                                                                                                                               |
| `uid`                    | string          | The case's identifier: [Create a case](https://docs.qualflare.com/docs/api/cases#create-case) sets it to the name, and [Create cases in bulk](https://docs.qualflare.com/docs/api/cases#bulk-create-cases) to a random UUID |
| `name`                   | string          | The case name                                                                                                                                                                                                                                               |
| `description`            | string          | Up to 1,024 characters, or `null`                                                                                                                                                                                                                           |
| `state`                  | string          | `active`, `review`, `outdated` or `draft` ([Case states](https://docs.qualflare.com/docs/test-management/test-cases#test-case-lifecycle))                                                                                                                   |
| `priority`               | string          | `low`, `medium`, `high` or `critical`                                                                                                                                                                                                                       |
| `testType`               | string          | The kind of test, or the framework that reported it: a value of `testType` in [List a suite's cases](https://docs.qualflare.com/docs/api/cases#list-suite-cases)                                                                            |
| `automation`             | string          | `manual` or `automated`                                                                                                                                                                                                                                     |
| `isFavorite`             | boolean         | `true` for a favorite case                                                                                                                                                                                                                                  |
| `isFlaky`, `flakyScore`  | boolean, number | Whether Qualflare flags the case as [flaky](https://docs.qualflare.com/docs/analytics/flaky-tests), and its flaky score                                                                                                                                     |
| `mark`                   | string          | `none`, `redundant` or `low_value`                                                                                                                                                                                                                          |
| `isArchived`             | boolean         | `true` for an archived case                                                                                                                                                                                                                                 |
| `archivedAt`             | string          | When it was archived; left out unless archived                                                                                                                                                                                                              |
| `suiteSeq`, `suiteName`  | integer, string | The case's suite                                                                                                                                                                                                                                            |
| `createdAt`, `updatedAt` | string          | RFC 3339 timestamps                                                                                                                                                                                                                                         |

## Step fields

Every step in [List a case's steps](https://docs.qualflare.com/docs/api/cases#list-steps), and the step a write returns, has these fields:

| Field                    | Type    | Notes                                                                                                                                                                                                             |
| ------------------------ | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`                     | integer | The step `id`, which [Update a step](https://docs.qualflare.com/docs/api/cases#update-step) takes                                                                                                 |
| `instruction`            | string  | The step text; left out when empty, as a shared step's can be                                                                                                                                                     |
| `data`                   | JSON    | The data kept with the step; left out when there is none                                                                                                                                                          |
| `stepType`               | string  | `precondition`, `action`, `expected_result`, `verification`, `navigation`, `api_request`, `data_input` or `cleanup`; left out when empty                                                                          |
| `position`               | integer | The step's place in the case                                                                                                                                                                                      |
| `origin`                 | string  | Who last wrote the step: `manual`, `ai_generated` or `automated`                                                                                                                                                  |
| `sharedStep`             | object  | For a [shared step](https://docs.qualflare.com/docs/test-management/shared-steps): its `seq`, `name` and `items`, each item with `id`, `instruction`, `data`, `stepType` and `position`. Left out for other steps |
| `createdAt`, `updatedAt` | string  | RFC 3339 timestamps                                                                                                                                                                                               |

## CLI and MCP equivalents

The qf CLI and the MCP server run the same reads, and the MCP server the same writes, so they return the same JSON:

| REST                                           | qf command and MCP tool                                        |
| ---------------------------------------------- | -------------------------------------------------------------- |
| **GET** `/api/v1/suite/{suiteSeq}/cases`       | `qf <identifier> cases list --suite <seq>`; `list_suite_cases` |
| **GET** `/api/v1/case/{caseSeq}`               | `qf <identifier> case get <seq>`; `get_test_case`              |
| **POST** `/api/v1/suite/{suiteSeq}/cases`      | No qf command; `create_test_case`                              |
| **PUT** `/api/v1/case/{caseSeq}`               | No qf command; `update_test_case`                              |
| **POST** `/api/v1/suite/{suiteSeq}/cases/bulk` | No qf command; `bulk_create_cases`                             |
| **GET** `/api/v1/case/{caseSeq}/steps`         | `qf <identifier> case steps <seq>`; `list_case_steps`          |
| **POST** `/api/v1/case/{caseSeq}/steps`        | No qf command; `create_case_step`                              |
| **PUT** `/api/v1/case/{caseSeq}/step/{id}`     | No qf command; `update_case_step`                              |

## Related

* **Guides:** [Create and edit test cases](https://docs.qualflare.com/docs/test-management/create-test-cases)
* **Reference:** [Test cases: fields, states and steps](https://docs.qualflare.com/docs/test-management/test-cases) · [Suites API](https://docs.qualflare.com/docs/api/suites)
* **CLI/API:** [Qualflare API](https://docs.qualflare.com/docs/api) · [Errors and status codes](https://docs.qualflare.com/docs/api/errors)
