Bulk Fetch Test Cases

Bulk fetch test cases in a single request, with filtering and field selection defined in the request body. Use this API to get test case metadata in volume.

Endpoint

POST /rest/testcases/bulk/fetch

Request Headers

Content-Type: application/json

Name

Located in

Required

Description

Default

Schema

apiKey

header

yes

Open API key generated in Integration, Open API in QMetry Test Management.

-

string

scope

header

no

Project or scope Id/Key/Name.

default

string

Content-Type

header

yes

Enter value "application/json".

-

string

Request Parameters

Name

Located in

Required

Description

Default

Schema

projectId

body

yes

Unique identifier of the project whose test cases you want to retrieve. Only one project per request is supported.

-

integer

filters

body

no

System defined field and user defined field filters to apply. See the filter tables below. Ignored when tsId or next is present.

-

object

fields

body

no

Names of the fields to return. Omit to return all system defined fields and all user defined fields.

-

Array[string]

tsId

body

no

Unique identifier of a test suite. Returns only the test cases linked to that test suite. All filters are ignored when you send tsId.

-

integer

next

body

no

Pagination cursor returned in pagination.next of the previous response. Pass the value exactly as returned.

-

string

Filter System Defined Fields

Place system defined field filters inside the filters object.

Filter

Type

Description

tcIds

Array[integer]

Returns only the test cases with the listed identifiers. Maximum 500 entries per request.

isArchived

boolean

Set to false to return active test cases, or true to return archived test cases only.

isShared

boolean

Set to true to return shared test cases, or false to return test cases that are not shared.

priorityAlias

Array[string]

Returns test cases that match any one of the supplied priority labels.

summary

string

Matches the test case summary. Use an asterisk as a wildcard for prefix, suffix, or substring matching, for example, tc1*.

createdDateFrom

string

Start of the created date range, in YYYY-MM-DD format. The boundary date is included in the results.

createdDateTo

string

End of the created date range, in YYYY-MM-DD format. The boundary date is included in the results.

Filter User Defined Fields

Place a user defined field filter inside the filters object, using the exact field name as the key. Field names are case sensitive. To find a field name, go to Customization, open Manage Fields, and read the value in the Field Name column.

Field type

Value format

Behavior

STRING

string

Matches the supplied text value.

NUMBER

number

Matches the supplied numeric value.

LOOKUPLIST

string

Matches the display label of the list value.

MULTILOOKUPLIST

Array[string]

Values within the same field are evaluated as OR. A test case is returned when it holds any one of the supplied values.

DATETIMEPICKER

object

Pass {"from": "YYYY-MM-DD", "to": "YYYY-MM-DD"}. Both boundary dates are included in the results. A plain string is not accepted.

LARGETEXT

Not supported

Large text fields can be returned through fields, but cannot be used as filter keys.

Note: Filter input dates always use the YYYY-MM-DD format. Dates in the response use the date and time format of the API key user.

Select the Fields to Return

Pass a fields array to limit the response to the columns you need. Omit fields to receive every system defined field and every user defined field configured for the project.

You can mix system defined field names and user defined field names in the same array.

A user defined field value appears as a top level key in each row. Rows in which the user defined field holds no value omit the key entirely, rather than returning a null value.

If fields contain a name that is neither a system defined field nor a user defined field configured for the project, the request is rejected before any query runs.

Paginate Through Results

The API returns a fixed page size of 500 test cases. The response carries a pagination object:

  • pagination.hasMore indicates whether further pages are available. A value of false marks the last page.

  • pagination.next carries an encrypted, opaque cursor. Send this value back as the top level next parameter to retrieve the following page.

Observe the following rules:

  • Pass the cursor value verbatim. Do not modify it or construct one manually.

  • The cursor embeds both the position in the result set and the scope that produced it, which includes any filters and any tsId applied on the first page. Do not resend those parameters with the cursor.

  • When next is present, it always takes precedence. Any filters, tsId, or other body parameters sent in the same request are ignored without warning, and the response reflects the cursor scope.

  • Pagination is sequential. You cannot jump to an arbitrary page.

  • No total record count is returned.

  • projectId remains mandatory when you send a cursor.

Restrict Results to a Test Suite

Send tsId to return only the test cases associated with that test suite. Note the following behavior:

  • All filters sent alongside tsId are discarded without warning. The response contains every test case in the test suite, archived and active, across all statuses.

  • Field selection through fields continues to work normally.

  • Cursor pagination continues to work normally, and the cursor carries the test suite scope.

  • If the test suite does not belong to the project named in projectId, the request is rejected before any query runs.

