Back to Documentation

API Reference

Complete reference for the Qualigate REST API. Trigger tests, check status, retrieve results, and configure CI/CD integrations programmatically.

Authentication

All API requests require authentication using an API key. You can pass the key using either header format:

Authentication headers
# Option 1: Authorization header (recommended)
curl -H "Authorization: Bearer qg_your_api_key_here" \
  https://qualigate.app/api/v1/trigger

# Option 2: X-API-Key header
curl -H "X-API-Key: qg_your_api_key_here" \
  https://qualigate.app/api/v1/trigger

Generating API Keys

Go to Settings > API Keys in your dashboard. Click Generate New Key, name it descriptively (e.g., "GitHub Actions CI"), and copy the key. Keys start with qg_ and are only shown once.

Never expose API keys in client-side code, commit them to version control, or include them in URLs. Store keys in environment variables or your CI/CD platform's secret management.

Base URL

https://qualigate.app

All endpoints below are relative to this base URL. Use HTTPS for all requests.

POST

/api/v1/trigger

Trigger one or more test runs. You must provide exactly one of test_case_id, test_suite_id, or project_id.

Request Body

Required (one of):

ParameterTypeDescription
test_case_idUUIDRun a single test case
test_suite_idUUIDRun all test cases in a suite
project_idUUIDRun all test cases in a project

Optional:

ParameterTypeDefaultDescription
browserTypestring"chromium"Browser engine to use
viewportPresetstring"desktop""desktop" | "tablet" | "mobile"
viewportWidthnumberCustom viewport width in pixels
viewportHeightnumberCustom viewport height in pixels
contextobjectCI/CD metadata (see below)

Context Object:

Optional metadata from your CI/CD pipeline. All fields are strings and appear in the Qualigate dashboard for traceability.

FieldDescription
sourceCI provider name (e.g., "github-actions", "jenkins")
pr_numberPull request number
pr_urlPull request URL
shaGit commit SHA
branchGit branch name
repositoryRepository name (e.g., "org/repo")

Examples

Run a Single Test Case

cURL
curl -X POST https://qualigate.app/api/v1/trigger \
  -H "Authorization: Bearer qg_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "test_case_id": "550e8400-e29b-41d4-a716-446655440000",
    "browserType": "chromium",
    "viewportPreset": "desktop",
    "context": {
      "source": "github-actions",
      "pr_number": "42",
      "branch": "main",
      "sha": "abc123def456"
    }
  }'

Response (201 Created)

Single test response
{
  "success": true,
  "test_run_id": "660e8400-e29b-41d4-a716-446655440000",
  "status": "pending",
  "message": "Test run queued successfully"
}

Run All Tests in a Suite

cURL
curl -X POST https://qualigate.app/api/v1/trigger \
  -H "Authorization: Bearer qg_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "test_suite_id": "770e8400-e29b-41d4-a716-446655440000"
  }'

Response (201 Created)

Suite response
{
  "success": true,
  "suite_run_id": "880e8400-e29b-41d4-a716-446655440000",
  "test_count": 5,
  "status": "pending",
  "message": "5 tests queued successfully"
}

Run All Tests in a Project

cURL
curl -X POST https://qualigate.app/api/v1/trigger \
  -H "Authorization: Bearer qg_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "project_id": "990e8400-e29b-41d4-a716-446655440000"
  }'

Response (201 Created)

Project response
{
  "success": true,
  "test_run_ids": [
    "aa0e8400-e29b-41d4-a716-446655440000",
    "bb0e8400-e29b-41d4-a716-446655440000",
    "cc0e8400-e29b-41d4-a716-446655440000"
  ],
  "test_count": 3,
  "status": "pending",
  "message": "3 tests queued successfully"
}

JavaScript / Node.js Example

trigger-test.ts
const response = await fetch("https://qualigate.app/api/v1/trigger", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.QUALIGATE_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    test_case_id: "550e8400-e29b-41d4-a716-446655440000",
    viewportPreset: "desktop",
    context: {
      source: "custom-script",
      branch: "main",
    },
  }),
});

const data = await response.json();
console.log("Test run ID:", data.test_run_id);

