API Reference
Complete reference for the QA Studio REST API. All endpoints use JSON request/response bodies and are served from http://localhost:3001 by default.
General Conventions
- Base URL:
http://localhost:3001/api(configurable via thePORTenvironment variable) - Content-Type: All request bodies must be
application/json - IDs: All resource IDs are generated server-side as unique strings
- Timestamps: All timestamps are ISO 8601 strings (e.g.,
2026-02-20T14:30:00.000Z)
Pagination
List endpoints that support pagination accept the following query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
limit |
number | 20 | Number of items to return (min: 1, max: 100) |
offset |
number | 0 | Number of items to skip |
Paginated responses include metadata:
{
"data": [ ... ],
"total": 42,
"limit": 20,
"offset": 0
}
Error Responses
Errors return an appropriate HTTP status code with a JSON body:
// 404 Not Found
{ "error": "Project not found" }
// 400 Bad Request (validation error)
{ "error": [{ "code": "too_small", "minimum": 1, "path": ["name"], "message": "String must contain at least 1 character(s)" }] }
SSE Streaming
Run endpoints support Server-Sent Events (SSE) for real-time progress. To enable SSE, set the Accept header to text/event-stream. The response streams events in the following format:
data: {"type":"step-result","stepResult":{...},"stepIndex":0}
data: {"type":"step-result","stepResult":{...},"stepIndex":1}
data: {"type":"complete","run":{...}}
Each data: line contains a JSON object followed by two newlines. The stream ends when the complete event is sent.
Projects
List All Projects
GET /api/projects
Returns an array of all projects, ordered by creation date.
[
{
"id": "proj_abc123",
"name": "My Website",
"baseUrl": "https://example.com",
"description": "Main website tests",
"createdAt": "2026-02-01T10:00:00.000Z",
"updatedAt": "2026-02-15T14:30:00.000Z"
}
]
Get Project
GET /api/projects/:id
Returns a single project by ID. Returns 404 if not found.
Create Project
POST /api/projects
{
"name": "My Website",
"baseUrl": "https://example.com",
"description": "Main website tests"
}
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Project name (1-100 characters) |
baseUrl |
string | No | Default base URL (must be a valid URL) |
description |
string | No | Project description (max 500 characters) |
Returns 201 with the created project object.
Update Project
PUT /api/projects/:id
{
"name": "Updated Name",
"baseUrl": "https://staging.example.com",
"description": "Updated description",
"variables": {
"API_KEY": "sk_test_new_key",
"BASE_URL": "https://staging.example.com"
}
}
All fields are optional. Only provided fields are updated. The variables field accepts a string-to-string record for environment variable substitution.
Delete Project
DELETE /api/projects/:id
Deletes a project and returns { "success": true }.
Export Project
GET /api/projects/:id/export
Returns a complete JSON export of the project including all tests and flows. See the Export & Import page for format details.
Import Into Project
POST /api/projects/:id/import
Accepts a test or project export JSON body. Creates new tests and flows with new IDs. Returns { "success": true, "importedTests": N, "importedFlows": N }.
Tests
List Tests for a Project
GET /api/projects/:projectId/tests
Returns all tests in a project, ordered by creation date. Each test is enriched with last run data:
[
{
"id": "test_xyz789",
"projectId": "proj_abc123",
"name": "Login Flow",
"description": "Verifies login works",
"config": { "browser": "chromium", "viewport": { "width": 1280, "height": 720 }, "timeout": 30000, "headless": true, "useRealChrome": false },
"steps": [ ... ],
"createdAt": "2026-02-01T10:00:00.000Z",
"updatedAt": "2026-02-15T14:30:00.000Z",
"lastRunStatus": "passed",
"lastRunDurationMs": 3450,
"lastRunAt": "2026-02-20T08:00:00.000Z"
}
]
Get Test
GET /api/tests/:id
Create Test
POST /api/tests
{
"projectId": "proj_abc123",
"name": "Homepage Test",
"description": "Verify homepage loads",
"config": {
"browser": "chromium",
"viewport": { "width": 1280, "height": 720 },
"timeout": 30000,
"headless": true,
"useRealChrome": false
},
"steps": [
{ "id": "step_1", "action": "goto", "url": "https://example.com" },
{ "id": "step_2", "action": "assert", "assertType": "title", "condition": "contains", "value": "Example" }
]
}
| Field | Type | Required | Description |
|---|---|---|---|
projectId |
string | Yes | Parent project ID |
name |
string | Yes | Test name (1-100 characters) |
description |
string | No | Description (max 500 characters) |
config |
object | No | Browser config (merged with defaults) |
steps |
array | No | Array of test step objects |
Returns 201 with the created test.
Update Test
PUT /api/tests/:id
Accepts the same fields as create (except projectId). All fields are optional. Config is merged with existing config.
Delete Test
DELETE /api/tests/:id
Clone Test
POST /api/tests/:id/clone
Creates a copy of the test with " (Copy)" appended to the name. All steps receive new IDs. Returns 201 with the cloned test.
Run Test
POST /api/tests/:id/run
Executes the test. Supports two response modes:
- Standard: Returns the complete run result as JSON when execution finishes.
- SSE Streaming: Set
Accept: text/event-streamto receive real-time step-by-step progress events.
SSE events for single test runs:
// Step result (sent after each step completes)
{ "type": "step-result", "stepResult": { "stepId": "step_1", "status": "passed", ... }, "stepIndex": 0 }
// Complete (sent when test finishes)
{ "type": "complete", "run": { "id": "run_abc", "status": "passed", "durationMs": 3450, ... } }
Get Test Runs
GET /api/tests/:id/runs?limit=20&offset=0
Returns paginated run history for a test, ordered by most recent first.
Export Test
GET /api/tests/:id/export
Returns the test as a portable JSON export. See Export & Import.
Runs
Get Run
GET /api/runs/:id
Returns a single run by ID, including all step results, screenshots, error messages, and timing data.
{
"id": "run_abc123",
"testId": "test_xyz789",
"status": "passed",
"durationMs": 3450,
"stepResults": [
{ "stepId": "step_1", "status": "passed", "durationMs": 1200 },
{ "stepId": "step_2", "status": "passed", "durationMs": 250, "screenshotPath": "data/screenshots/run_abc123_step_2.png" }
],
"error": null,
"screenshotPath": null,
"videoPath": null,
"createdAt": "2026-02-20T14:30:00.000Z"
}
Suites
List Suites
GET /api/projects/:projectId/suites
Returns all suites in a project, ordered by creation date.
Create Suite
POST /api/suites
{
"projectId": "proj_abc123",
"name": "Smoke Tests",
"testIds": ["test_1", "test_2", "test_3"]
}
Update Suite
PUT /api/suites/:id
Update the suite name and/or test IDs. Both fields are optional.
Delete Suite
DELETE /api/suites/:id
Run All Project Tests
POST /api/projects/:projectId/run-all
{
"concurrency": 3
}
Runs all tests in the project with the specified concurrency (1-5, default: 1). Responds with an SSE stream:
// Test started
{ "type": "test-start", "testId": "test_1", "testName": "Login Flow", "index": 0 }
// Test completed
{ "type": "test-complete", "testId": "test_1", "testName": "Login Flow", "index": 0, "status": "passed", "durationMs": 3200, "error": null, "runId": "run_abc" }
// Suite complete (final event)
{ "type": "suite-complete", "suiteRunId": "sr_xyz", "status": "passed", "passed": 5, "failed": 0, "durationMs": 12400 }
Run Suite
POST /api/suites/:id/run
Same behavior as run-all, but only executes the tests in the specified suite. Accepts the same concurrency body parameter. Returns SSE events in the same format.
List Suite Runs
GET /api/projects/:projectId/suite-runs?limit=20&offset=0
Returns paginated suite run history for a project.
Get Suite Run
GET /api/suite-runs/:id
Returns a single suite run record including status, test counts, run IDs, and duration.
Flows
List Flows
GET /api/projects/:projectId/flows
Returns all reusable flows in a project, ordered by creation date.
Get Flow
GET /api/flows/:id
Create Flow
POST /api/flows
{
"projectId": "proj_abc123",
"name": "Login Steps",
"description": "Reusable login sequence",
"steps": [
{ "id": "fs_1", "action": "goto", "url": "{{BASE_URL}}/login" },
{ "id": "fs_2", "action": "fill", "selector": "#email", "value": "{{USER_EMAIL}}" },
{ "id": "fs_3", "action": "click", "selector": "button[type=submit]" }
]
}
| Field | Type | Required | Description |
|---|---|---|---|
projectId |
string | Yes | Parent project ID |
name |
string | Yes | Flow name (1-100 characters) |
description |
string | No | Description (max 500 characters) |
steps |
array | No | Array of step objects |
Update Flow
PUT /api/flows/:id
Update a flow's name, description, or steps. All fields are optional.
Delete Flow
DELETE /api/flows/:id
Visual Regression
Get Baselines
GET /api/tests/:testId/baselines
Returns all baseline screenshots for a test.
[
{
"id": "bl_abc123",
"testId": "test_xyz789",
"stepId": "step_5",
"screenshotPath": "data/screenshots/baseline_step_5.png",
"runId": "run_def456",
"createdAt": "2026-02-15T10:00:00.000Z"
}
]
Set Baselines from Run
POST /api/tests/:testId/baselines/from-run/:runId
Sets baseline screenshots from a specific run. Extracts all screenshots from the run's step results, deletes any existing baselines (and their associated diffs) for the test, and creates new baseline records. Returns 201 with the new baselines array.
Returns 400 if the run contains no screenshots.
Get Diffs for a Run
GET /api/runs/:runId/diffs
Returns all screenshot diffs generated for a specific run, including baseline path, actual path, diff image path, mismatch percentage, and status (pending, approved, or rejected).
Approve Diff
POST /api/diffs/:id/approve
Approves a screenshot diff and updates the corresponding baseline to use the actual screenshot from the new run. Returns { "success": true, "status": "approved" }.
Reject Diff
POST /api/diffs/:id/reject
Rejects a screenshot diff (the baseline remains unchanged). Returns { "success": true, "status": "rejected" }.
Delete Baseline
DELETE /api/baselines/:id
Deletes a baseline and all its associated screenshot diffs.
Analytics
Summary
GET /api/projects/:projectId/analytics/summary
Returns total tests, total runs, pass rate percentage, average duration in milliseconds, and test status counts (passing, failing, noRuns). See the Analytics page for details.
Trends
GET /api/projects/:projectId/analytics/trends?days=30
Returns daily pass/fail statistics. The days parameter controls the lookback window (default: 30).
Flaky Tests
GET /api/projects/:projectId/analytics/flaky
Returns flaky test analysis based on the last 10 runs per test. See the Flaky Test Detection section for the algorithm details.
Recorder
Start Recording
POST /api/recorder/start
{
"testId": "test_xyz789",
"startUrl": "https://example.com"
}
Launches a browser and starts capturing user interactions. Returns a session ID:
{
"sessionId": "rec_abc123"
}
Stop Recording
POST /api/recorder/stop
{
"sessionId": "rec_abc123"
}
Stops the recording session and closes the browser. Returns { "success": true }.
WebSocket Stream
GET /api/recorder/ws?sessionId=rec_abc123
Establishes a WebSocket connection that streams captured steps in real-time. Messages are JSON objects:
// Step captured
{ "type": "step", "step": { "action": "click", "selector": "#login-btn", ... } }
// Session ended
{ "type": "disconnect" }
// Error
{ "type": "error", "message": "Session not found" }
The recorder WebSocket endpoint requires WebSocket support in your reverse proxy if you are running behind one. See the Self-Hosting page for nginx configuration.
Schedules
List Schedules
GET /api/projects/:projectId/schedules
Returns all schedules for a project, ordered by creation date.
Create Schedule
POST /api/schedules
{
"projectId": "proj_abc123",
"name": "Nightly Regression",
"cronExpression": "0 0 * * *",
"suiteId": "suite_xyz789",
"enabled": true
}
See Scheduled Runs for cron expression format and behavior.
Update Schedule
PUT /api/schedules/:id
Update name, cronExpression, suiteId, or enabled status. All fields are optional.
Delete Schedule
DELETE /api/schedules/:id
Unregisters the cron job and deletes the schedule record.
Admin
Manual Cleanup
POST /api/admin/cleanup
Triggers manual cleanup of expired run data based on the RETENTION_DAYS environment variable (default: 30). Removes old runs, suite runs, screenshots, videos, and diff images. Returns { "success": true }.
Health
Health Check
GET /api/health
{
"status": "ok",
"timestamp": "2026-02-20T14:30:00.000Z"
}
A simple health check endpoint that confirms the server is running and responsive. Useful for monitoring and load balancer health checks.