Data Scope and Limitations

  • The API always serves the latest unarchived version of each test case. When the approval workflow is enabled for the project, it serves the latest approved version.

  • User defined field values appear as top level keys in each row. When a user defined field holds no value for a test case, the key is omitted from that row.

  • Results are always ordered by tcID in ascending order. Custom sorting is not supported.

  • Test step data and test step level user defined fields are not returned.

  • Rows where the UDF has no value, key is omitted.

  • Historical test case versions are not returned.

  • Test execution data is outside the scope of this API.

  • Cross project retrieval in a single request is not supported.

Response

Content-Type: application/json

Status Code

Reason

Response Model

200

Test case list fetched successfully.

ResponseEntity

400

projectId is missing, the pagination cursor is invalid or expired, or tsId does not belong to the supplied project.

-

403

The fields array contains an unknown field name, filters.tcIds exceeds 500 entries, or the API key user holds no role in the requested project.

-

500

Returned when server connection times out.

-

Examples

Retrive Test Cases

Example 61. Example 1: Retrieve All Fields for the First Page

Request

{
  "projectId": 43
}

Response

{
  "data": [
    {
      "tcID": 7,
      "entityKey": "1FHB-TC-6",
      "summary": "User Login Scenario",
      "description": "Verify user login with valid credentials",
      "tcVersion": 2,
      "tcVersionID": 7,
      "priority": 100,
      "priorityAlias": "P2",
      "testCaseStateAlias": "Open",
      "testCaseStateLabel": "Open",
      "testCaseTypeAlias": "Functional",
      "testingTypeAlias": "Manual",
      "componentAlias": "Comp1,Comp2",
      "ownerAlias": "admin",
      "executionMinutes": "270",
      "isArchived": false,
      "isShared": false,
      "projectId": 43,
      "projectName": "QMetry",
      "folderPath": "/Project-1/folder1 : /Project-1/folder2",
      "folderMappings": [
        { "folderPath": "/Project-1/folder1", "tcFolderID": 46 },
        { "folderPath": "/Project-1/folder2", "tcFolderID": 47 }
      ],
      "createdBy": "admin",
      "createdDate": "10-11-2023 03:53:33 PM",
      "updatedBy": "admin",
      "updatedDate": "10-11-2023 04:33:30 PM",
      "lookuplistdemo": "New"
    }
  ],
  "pagination": {
    "hasMore": true,
    "next": "e4ebf0628dc29626f2e7d239a9b4aa2a"
  }
}


Example 62. Example 2: Retrieve the Next Page

Send the cursor from pagination.next of the previous response as the top level next parameter. Do not resend filters, because the cursor already carries them.

Request

{
  "projectId": 43,
  "next": "e4ebf0628dc29626f2e7d239a9b4aa2a"
}

Response

{
  "data": [
    { "tcID": 664, "entityKey": "1FHB-TC-664" },
    { "tcID": 665, "entityKey": "1FHB-TC-665" }
  ],
  "pagination": {
    "hasMore": true,
    "next": "83501e16ec57d283917fb7272cf331a0"
  }
}


Example 63. Example 3: Cursor Takes Precedence Over Filters

When a request contains both next and filters, the filters embedded in the cursor apply and the filters in the request body are ignored. In this example, the cursor was produced by a first page filtered on isArchived set to false, so every row is active even though the request body asks for archived test cases.

Request

{
  "projectId": 43,
  "next": "e4ebf0628dc29626f2e7d239a9b4aa2a",
  "filters": {
    "isArchived": true
  }
}

Response

{
  "data": [
    { "tcID": 664, "isArchived": false },
    { "tcID": 665, "isArchived": false }
  ],
  "pagination": {
    "hasMore": true,
    "next": "83501e16ec57d283917fb7272cf331a0"
  }
}


Filter on System Defined Fields

Example 64. Example 4: Filter by Priority

Pass one or more priority labels as an array. Every returned test case matches at least one of the supplied labels.

Request

{
  "projectId": 43,
  "filters": {
    "priorityAlias": ["Blocker"]
  }
}

Response

{
  "data": [
    { "entityKey": "1FHB-TC-6", "priorityAlias": "Blocker" },
    { "entityKey": "1FHB-TC-20", "priorityAlias": "Blocker" }
  ],
  "pagination": { "hasMore": false }
}


Example 65. Example 5: Filter by Archive Status

Set isArchived to false to return active test cases, or true to return archived test cases only.