Python Example

trigger_test.py
import os
import requests

response = requests.post(
    "https://qualigate.app/api/v1/trigger",
    headers={
        "Authorization": f"Bearer {os.environ['QUALIGATE_API_KEY']}",
        "Content-Type": "application/json",
    },
    json={
        "test_suite_id": "770e8400-e29b-41d4-a716-446655440000",
        "context": {
            "source": "python-script",
            "branch": "develop",
        },
    },
)

data = response.json()
print(f"Suite run ID: {data['suite_run_id']}")
print(f"Tests queued: {data['test_count']}")
GET

/api/v1/trigger

Check the status of a running or completed test. Poll this endpoint after triggering a test to determine when it finishes.

Query Parameters

ParameterTypeDescription
test_run_idUUIDCheck a single test run status
suite_run_idUUIDCheck a suite run status (aggregated across all tests)

Examples

Check Single Test Run

cURL
curl -H "Authorization: Bearer qg_your_api_key" \
  "https://qualigate.app/api/v1/trigger?test_run_id=660e8400-e29b-41d4-a716-446655440000"

Response (200 OK)

Single test run status
{
  "id": "660e8400-e29b-41d4-a716-446655440000",
  "status": "passed",
  "started_at": "2026-01-28T10:30:00Z",
  "completed_at": "2026-01-28T10:32:15Z",
  "duration_ms": 135000,
  "steps_completed": 12,
  "steps_total": 12,
  "error_message": null,
  "video_url": "https://nnkppgzxyitzkfntrthf.supabase.co/storage/v1/object/public/recordings/..."
}

Check Suite Run

cURL
curl -H "Authorization: Bearer qg_your_api_key" \
  "https://qualigate.app/api/v1/trigger?suite_run_id=880e8400-e29b-41d4-a716-446655440000"

Response (200 OK)

Suite run status
{
  "id": "880e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "started_at": "2026-01-28T10:30:00Z",
  "completed_at": "2026-01-28T10:35:00Z",
  "duration_ms": 300000,
  "total_tests": 5,
  "passed_tests": 4,
  "failed_tests": 1
}

Polling Script (Bash)

poll-until-complete.sh
#!/bin/bash
RUN_ID="$1"
API_KEY="$QUALIGATE_API_KEY"

for i in $(seq 1 60); do
  RESULT=$(curl -s -H "Authorization: Bearer $API_KEY" \
    "https://qualigate.app/api/v1/trigger?test_run_id=$RUN_ID")
  STATUS=$(echo $RESULT | jq -r '.status')
  echo "[$i] Status: $STATUS"

  case "$STATUS" in
    passed) echo "Test passed!"; exit 0 ;;
    failed|error|timeout) echo "Test $STATUS"; exit 1 ;;
  esac

  sleep 10
done

echo "Timed out after 10 minutes"
exit 1
GET

/api/v1/results

Get aggregated test results for multiple test runs or a suite. Useful for generating CI reports or dashboard summaries.

Query Parameters

ParameterTypeDescription
test_run_idsstringComma-separated list of test run UUIDs
suite_run_idUUIDSuite run ID to get all results for

Examples

Get Multiple Test Results

cURL
curl -H "Authorization: Bearer qg_your_api_key" \
  "https://qualigate.app/api/v1/results?test_run_ids=aa0e8400-e29b-41d4-a716-446655440000,bb0e8400-e29b-41d4-a716-446655440000"

Response (200 OK)

Aggregated results
{
  "total_tests": 2,
  "passed_tests": 1,
  "failed_tests": 1,
  "status": "failed",
  "results": [
    {
      "test_run_id": "aa0e8400-e29b-41d4-a716-446655440000",
      "test_case_name": "User Login Flow",
      "status": "passed",
      "duration_ms": 45000,
      "dashboard_url": "https://qualigate.app/test-runs/aa0e8400-e29b-41d4-a716-446655440000"
    },
    {
      "test_run_id": "bb0e8400-e29b-41d4-a716-446655440000",
      "test_case_name": "Checkout Process",
      "status": "failed",
      "duration_ms": 60000,
      "error_message": "Element not found: button[data-test='submit-order']",
      "dashboard_url": "https://qualigate.app/test-runs/bb0e8400-e29b-41d4-a716-446655440000"
    }
  ]
}

