These endpoints create test suites and cases, trigger runs, and read run status and step results. Authentication, error shapes and rate limits are covered in the REST API overview.
ID format: The
{suite_id},{case_id},{run_id}, and{suite_run_id}path parameters are string public IDs (thepublic_idfield in responses, e.g."suite_abc123"), not the numericid. App references in query and body fields generally take the app’spublic_idas well — Create Suite additionally accepts a legacy numericapp_id. One exception on run IDs: the AI suite-run cancel endpoint takes the numeric ID.
Test Suites
List Suites
GET /api/v1/tests/suites
Auth: Bearer token required. Viewer role or above.
Query parameters:
| Parameter | Type | Description |
|---|---|---|
app_id | string | Filter suites by app public ID (e.g. ?app_id=app_xyz789) |
tags | string | Comma-separated tag names to filter by (e.g. ?tags=smoke,profiles) |
match | string | any (default) — suite has at least one tag; all — suite has every tag |
Response:
[
{
"id": 1,
"public_id": "suite_abc123",
"name": "Login Flow",
"description": "Tests for the login feature",
"app_id": 1,
"app_public_id": "app_xyz789",
"app_name": "My App",
"platform": "ios",
"case_count": 5,
"reset_strategy": "clear_data",
"context": null,
"variables": {},
"last_run_status": "passed",
"last_run_at": "2025-01-20T14:00:00",
"created_at": "2025-01-15T10:30:00",
"updated_at": "2025-01-20T14:00:00",
"tags": [{"name": "profiles", "display_name": "Profiles"}]
}
]
Create Suite
POST /api/v1/tests/suites
Auth: Bearer token required. Developer role or above.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Suite name |
description | string | No | Suite description |
app_public_id | string | No | Associated app public ID (preferred) |
app_id | int | No | Associated app numeric ID (legacy alternative to app_public_id) |
platform | string | No | ios or android |
tags | string[] | No | Optional list of tags. Each tag must match ^[a-z0-9_-]{1,50}$. Auto-creates new tags within the org (case-insensitive uniqueness; first-seen casing becomes display_name). |
Response includes tags: [{name, display_name}] reflecting the suite’s current tags.
Export Suite as YAML
Downloads the suite and all its cases as a YAML file. Includes step mappings, source recordings, and device dimensions for portable hybrid replay.
GET /api/v1/tests/suites/{suite_id}/export-yaml
Auth: Bearer token required. Viewer role or above.
Response: YAML file download (text/yaml).
Import Suite from YAML
Creates a test suite from an uploaded YAML file. Optionally links to an app.
POST /api/v1/tests/suites/import-yaml
Auth: Bearer token required. Developer role or above.
Body: multipart/form-data with a file field containing the YAML file.
Query parameters:
| Parameter | Type | Description |
|---|---|---|
app_id | string | (Optional) App public ID to link the suite to |
If app_id is not provided but the YAML contains an appId field, the import attempts to match an existing app by package name.
Response:
{
"public_id": "my-suite-abc123",
"name": "My Test Suite",
"case_count": 5
}
Get Suite
Returns the suite with all its test cases.
GET /api/v1/tests/suites/{suite_id}
Auth: Bearer token required. Viewer role or above.
Update Suite
PATCH /api/v1/tests/suites/{suite_id}
Auth: Bearer token required. Developer role or above.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
name | string | No | Suite name |
description | string | No | Suite description |
reset_strategy | string | No | One of relaunch, clear_data, reinstall |
context | string | No | Additional context passed to the AI agent |
variables | object | No | Key-value variables available during test execution |
visual_regression_warn_pct | int | No | Warn-tier threshold for visual regression (% changed pixels). null disables the warn tier. See Visual regression. |
visual_regression_fail_pct | int | No | Fail-tier threshold for visual regression (% changed pixels). null disables the fail tier. See Visual regression. |
tags | string[] | No | When present, replaces the suite’s tag set wholesale. An empty array clears all tags. Omit to leave existing tags unchanged. |
Delete Suite
DELETE /api/v1/tests/suites/{suite_id}
Auth: Bearer token required. Developer role or above.
List Org Tags
GET /api/v1/tests/tags
Auth: Bearer token required. Viewer role or above.
Lists every tag in the user’s organization with usage counts. Used by autocomplete UIs.
Response: 200 OK
[
{ "name": "smoke", "display_name": "smoke", "suite_count": 7 },
{ "name": "profiles", "display_name": "Profiles", "suite_count": 3 }
]
Sorted by suite_count DESC, name ASC. Tags with zero suites are included.
Test Cases
Create Test Case (in a suite)
POST /api/v1/tests/suites/{suite_id}/cases
Auth: Bearer token required. Developer role or above.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Test case name |
steps | array | Yes | Array of step objects or strings |
assertions | array | No | Verification assertions |
mode | string | No | ai or recorded (default: recorded) |
source_recording | array | No | Raw recording actions for hybrid replay |
source_device_width | int | No | Device width used during recording |
source_device_height | int | No | Device height used during recording |
Response:
{
"id": 1,
"suite_id": 1,
"name": "Login with valid credentials",
"mode": "ai",
"steps": [...],
"assertions": [...],
"step_count": 5,
"has_source_recording": true,
"source_recording_summary": {
"total_actions": 12,
"gesture_counts": {"tap": 3, "swipe": 1}
},
"source_gesture_list": [...],
"step_gesture_groups": [...],
"source_device_width": 390,
"source_device_height": 844,
"context": null,
"created_at": "2025-01-15T10:30:00",
"updated_at": "2025-01-15T10:30:00"
}
List Test Cases (in a suite)
A suite’s cases are returned embedded in the suite object — fetch them with Get Suite (GET /api/v1/tests/suites/{suite_id}). There is no separate list endpoint.
Get Test Case
Returns the test case. Works for both suite-attached and standalone test cases. To fetch a case’s run history, use GET /api/v1/tests/cases/{case_id}/runs.
GET /api/v1/tests/cases/{case_id}
Auth: Bearer token required. Viewer role or above.
Update Test Case
PATCH /api/v1/tests/cases/{case_id}
Auth: Bearer token required. Developer role or above.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
name | string | No | Test case name |
steps | array | No | Updated steps |
assertions | array | No | Updated assertions |
context | string | No | Additional context for the AI |
app_id | string | No | Associated app public ID. Only settable on standalone cases — returns 400 if the case is attached to a suite (the suite owns the app linkage). |
sub_flow_ids | array | No | Ordered list of reusable case IDs to run before this case’s own steps |
source_recording | array | No | Raw recording actions for hybrid replay |
fuzzy_match | boolean | No | Enable fuzzy coordinate matching during replay |
is_reusable | boolean | No | Mark case as a reusable sub-flow. Setting true requires no parent suite — returns 400 if the case is attached to a suite. |
Delete Test Case
DELETE /api/v1/tests/cases/{case_id}
Auth: Bearer token required. Developer role or above.
Copy Test Case
Copy a test case to another suite.
POST /api/v1/tests/suites/{suite_id}/cases/{case_id}/copy
Auth: Bearer token required. Developer role or above.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
target_suite_id | string | Yes | Destination suite public ID |
Create Standalone Test Case
Create a test case that is not attached to any suite. If a standalone case with the same name already exists for the app, it is updated in place instead of duplicated.
POST /api/v1/tests/cases
Auth: Bearer token required. Developer role or above.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Test case name |
app_id | string | Yes | App public ID the case belongs to |
steps | array | Yes | Array of step objects or strings |
assertions | array | No | Verification assertions |
mode | string | No | ai or recorded (default: recorded) |
context | string | No | Additional context for the AI |
source_recording | array | No | Raw recording actions for hybrid replay |
source_device_width | int | No | Device width used during recording |
source_device_height | int | No | Device height used during recording |
source_platform | string | No | ios, android, tvos, or androidtv (defaults to the app’s platform) |
fuzzy_match | boolean | No | Enable fuzzy coordinate matching during replay (default: true) |
Response: The created (or updated) test case object, same shape as Create Test Case (in a suite).
Errors:
404— App not found in your organization.
List Standalone Test Cases
List test cases that are not attached to any suite.
GET /api/v1/tests/cases
Auth: Bearer token required. Viewer role or above.
Query parameters:
| Parameter | Type | Description |
|---|---|---|
reusable | boolean | true — only reusable sub-flows; false — only non-reusable; omit for all |
Response: Array of test case objects (most recent first), each including recent_run_statuses for the last 10 runs.
Test Case Runs
List Runs for a Test Case
GET /api/v1/tests/cases/{case_id}/runs
Auth: Bearer token required. Viewer role or above.
Returns all runs for the specified test case, ordered by most recent first.
Create a Run Record
POST /api/v1/tests/cases/{case_id}/run
Auth: Bearer token required. Viewer role or above.
Creates a run record for the case in pending status — it does not execute the test. To actually execute a test, use Run AI Test (POST /api/v1/ai/test/run) or the CI endpoints.
Response:
{
"id": 1,
"public_id": "tr7abc123x",
"test_case_id": 1,
"status": "pending",
"started_at": "2025-01-20T14:00:00",
"finished_at": null,
"result": null,
"reasoning_log": null,
"error_message": null,
"duration_ms": null,
"model_used": null,
"tokens_used": null,
"cost_micro": null
}
List Baselines for a Test Case
GET /api/v1/tests/cases/{case_id}/baselines
Auth: Bearer token required. Viewer role or above.
Returns all baseline image records for the test case.
Get Baseline Image
GET /api/v1/tests/cases/{case_id}/baselines/step_{step_index}.jpg
Auth: Bearer token required. Viewer role or above.
Returns the baseline screenshot for the specified step as a JPEG image.
Test Runs (run-level operations)
Update Test Run
PATCH /api/v1/tests/runs/{run_id}
Auth: Bearer token required.
Query parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
status | string | Yes | One of pending, running, passed, failed, error |
result_json | string | No | JSON-encoded result data |
error_message | string | No | Error message if failed |
duration_ms | int | No | Execution duration in milliseconds |
Get Test Run
GET /api/v1/tests/runs/{run_id}
Auth: Bearer token required.
Cancel Test Run
Cancel a running AI test execution.
POST /api/v1/tests/runs/{run_id}/cancel
Auth: Bearer token required.
Response:
{
"status": "cancellation_requested"
}
Errors:
400— Run is not active or already finished.
Suite Runs
Get Suite Run
Get details of a suite run including all linked test runs.
GET /api/v1/tests/suite-runs/{suite_run_id}
Auth: Bearer token required.
Response:
{
"id": 1,
"suite_id": 1,
"session_id": "uuid-string",
"status": "passed",
"reset_strategy": "clear_data",
"started_at": "2025-01-20T14:00:00",
"finished_at": "2025-01-20T14:05:00",
"duration_ms": 300000,
"error_message": null,
"test_runs": [
{
"id": 1,
"test_case_id": 1,
"status": "passed",
"duration_ms": 15000,
"error_message": null
}
]
}