Manage test cases and suites with the API
Find a repository, create a manual test case, update it, and add it
to a test suite. Use a non-production project while building your integration.
1. Set up authentication
Use your tenant host, https://<tenant>.katalon.io, with no trailing slash.
Authenticate with a Katalon API key using HTTP Basic: leave the username empty
and use the key as the password. See
Authenticate with the v2 API.
Keep the key in your secret store; do not enable shell tracing (set -x).
Send x-project-id on every request. The optional x-account-id header takes
an account UUID, and x-organization-id takes the organization ID. Your key's
user needs TestCase:Read, TestCase:Create, and TestCase:Update for the case
examples, plus TestSuite:Read and TestSuite:Update to find a suite and add
members. Creating a suite also needs TestSuite:Create. Linking a case to a
requirement needs TestCase:Create; unlinking uses the same permission.
Set KATALON_API_HOST, KATALON_API_KEY, and KATALON_PROJECT_ID from your
environment. This Bash helper passes the key to curl through standard input,
not through process arguments. If the key contains " or \, escape those
characters as \" and \\ for curl's configuration format.
katalon_request() {
: "${KATALON_API_KEY:?Missing API key}"
printf 'user = ":%s"\n' "${KATALON_API_KEY}" |
curl --config - --silent --show-error --fail-with-body \
--header "x-project-id: ${KATALON_PROJECT_ID:?Missing project ID}" \
"$@"
}2. Choose a repository and an existing folder
katalon_request "${KATALON_API_HOST}/v2/tm/repositories/search?page=0&size=100"Choose a writable Cloud repository from content. Save its id as REPO_ID.
This is the repository ID, called testProjectId in write payloads. It is
not the project ID in your header. See
Know which ID is which.
By default, repository search includes only repositories with ACTIVE or
ERROR status.
The older
repository list
returns an array instead of a page. If you use it, specify types explicitly:
omitting types does not select all types and can return an empty array. Use
types=CLOUD for Cloud repositories, or all supported types as shown below.
Add includeAllStatuses=true to include other statuses.
katalon_request "${KATALON_API_HOST}/v2/tm/repositories?types=GIT,KS,CLOUD"Search test folders in the selected repository.
Requires the TestCase:Read permission. This also applies to test-suite folders.
katalon_request --get \
--data-urlencode "q=testProjectId==${REPO_ID:?Missing repository ID}" \
--data-urlencode 'includeFields=directSubFolderCount' \
--data-urlencode 'sorts=id asc' \
"${KATALON_API_HOST}/v2/tm/test-folders"The response contains content, totalElements, totalPages, and pageable.
Use page and size to read more results; the maximum page size is 100.
Choose a type: TEST_CASE folder.
Save its complete rawPath, such as Test Cases/Smoke.
Choose a type: TEST_SUITE folder, such as Test Suites, for suite changes.
Use rawPath, not the hierarchy IDs in treePath, in the payloads below.
The project header limits the results; a repository from another project returns an empty page.
includeFields=directSubFolderCount calculates immediate subfolders.
Without it, the response uses stored counts.
Neither form calculates direct or recursive test-case counts.
3. Create and read a test case
All changes below use
Publish test entities.
Save this payload as create-case.json. Replace 123 with your REPO_ID
and Test Cases/Smoke with the selected folder's complete path:
[
{
"testProjectId": 123,
"testEntities": [
{
"action": "CREATE",
"resource": "TEST_CASE",
"data": {
"name": "Customer sign-in",
"path": "Test Cases/Smoke",
"testType": "MANUAL",
"steps": [
{"description": "Sign in with a valid account", "expectedResult": "The dashboard opens"}
]
}
}
]
}
]katalon_request --request POST --header "Content-Type: application/json" \
--data @create-case.json \
"${KATALON_API_HOST}/v2/tm/repositories/test-entities?async=false"Save the returned testEntities[].data.id for this case as TEST_CASE_ID.
If a response contains taskResource.uuid but no created ID, do not submit
dependent changes. Before you retry the create,
search test cases
to check whether the case already exists. A response can arrive before
repository file publication finishes.
Read the case
to confirm its metadata:
katalon_request "${KATALON_API_HOST}/v2/tm/test-cases/${TEST_CASE_ID}"4. Update the test case
Save this as update-case.json, replacing 123 with your REPO_ID and 456
with your TEST_CASE_ID:
[
{
"testProjectId": 123,
"testEntities": [
{
"action": "UPDATE",
"resource": "TEST_CASE",
"data": {"id": 456, "description": "Verify that active customers can sign in."}
}
]
}
]katalon_request --request POST --header "Content-Type: application/json" \
--data @update-case.json \
"${KATALON_API_HOST}/v2/tm/repositories/test-entities?async=false"Read the case again to check the changed description. Omitted manual content
is preserved. If you replace steps or full manual content, send the complete
desired content, not only changed steps.
5. Add the case to a test suite
Search suites,
then select a manual suite in the same repository and save its ID as
TEST_SUITE_ID:
katalon_request "${KATALON_API_HOST}/v2/tm/test-suites/search?page=0&size=100"To create a suite instead, publish a TEST_SUITE entity with action: CREATE
and data: {"name": "Smoke checks", "path": "Test Suites", "testSuiteTestType": "MANUAL", "testSuiteItems": []}.
An empty testSuiteItems list creates the suite without members.
Use your selected suite folder's complete path and save the returned suite ID
as TEST_SUITE_ID.
Save add-to-suite.json, replacing 123 with your REPO_ID, 789 with your
TEST_SUITE_ID, and 456 with your TEST_CASE_ID:
[
{
"testProjectId": 123,
"testEntities": [
{
"action": "ADD_TEST_CASES",
"resource": "TEST_SUITE",
"data": {
"id": 789,
"testSuiteItems": [{"testCaseId": 456, "versionSelectionType": "LATEST_VERSION"}]
}
}
]
}
]katalon_request --request POST --header "Content-Type: application/json" \
--data @add-to-suite.json \
"${KATALON_API_HOST}/v2/tm/repositories/test-entities?async=false"ADD_TEST_CASES adds membership without replacing the existing list. In
contrast, suite UPDATE replaces the full membership list. Confirm membership
with the
suite membership search,
matching the returned testSuiteId and testCaseId across pages.
katalon_request --get \
--data-urlencode "q=testSuiteId==${TEST_SUITE_ID:?Missing suite ID}" \
"${KATALON_API_HOST}/v2/tm/test-suites/test-cases/search"Next steps
Read assigned custom-field values
List custom-field values after a case UPDATE.
Requires the TestCase:Read permission.
Use the same project as the case:
katalon_request --get \
--data-urlencode "q=entityId==${TEST_CASE_ID:?Missing test case ID} and entityType==TEST_CASE" \
"${KATALON_API_HOST}/v2/tm/customizable-fields"--data-urlencode encodes the spaces and comparisons in q.
Use textual and, not ;, between comparisons.
A semicolon can return 400 with a missing-selector message.
The selectors belong inside q; separate entityId and entityType query parameters do not select the case.
Each content item includes definitionId, definitionType, and the typed value, such as optionValueUuid or textValue.
The result is a page, not an array of definitions or grouped values.
To select one definition, add and definitionId==<definitionId> inside the same q value.
You can also use q=definitionId==<definitionId> alone to select its values in the project.
Use the Admin definition ID, not an option ID.
Get a test case returns Feature Area and Test Type, not modern custom-field values.
Clear a selected field with values: [].
Repeat this read to check that its value items are absent.
An empty content array means no values match the filter.
See Define and assign custom fields for the UPDATE payload.
Link a case to a requirement
Find an ALM-synchronized requirement with
requirement search
or its external key
(the requirement's sourceId, for example XQE-5).
Save its True Platform ID as REQUIREMENT_ID, not its external key:
katalon_request --request POST --header "Content-Type: application/json" \
--data "{\"testCaseIds\":[${TEST_CASE_ID:?Missing test case ID}]}" \
"${KATALON_API_HOST}/v2/tm/requirements/${REQUIREMENT_ID}/link-test-cases"A requirement must have a synchronized external issue: a successful response
without one does not create coverage links. Links to the ALM issue may appear
after the next ALM sync; a successful response does not promise an immediate
linkedTestCaseCount change. To
unlink cases,
send the same JSON shape with DELETE, not POST.
Move or delete assets
The publishing reference
also covers rename, move, duplicate, and delete. Case and suite moves use a
destination parent path; folder moves use the complete destination path.
Folder changes can affect descendants. Review those effects and your permissions
before deleting or moving test assets.
Known limitations
Deleted suites can continue to appear in suite detail and search reads for a
while. No visibility-update deadline is guaranteed. A repeated delete can return
400 with "Test suite has been deleted since you last took action" even while
the suite is still returned by those reads. Do not retry the delete only
because the suite is still visible.
Case content and versions
Use these operations after you select TEST_CASE_ID and REPO_ID above.
Keep x-project-id set to the case's project.
See the ID glossary for each ID.
-
Read manual content.
Requires theTestCase:Readpermission.katalon_request "${KATALON_API_HOST}/v2/tm/test-cases/${TEST_CASE_ID}/contents/MANUAL?mode=LATEST"Example response:
{"testCaseId":456,"contentType":"MANUAL","testCaseVersionNumber":1,"description":"Check sign-in.","preCondition":"An active account exists.","content":{"version":"1.0.0","steps":[]}}Only
MANUALcontent is supported. A fallback read can return a null version number.
Usemode=VERSION&versionNumber=1for a specific version.
Usemode=REF&refType=BRANCH&refName=mainfor a repository reference. -
List versions.
Requires theTestCase:Readpermission.katalon_request "${KATALON_API_HOST}/v2/tm/test-cases/${TEST_CASE_ID}/versions?page=0&size=100" katalon_request "${KATALON_API_HOST}/v2/tm/test-cases/${TEST_CASE_ID}/versions/latest" katalon_request "${KATALON_API_HOST}/v2/tm/test-cases/${TEST_CASE_ID}/versions/1"The list returns
content,pageable,totalElements, andtotalPages.
A single-version response includestestCaseId,versionNumber, and snapshot metadata. -
Update manual content.
Requires theTestCase:Updatepermission.
Save the complete flow ascase-content.json.
Replace1with the latest version number before you send the request.{"mode":"VERSION","versionNumber":1,"message":"Update manual steps","content":{"version":"1.0.0","steps":[{"id":"a8c2def0-73f5-4b39-8722-15f482df0c12","name":"Sign in with a valid account"}]}}WARNING: Send all steps that you want to keep. An empty steps array removes the manual steps.
katalon_request --request PUT --header "Content-Type: application/json" \ --data @case-content.json \ "${KATALON_API_HOST}/v2/tm/test-cases/${TEST_CASE_ID}/contents/MANUAL"Example response:
{"testCaseId":456,"contentType":"MANUAL","testCaseVersionNumber":2}A stale
VERSIONbase returns409. Read the latest content before you reconcile the change.
The repository must support versioned authoring and accept the workspace and content.
Repository readiness can prevent a write. A returned task does not mean publication has finished.
Writes can target only the configured default repository ref; other refs return400.
This write restriction does not limit reads to the default ref. -
Restore a prior version only when you intend to replace the latest snapshot.
Requires theTestCase:Updatepermission.katalon_request --request POST \ "${KATALON_API_HOST}/v2/tm/test-cases/${TEST_CASE_ID}/versions/1/restore"The response contains the latest version after the restore.
The selected version must belong to this case. The latest version cannot restore itself. -
Find reusable cases and inspect the call graph.
Requires theTestCase:Readpermission.katalon_request --get --data-urlencode "q=testProjectId==${REPO_ID},name==login" \ "${KATALON_API_HOST}/v2/tm/test-cases/callable" katalon_request "${KATALON_API_HOST}/v2/tm/test-cases/${TEST_CASE_ID}/callers" katalon_request "${KATALON_API_HOST}/v2/tm/test-cases/${TEST_CASE_ID}/callers/count" katalon_request "${KATALON_API_HOST}/v2/tm/test-cases/${TEST_CASE_ID}/callees"Callable search uses comma-separated
key==valuefilters, not the general search syntax.
Its repository selector is required. Callable, caller, and callee pages contain at most 20 records.
Resolve references to read metadata or content, not to create links.
Send 1–10 same-project URIs withaction: resolveoraction: resolve_content.
Check each result'serroreven when the request returns200.
Prefix a returned relative content URL with/v2/tmon your tenant host. -
Save unsaved edits with the authoring draft.
Requires theTestCase:Updatepermission, including for draft GET and DELETE.
Drafts support only Cloud cases with manual-like types and belong to the current user.
A draft does not create a published case version.
GET returns204when your draft is absent. DELETE also returns204when it is absent.
OmitexpectedRevisiononly for a new draft.
Send the currentrevisionasexpectedRevisionto update it; a stale revision returns409. -
Read case links or linked ALM test cases.
Requires theTestCase:Readpermission.katalon_request "${KATALON_API_HOST}/v2/tm/test-case-link?page=0&size=100" katalon_request "${KATALON_API_HOST}/v2/tm/test-cases/${TEST_CASE_ID}/linked-alm-test-cases"The link index returns a page with source and destination cases in this project.
The ALM operation returns an array of linked Azure DevOps or Xray test cases.
Use datasets and export test assets
Create and link a dataset
Dataset routes manage metadata and test case links. Clients read and write dataset rows directly in Storage.
Requires the TestCase:Read permission for reads.
Requires the TestCase:Update permission for dataset changes.
To link a dataset, you need both permissions.
- Create a dataset with a name that is unique in the project.
- Save its
idasDATASET_ID. - Use its
contentReferenceto access Storage. - Report the saved schema, counts, and content hash with Update a dataset.
- Link the dataset to a test case.
Create metadata with this request:
katalon_request --request POST --header "Content-Type: application/json" \
--data '{"name":"Smoke data","description":"Checkout matrix"}' \
"${KATALON_API_HOST}/v2/tm/datasets"A content reference contains a durable uri and optional origin, path, scopes, and expiresAt fields.
When signed, path has read access or read and write access, limited by scopes and expiry in epoch seconds.
The signature binds the user, project, and Storage artifact.
Use the same user and project context for Storage access.
If signing is disabled or lacks a key or principal, the optional fields are null.
Do not assume every response contains a signed path.
WARNING: Keep signed paths private. Do not store them in logs or share them with other users.
For an existing dataset, call Prepare a dataset save with its current baseContentHash.
Save rows through Storage before you send the metadata update.
The prepare request takes no edit lock. A concurrent save can make the later update return 409 with data.reason: stale_content.
Reload the dataset before you retry. Schema changes can also require explicit confirm=true after you inspect their impact on linked cases.
Link a dataset after its content is ready:
katalon_request --request PUT --header "Content-Type: application/json" \
--data "{\"datasetId\":\"${DATASET_ID:?Missing dataset ID}\",\"rowSelection\":\"all\"}" \
"${KATALON_API_HOST}/v2/tm/test-cases/${TEST_CASE_ID:?Missing test case ID}/data/binding"Get test case data returns link metadata, variable diagnostics, and the iteration count, not row values.
Only rowSelection: all is supported. The API rejects nested iteration across the case call chain.
Unlink a dataset with DELETE on the same binding path.
Duplicate a dataset copies its schema but starts with empty content.
Export cases or a release matrix
Export test cases supports document exports in CSV or WORD format.
Requires the TestCase:Read permission.
The request returns 202 with a task UUID, not a completed file.
If you send a JSON body, it replaces the query selection. Use query in the body and q in the URL.
katalon_request --request POST --header "Content-Type: application/json" \
--data '{"query":"id=in=(456,457)","destination":"DOCUMENT","format":"CSV"}' \
"${KATALON_API_HOST}/v2/tm/test-cases/export"Replace the example case IDs with cases in your project.
Get release traceability scope previews current counts.
Export a release traceability matrix accepts format=xlsx or format=docx.
Both release operations require the Requirement:Read permission.
The export returns 202 with format and taskUuid. Preview counts can change before the export finishes.
Save the returned task UUID as TASK_ID.
Only the user who created the task can get its status.
katalon_request "${KATALON_API_HOST}/v2/tm/tasks/${TASK_ID:?Missing task UUID}"Wait for status: SUCCEED. For document exports, inspect output.firstItem.downloadReady and output.firstItem.downloadUrl.
A successful task alone does not guarantee an available download.
The API supplies a short-lived URL only for a ready artifact that has not expired.
Request the task again if the URL expires while the artifact remains available.
WARNING: Keep download URLs private. Do not write them to logs.
The task creator can cancel a task.
Cancellation does not undo completed work or guarantee that all work stops immediately.
Import ADO cases
Import ADO test cases starts a separate task.
Requires the TestCase:Create permission.
Select an Azure DevOps integration and a Cloud repository in the current project.
The repository must also belong to your organization.
If you supply targetTestFolderId, it must identify a test-case folder in that project and repository.
If you omit it, the API uses Test Cases.
The response is a task UUID string, not a completed import result.
Use the same task status route to follow the import.
Manage field options and linked assets
Use the API Reference links below to check each request's permission, input, response, and error details.
List suite collections and variables
List the test suite collections in the project. Use a collection ID to list its entries:
katalon_request --get "${KATALON_API_HOST}/v2/tm/test-suite-collections?page=0&size=100"
katalon_request --get \
"${KATALON_API_HOST}/v2/tm/test-suite-collections/${COLLECTION_ID:?Missing collection ID}/test-suite-entries?page=0&size=100"Use the project variable index to find variable names. Use the variable name to find cases that declare it. The name match is case-sensitive.
katalon_request --get "${KATALON_API_HOST}/v2/tm/projects/${KATALON_PROJECT_ID}/variables"
katalon_request --get \
"${KATALON_API_HOST}/v2/tm/projects/${KATALON_PROJECT_ID}/variables/accountId/test-cases?page=0&size=20"Manage system field options
Read the system fields featureArea and testType. Create or rename an option with a value body:
katalon_request --request POST --header "Content-Type: application/json" \
--data '{"value":"Regression"}' \
"${KATALON_API_HOST}/v2/tm/custom-field-definition/testType/options"An option in use returns 409 unless you set force=true. Forced deletion removes eligible option links before it deletes the option.
| Delete condition | Required permission |
|---|---|
| Every delete | Requires the SystemFieldOption:Delete permission. |
| Forced delete of a linked test case | Requires the TestCase:Update permission. |
| Forced delete of a linked execution, result, or schedule | Requires the TestRun:Update permission. |
Assign tags
Send a JSON array to add, replace, or remove tag links. Use PUT to replace the tag set. An empty tags array clears that set.
katalon_request --request POST --header "Content-Type: application/json" \
--data '[{"entityType":"TEST_CASE","entityId":456,"tags":[{"name":"smoke"}]}]' \
"${KATALON_API_HOST}/v2/tm/tags"The API accepts TEST_CASE, TEST_SUITE, EXECUTION, and EXECUTION_TEST_RESULT assignments. Check the Add tags reference for the permission that matches each type.
Find the operation for each task
| Task | API Reference |
|---|---|
| List suite collections and entries | List test suite collections · List collection entries |
| Read or change system field options | List system field definitions · Create an option · Update an option · Merge options · Delete an option |
| Manage tag assignments and names | Add tags · Replace tags · Remove tags · Create a tag name · Rename a tag |
| Find project variables and cases | List project variables · List cases by variable |
| Change requirement status or assignee | Update a requirement |
| Read the latest test plan | Get the latest test plan |
| Link or find ADO issues | Link an ADO issue · Unlink an ADO issue · List linked issues · List available ADO test cases · List available issues |
| Remove a defect link | Unlink a defect |
| Select a repository branch or path | List branches · List installed repositories · Test a repository path |
For a requirement update, always include assignee.uuid.
To change only its status, send the current assignee UUID to preserve the assignment.
Send null only when the requirement is already unassigned or you want to clear its assignment.
Updated 17 days ago