Get Suite Results

cURL
curl -H "Authorization: Bearer qg_your_api_key" \
  "https://qualigate.app/api/v1/results?suite_run_id=880e8400-e29b-41d4-a716-446655440000"

Response (200 OK)

Suite results
{
  "suite_run_id": "880e8400-e29b-41d4-a716-446655440000",
  "suite_name": "Critical User Flows",
  "total_tests": 5,
  "passed_tests": 4,
  "failed_tests": 1,
  "status": "failed",
  "results": [
    {
      "test_run_id": "cc0e8400-e29b-41d4-a716-446655440000",
      "test_case_name": "User Login",
      "status": "passed",
      "duration_ms": 30000,
      "dashboard_url": "https://qualigate.app/test-runs/cc0e8400-e29b-41d4-a716-446655440000"
    }
  ]
}
GET

/api/v1/ci-config

Retrieve the CI/CD configuration for a project, including the trigger settings and associated test suite.

Query Parameters

ParameterTypeDescription
project_idUUIDThe project to retrieve CI configuration for

Example

cURL
curl -H "Authorization: Bearer qg_your_api_key" \
  "https://qualigate.app/api/v1/ci-config?project_id=990e8400-e29b-41d4-a716-446655440000"

Response (200 OK)

CI config response
{
  "project_id": "990e8400-e29b-41d4-a716-446655440000",
  "project_name": "E-commerce Site",
  "ci_config": {
    "provider": "github-actions",
    "trigger_on": ["push", "pull_request"],
    "branches": ["main", "develop"],
    "test_suite_id": "770e8400-e29b-41d4-a716-446655440000"
  }
}

Rate Limits

EndpointLimitWindow
/api/v1/trigger (POST)30 requestsPer minute, per API key
/api/v1/trigger (GET)30 requestsPer minute, per API key
/api/v1/results30 requestsPer minute, per API key

When you exceed the rate limit, the API returns a 429 Too Many Requests response with a retry_after field indicating how many seconds to wait. Implement exponential backoff in your polling logic.

Status Values

StatusTerminal?Description
pendingNoTest is queued and waiting to start
runningNoTest is currently executing in the browser
passedYesAll steps and assertions completed successfully
failedYesAn assertion failed or a required element was not found
errorYesAn unexpected error occurred (browser crash, network failure)
timeoutYesTest exceeded the maximum execution time
canceledYesTest was manually canceled by a user

Keep polling while status is pending or running. Stop when a terminal status is reached.

Error Responses

All error responses use a consistent JSON format:

Error format
{
  "error": "Error Type",
  "message": "Human-readable description of what went wrong"
}

401 Unauthorized

Missing or invalid API key. Ensure the key is active and correctly formatted in the Authorization or X-API-Key header.

json
{
  "error": "Unauthorized",
  "message": "Missing or invalid API key"
}

403 Forbidden

The API key is valid but does not have access to the requested resource. Check that the test case, suite, or project belongs to the same account.

json
{
  "error": "Forbidden",
  "message": "You don't have access to this resource"
}

404 Not Found

The specified test case, suite, project, or test run does not exist. Verify the UUID is correct.

json
{
  "error": "Not Found",
  "message": "Test case not found"
}

429 Too Many Requests

Rate limit exceeded. Wait the number of seconds specified in retry_after before retrying.

json
{
  "error": "Too Many Requests",
  "message": "Rate limit exceeded. Please try again later.",
  "retry_after": 60
}

500 Internal Server Error

An unexpected server error. Retry with exponential backoff. If the issue persists, contact support.

json
{
  "error": "Internal Server Error",
  "message": "An unexpected error occurred. Please try again later."
}

Best Practices

1. Poll with Appropriate Intervals

After triggering a test, poll the status endpoint every 10 seconds. Most tests complete in 1--3 minutes. Set a maximum timeout of 10 minutes and handle the timeout case in your pipeline.

2. Implement Exponential Backoff

