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 the PORT environment 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:

Paginated Response
{
  "data": [ ... ],
  "total": 42,
  "limit": 20,
  "offset": 0
}

Error Responses

Errors return an appropriate HTTP status code with a JSON body:

Error Response
// 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:

SSE 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

HTTP
GET /api/projects

Returns an array of all projects, ordered by creation date.

Response 200
[
  {
    "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

HTTP
GET /api/projects/:id

Returns a single project by ID. Returns 404 if not found.

Create Project

HTTP
POST /api/projects
Request Body
{
  "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

HTTP
PUT /api/projects/:id
Request Body
{
  "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

HTTP
DELETE /api/projects/:id

Deletes a project and returns { "success": true }.

Export Project

HTTP
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

HTTP
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

HTTP
GET /api/projects/:projectId/tests

Returns all tests in a project, ordered by creation date. Each test is enriched with last run data:

Response 200
[
  {
    "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

HTTP
GET /api/tests/:id

Create Test

HTTP
POST /api/tests
Request Body
{
  "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

HTTP
PUT /api/tests/:id

Accepts the same fields as create (except projectId). All fields are optional. Config is merged with existing config.

Delete Test

HTTP
DELETE /api/tests/:id

Clone Test

HTTP
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

HTTP
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-stream to receive real-time step-by-step progress events.

SSE events for single test runs:

SSE Events
// 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

HTTP
GET /api/tests/:id/runs?limit=20&offset=0

Returns paginated run history for a test, ordered by most recent first.

Export Test

HTTP
GET /api/tests/:id/export

Returns the test as a portable JSON export. See Export & Import.

Runs

Get Run

HTTP
GET /api/runs/:id

Returns a single run by ID, including all step results, screenshots, error messages, and timing data.

Response 200
{
  "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

HTTP
GET /api/projects/:projectId/suites

Returns all suites in a project, ordered by creation date.

Create Suite

HTTP
POST /api/suites
Request Body
{
  "projectId": "proj_abc123",
  "name": "Smoke Tests",
  "testIds": ["test_1", "test_2", "test_3"]
}

Update Suite

HTTP
PUT /api/suites/:id

Update the suite name and/or test IDs. Both fields are optional.

Delete Suite

HTTP
DELETE /api/suites/:id

Run All Project Tests

HTTP
POST /api/projects/:projectId/run-all
Request Body (optional)
{
  "concurrency": 3
}

Runs all tests in the project with the specified concurrency (1-5, default: 1). Responds with an SSE stream:

SSE Events
// 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

HTTP
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

HTTP
GET /api/projects/:projectId/suite-runs?limit=20&offset=0

Returns paginated suite run history for a project.

Get Suite Run

HTTP
GET /api/suite-runs/:id

Returns a single suite run record including status, test counts, run IDs, and duration.

Flows

List Flows

HTTP
GET /api/projects/:projectId/flows

Returns all reusable flows in a project, ordered by creation date.

Get Flow

HTTP
GET /api/flows/:id

Create Flow

HTTP
POST /api/flows
Request Body
{
  "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

HTTP
PUT /api/flows/:id

Update a flow's name, description, or steps. All fields are optional.

Delete Flow

HTTP
DELETE /api/flows/:id

Visual Regression

Get Baselines

HTTP
GET /api/tests/:testId/baselines

Returns all baseline screenshots for a test.

Response 200
[
  {
    "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

HTTP
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

HTTP
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

HTTP
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

HTTP
POST /api/diffs/:id/reject

Rejects a screenshot diff (the baseline remains unchanged). Returns { "success": true, "status": "rejected" }.

Delete Baseline

HTTP
DELETE /api/baselines/:id

Deletes a baseline and all its associated screenshot diffs.

Analytics

Summary

HTTP
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.

HTTP
GET /api/projects/:projectId/analytics/trends?days=30

Returns daily pass/fail statistics. The days parameter controls the lookback window (default: 30).

Flaky Tests

HTTP
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

HTTP
POST /api/recorder/start
Request Body
{
  "testId": "test_xyz789",
  "startUrl": "https://example.com"
}

Launches a browser and starts capturing user interactions. Returns a session ID:

Response 200
{
  "sessionId": "rec_abc123"
}

Stop Recording

HTTP
POST /api/recorder/stop
Request Body
{
  "sessionId": "rec_abc123"
}

Stops the recording session and closes the browser. Returns { "success": true }.

WebSocket Stream

WebSocket
GET /api/recorder/ws?sessionId=rec_abc123

Establishes a WebSocket connection that streams captured steps in real-time. Messages are JSON objects:

WebSocket Messages
// Step captured
{ "type": "step", "step": { "action": "click", "selector": "#login-btn", ... } }

// Session ended
{ "type": "disconnect" }

// Error
{ "type": "error", "message": "Session not found" }
Info

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

HTTP
GET /api/projects/:projectId/schedules

Returns all schedules for a project, ordered by creation date.

Create Schedule

HTTP
POST /api/schedules
Request Body
{
  "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

HTTP
PUT /api/schedules/:id

Update name, cronExpression, suiteId, or enabled status. All fields are optional.

Delete Schedule

HTTP
DELETE /api/schedules/:id

Unregisters the cron job and deletes the schedule record.

Admin

Manual Cleanup

HTTP
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

HTTP
GET /api/health
Response 200
{
  "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.