Request

{
  "projectId": 43,
  "filters": {
    "isArchived": false
  }
}

Response

{
  "data": [
    { "entityKey": "1FHB-TC-6", "isArchived": false }
  ],
  "pagination": {
    "hasMore": true,
    "next": "8123620a73cb2e32d80d08f32cc19c4b"
  }
}


Example 66. Example 6: Filter by Shared Status

Set isShared to true to return shared test cases, or false to return test cases that are not shared.

Request

{
  "projectId": 43,
  "filters": {
    "isShared": false
  }
}

Response

{
  "data": [
    { "entityKey": "1FHB-TC-6", "isShared": false }
  ],
  "pagination": {
    "hasMore": true,
    "next": "5d1f0a9c2b7e4d38a6c1f09e7b3a2d54"
  }
}


Example 67. Example 7: Filter by Summary with a Wildcard

Use an asterisk anywhere in the value for prefix, suffix, or substring matching. The value tc1* matches summaries such as tc1 and tc1_login.

Request

{
  "projectId": 43,
  "filters": {
    "summary": "tc1*"
  }
}

Response

{
  "data": [
    { "entityKey": "1FHB-TC-6", "summary": "tc1" }
  ],
  "pagination": { "hasMore": false }
}


Example 68. Example 8: Filter by Test Case Identifiers

Returns only the listed test cases. Because the result set is limited to the supplied identifiers, hasMore is always false. You can send up to 500 identifiers per request. For a larger set, split the identifiers across several requests.

Request

{
  "projectId": 43,
  "filters": {
    "tcIds": [7, 165]
  }
}

Response

{
  "data": [
    { "tcID": 7, "entityKey": "1FHB-TC-6" },
    { "tcID": 165, "entityKey": "1FHB-TC-20" }
  ],
  "pagination": { "hasMore": false }
}


Example 69. Example 9: Filter by Created Date Range

Pass both dates in YYYY-MM-DD format. Both boundary dates are included in the results.

Request

{
  "projectId": 43,
  "filters": {
    "createdDateFrom": "2025-07-01",
    "createdDateTo": "2025-07-31"
  }
}

Response

{
  "data": [
    { "entityKey": "1FHB-TC-20", "createdDate": "07-30-2025 10:39:39 AM" }
  ],
  "pagination": { "hasMore": false }
}


Select Fields

Example 70. Example 10: Select Specific Fields

Pass a fields array to receive only the listed columns. The priority field returns the numeric identifier of the priority list value, not the label. To get the label, request priorityAlias.

Request

{
  "projectId": 43,
  "fields": ["entityKey", "summary", "priority"]
}

Response

{
  "data": [
    { "tcID": 7, "entityKey": "1FHB-TC-6", "summary": "tc1", "priority": 12345 }
  ],
  "pagination": {
    "hasMore": true,
    "next": "b7c2e19f04a36d58e1f2a9c07d4b3e61"
  }
}


Example 71. Example 11: Include a User Defined Field

Add the user defined field name to fields. When the field holds no value for a test case, the key is omitted from that row, as in the first row of this response.

Request

{
  "projectId": 43,
  "fields": ["entityKey", "summary", "lookuplistdemo"]
}

Response

{
  "data": [
    { "tcID": 7, "entityKey": "1FHB-TC-6", "summary": "tc1" },
    { "tcID": 165, "entityKey": "1FHB-TC-20", "summary": "root", "lookuplistdemo": "New" }
  ],
  "pagination": {
    "hasMore": true,
    "next": "c91d3a7e25f06b48d2e1a0f93c7b5d82"
  }
}


Filter on User Defined Fields

Example 72. Example 12: Include a Date User Defined Field

Replace plannedDate with the name of a DATETIMEPICKER user defined field configured in your project. The value is returned in the date and time format of the API key user. When the field holds no value for a test case, the key is omitted from that row.

Request

{
  "projectId": 57,
  "fields": ["entityKey", "summary", "plannedDate"]
}

Response

{
  "data": [
    { "tcID": 155, "entityKey": "KEV1-TC-1", "summary": "Testcase_1", "plannedDate": "04-23-2025 06:30:00 PM" },
    { "tcID": 156, "entityKey": "KEV1-TC-2", "summary": "Test_2", "plannedDate": "03-25-2025 06:30:00 PM" }
  ],
  "pagination": { "hasMore": false }
}


Example 73. Example 13: Filter on a Lookup List User Defined Field

Use the field name as the key and the display label of the list value as the value.