When you receive a 429 response, use the retry_after value. For 500 errors, start with a 1-second delay and double it on each retry up to a maximum of 30 seconds.

3. Include CI Context

Always pass the context object with branch, SHA, and PR number. This metadata appears in the Qualigate dashboard and makes it easy to trace test failures back to the specific commit or pull request that caused them.

4. Secure Your API Keys

Store API keys in environment variables or secret management systems (GitHub Secrets, AWS Secrets Manager, Vault). Use separate keys for each environment (dev, staging, production) so you can rotate them independently.

5. Fail Builds on Test Failure

In CI/CD pipelines, exit with a non-zero code when tests fail. This prevents broken code from being deployed. Check the status field for "failed", "error", or "timeout" values.

Quick Start Examples

Complete working examples for common integration scenarios.

GitHub Actions Workflow

Add this to .github/workflows/e2e.yml in your repository. Set QUALIGATE_API_KEY as a repository secret and QUALIGATE_SUITE_ID as a variable.

.github/workflows/e2e.yml
name: E2E Tests

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  e2e:
    runs-on: ubuntu-latest
    steps:
      - name: Trigger Qualigate Tests
        id: trigger
        run: |
          RESPONSE=$(curl -s -X POST https://qualigate.app/api/v1/trigger \
            -H "Authorization: Bearer ${{ secrets.QUALIGATE_API_KEY }}" \
            -H "Content-Type: application/json" \
            -d '{
              "test_suite_id": "${{ vars.QUALIGATE_SUITE_ID }}",
              "context": {
                "source": "github-actions",
                "branch": "${{ github.ref_name }}",
                "sha": "${{ github.sha }}",
                "pr_number": "${{ github.event.pull_request.number }}",
                "repository": "${{ github.repository }}"
              }
            }')
          echo "run_id=$(echo $RESPONSE | jq -r '.suite_run_id // .test_run_id')" >> $GITHUB_OUTPUT

      - name: Wait for Results
        run: |
          for i in $(seq 1 60); do
            RESULT=$(curl -s \
              -H "Authorization: Bearer ${{ secrets.QUALIGATE_API_KEY }}" \
              "https://qualigate.app/api/v1/trigger?suite_run_id=${{ steps.trigger.outputs.run_id }}")
            STATUS=$(echo $RESULT | jq -r '.status')
            echo "Attempt $i: $STATUS"
            if [ "$STATUS" = "completed" ] || [ "$STATUS" = "passed" ]; then
              exit 0
            elif [ "$STATUS" = "failed" ]; then
              echo "Tests failed"
              exit 1
            fi
            sleep 10
          done
          echo "Timed out"
          exit 1

Node.js Script (Trigger + Poll)

run-e2e.ts
async function runE2ETests(suiteId: string): Promise<boolean> {
  const API_KEY = process.env.QUALIGATE_API_KEY!;
  const BASE = "https://qualigate.app";

  // 1. Trigger
  const triggerRes = await fetch(`${BASE}/api/v1/trigger`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ test_suite_id: suiteId }),
  });
  const { suite_run_id } = await triggerRes.json();
  console.log(`Suite run started: ${suite_run_id}`);

  // 2. Poll
  for (let i = 0; i < 60; i++) {
    await new Promise((r) => setTimeout(r, 10000));
    const statusRes = await fetch(
      `${BASE}/api/v1/trigger?suite_run_id=${suite_run_id}`,
      { headers: { Authorization: `Bearer ${API_KEY}` } }
    );
    const data = await statusRes.json();
    console.log(`[${i + 1}] Status: ${data.status}`);

    if (data.status === "completed" || data.status === "passed") {
      console.log(`Passed: ${data.passed_tests}/${data.total_tests}`);
      return true;
    }
    if (data.status === "failed") {
      console.log(`Failed: ${data.failed_tests}/${data.total_tests}`);
      return false;
    }
  }
  throw new Error("Timed out waiting for test results");
}

// Usage
runE2ETests("your-suite-uuid")
  .then((ok) => process.exit(ok ? 0 : 1))
  .catch(() => process.exit(1));

Need Help?

If you have questions or need assistance with the API: