Run Tests API
Use the Test-Lab API to trigger test plan execution programmatically. Run single tests, batch multiple plans, or trigger all tests for a project with CI/CD build tracking.
Run Tests API
The Run Tests endpoint lets you trigger test plan execution programmatically from your CI/CD pipeline, scripts, or any HTTP client. You can run a single test plan, batch multiple plans in one request, or trigger every plan in a project — all with optional build ID tracking for traceability.
POST https://test-lab.ai/api/v1/runAuthentication
Authorization: Bearer tl_xxxxxRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
testPlanIds | number[] | string | One of these | Run one or more test plans (e.g. [1,2,3] or "1,2,3") |
projectId | number | One of these | Run all test plans for a project |
label | string | One of these | Run all test plans tagged with this label name |
testType | string | No | "quickTest" or "deepTest" (default: plan's default) |
buildId | string | No | CI build/commit identifier (max 100 chars) |
cookies | array | No | Authentication cookies to inject (see below) |
preferScript | boolean | No | When true, each plan runs as its saved Playwright script (deterministic, no LLM cost). Plans without a generated script fall back to an AI run automatically. |
triggerPipelinePreSteps | boolean | No | Default false. When false, plans configured as a pipeline pre-step (referenced by another plan as a pre-step) are silently excluded from batch runs and reported with status: "skipped". Pre-steps usually expect input parameters or specific browser state and produce false-failures when run solo. Pass true to include them — useful when you explicitly want to smoke-test a login pre-step on its own with default credentials. |
Exactly one of testPlanIds, projectId, or label must be provided. Every selector is scoped to the API key's account; the API never resolves plans, projects, or labels belonging to other accounts.
Cookie Object
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Cookie name |
value | string | Yes | Cookie value |
domain | string | Yes | Domain (e.g. .example.com) |
Cookies can also be configured at the project or test plan level in the dashboard. Runtime cookies override stored cookies.
Examples
Test Plans
Using an array:
curl -X POST https://test-lab.ai/api/v1/run \
-H "Authorization: Bearer tl_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"testPlanIds": [ID_1, ID_2, ID_3],
"testType": "deepTest"
}'Using a comma-separated string:
curl -X POST https://test-lab.ai/api/v1/run \
-H "Authorization: Bearer tl_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"testPlanIds": "ID_1,ID_2,ID_3"
}'Response (multiple plans):
{
"jobs": [
{
"jobId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "running",
"testPlanId": YOUR_TEST_PLAN_ID,
"testPlanName": "Login Flow",
"testType": "deepTest"
},
{
"jobId": "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy",
"status": "running",
"testPlanId": ID_2,
"testPlanName": "Signup Flow",
"testType": "deepTest"
}
],
"triggered": 2,
"failed": 0
}All Plans for a Project
curl -X POST https://test-lab.ai/api/v1/run \
-H "Authorization: Bearer tl_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"projectId": YOUR_PROJECT_ID
}'All Plans with a Label
Run every test plan tagged with a given label. Labels are account-scoped and matched by name (the same string you'd see on the plan in the dashboard).
curl -X POST https://test-lab.ai/api/v1/run \
-H "Authorization: Bearer tl_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"label": "smoke"
}'Useful for grouping smoke tests, regression suites, or environment-specific subsets without hardcoding plan IDs in CI.
Run as Script (Cheaper, Deterministic)
When a test plan has a generated Playwright script (Save as Script from a passing AI run), the API can run that script instead of spinning up an AI agent. Add "preferScript": true:
curl -X POST https://test-lab.ai/api/v1/run \
-H "Authorization: Bearer tl_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"projectId": YOUR_PROJECT_ID,
"preferScript": true,
"buildId": "abc123"
}'Each plan in the request is checked individually. Plans with an active or stale script run as scripts; plans without a script fall back to a normal AI run, so flipping the flag never silently breaks a plan that hasn't been scriptified yet. Script runs do not consume LLM credits.
Pipelines (plans with pre-steps)
A plan with pre-steps configured in the dashboard runs as a pipeline automatically — pre-steps execute first, then the main test, all sharing browser state (cookies, localStorage, current URL). No special API parameter needed; just include the master plan in testPlanIds (or its projectId / label).
Behavior with preferScript: true:
- If every step in the pipeline (every pre-step + the main test) has a saved script for the chosen device, the whole pipeline runs deterministically as a script pipeline. State chains between steps via Playwright
storageState. No LLM cost. - If any step is missing a script, the entire pipeline falls back to AI mode (all steps run as AI, including those that do have scripts). Mixing script + AI mid-pipeline can't share state cleanly across the boundary, so we keep the whole chain on one execution mode.
Response shape: the jobs[] entry returned for a pipeline run carries the main plan's job ID (the last position in the chain). Pre-step jobs share the same pipeline_id and run_group_id and can be looked up by querying jobs with that group ID. testType is script for the script-pipeline branch, otherwise the main plan's recipe.
Pre-step plans listed alongside their masters: the triggerPipelinePreSteps flag (covered above) controls plans that ARE pre-steps (i.e. referenced by another plan). The default false skips them when listed in a batch. This is independent from the pipeline-execution behavior described here, which kicks in for plans that HAVE pre-steps.
With Build ID (CI Integration)
curl -X POST https://test-lab.ai/api/v1/run \
-H "Authorization: Bearer tl_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"testPlanIds": [YOUR_TEST_PLAN_ID],
"buildId": "abc123"
}'With Authentication Cookies
curl -X POST https://test-lab.ai/api/v1/run \
-H "Authorization: Bearer tl_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"testPlanIds": [YOUR_TEST_PLAN_ID],
"cookies": [
{ "name": "session", "value": "abc123xyz", "domain": ".myapp.com" }
]
}'Response
The endpoint always returns the same array shape, regardless of which selector you used:
| Field | Type | Description |
|---|---|---|
jobs | array | Array of job objects |
jobs[].jobId | string | UUID of each job |
jobs[].status | string | Status of each job (running, queued, pending, error, or skipped) |
jobs[].testPlanId | number | Test plan ID |
jobs[].testPlanName | string | Test plan name |
jobs[].testType | string | Test mode (quickTest, deepTest, or script) |
jobs[].error | string | Error if the job failed to start, or the reason a plan was skipped |
triggered | number | Count of successfully triggered jobs (excludes error and skipped) |
failed | number | Count of failed jobs |
skipped | number | Count of plans excluded from this run (e.g. pre-step plans when triggerPipelinePreSteps is not set) |
buildId | string | Build ID if provided |
Error Responses
Invalid API Key
{
"error": "Invalid API key"
}Status: 401
Insufficient Credits
{
"error": "Insufficient credits. Please top up to continue running tests."
}Status: 402
Test Plan Not Found
{
"error": "No test plans found"
}Status: 404
Invalid Parameters
{
"error": "One of testPlanIds, projectId, or label is required"
}Status: 400
Code Examples
JavaScript/Node.js
const response = await fetch('https://test-lab.ai/api/v1/run', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.TESTLAB_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
testPlanIds: [YOUR_TEST_PLAN_ID],
testType: 'quickTest',
buildId: process.env.GITHUB_SHA,
}),
});
const data = await response.json();
console.log('Triggered:', data.triggered, 'jobs');Python
import requests
import os
response = requests.post(
'https://test-lab.ai/api/v1/run',
headers={
'Authorization': f'Bearer {os.environ["TESTLAB_API_KEY"]}',
'Content-Type': 'application/json',
},
json={
'testPlanIds': [YOUR_TEST_PLAN_ID],
'testType': 'quickTest',
'buildId': os.environ.get('GITHUB_SHA'),
}
)
data = response.json()
print(f'Triggered: {data["triggered"]} jobs')