Request

{
  "projectId": 43,
  "filters": {
    "lookuplistdemo": "New"
  }
}

Response

{
  "data": [
    { "entityKey": "1FHB-TC-20", "lookuplistdemo": "New" }
  ],
  "pagination": { "hasMore": false }
}


Example 74. Example 14: Filter on a Multi Lookup List User Defined Field

Pass the values as an array. The values are evaluated as OR, so the following request returns every test case that holds either value, or both.

Request

{
  "projectId": 43,
  "filters": {
    "multilookfield6": ["CC", "BB"]
  }
}

Response

{
  "data": [
    { "entityKey": "1FHB-TC-7", "multilookfield6": "BB,CC" },
    { "entityKey": "1FHB-TC-32", "multilookfield6": "Alpha,BB,Beta,CC,Gamma" },
    { "entityKey": "1FHB-TC-37", "multilookfield6": "Alpha,CC,Gamma" }
  ],
  "pagination": { "hasMore": false }
}


Example 75. Example 15: Filter on a Date User Defined Field

Replace plannedDate with the name of a DATETIMEPICKER user defined field configured in your project. The value must be an object with from and to dates in YYYY-MM-DD format. Both boundary dates are included, so test cases 163 and 156, which fall on the boundary dates, appear in the results. Test case 155, planned for April 23, 2025, falls outside the range and is excluded.

Request

{
  "projectId": 57,
  "filters": {
    "plannedDate": {
      "from": "2025-03-16",
      "to": "2025-03-25"
    }
  }
}

Response

{
  "data": [
    { "tcID": 156, "entityKey": "KEV1-TC-2", "plannedDate": "03-25-2025 06:30:00 PM" },
    { "tcID": 158, "entityKey": "KEV1-TC-4", "plannedDate": "03-17-2025 06:30:00 PM" },
    { "tcID": 163, "entityKey": "KEV1-TC-9", "plannedDate": "03-16-2025 06:30:00 PM" }
  ],
  "pagination": { "hasMore": false }
}


Retrieve the Test Cases of a Test Suite

Example 76. Example 16: Retrieve a Test Suite with Selected Fields, Then Page Through It

Send tsId to return only the test cases linked to that test suite. The fields array continues to apply.

Request

{
  "projectId": 43,
  "tsId": 101,
  "fields": ["tcID", "summary", "status"]
}

Response

{
  "data": [
    { "tcID": 11, "summary": "Login smoke", "status": "Draft" }
  ],
  "pagination": {
    "hasMore": true,
    "next": "3mK9vXpL8QrN2wYtA0bDcEfGhIjKlMnOpQrStUvWxYz1234ABCD=="
  }
}

Request for the next page. The cursor carries the test suite scope, so do not resend tsId. If you send a different tsId together with the cursor, it is ignored, and the response still contains test cases from test suite 101.

{
  "projectId": 43,
  "next": "3mK9vXpL8QrN2wYtA0bDcEfGhIjKlMnOpQrStUvWxYz1234ABCD=="
}

Response

{
  "data": [
    { "tcID": 511, "summary": "Checkout smoke" }
  ],
  "pagination": {
    "hasMore": true,
    "next": "7pQwRmLkNvBcYdZaJhUeGfTyOi9sXwQp0An8E3uCjMrVb6KDlFhS=="
  }
}


Example 77. Example 17: Filters Are Ignored with a Test Suite

Any filters sent alongside tsId are discarded without warning. The response contains every test case in the test suite, archived and active, across all statuses.

Request

{
  "projectId": 43,
  "tsId": 101,
  "filters": {
    "isArchived": true,
    "status": "Draft"
  }
}

Response

{
  "data": [
    { "tcID": 11, "isArchived": false, "status": "Approved" },
    { "tcID": 15, "isArchived": true, "status": "Approved" }
  ],
  "pagination": { "hasMore": false }
}


Error Responses

Example 78. Missing Project
{
  "error": "projectId is required"
}


Example 79. Invalid or expired cursor
{
  "error": "Invalid or expired pagination cursor"
}


Example 80. Test suite in a different project (400):
{
  "message": "tsId 9999 does not belong to project 43",
  "status": 400
}


Example 81. Unknown field name (403):
{
  "error": "Unknown field: nonExistentField99"
}


Example 82. Too many test case identifiers (403):
{
  "error": "tcIds filter cannot exceed 500 entries per request"
}


Example 83. No access to the project (403):
{
  "error": "Access denied to project: 99999999"
}


Publication date: