Endpoints

Runs

How to manage test runs using the public API

The runs endpoints allow you to create and manage test executions in your project. You can create new runs, list existing runs, manage test cases within runs, and track their results. Write operations (create/update/delete) can only be performed by users with role test runner or with higher privileges.

Types of Runs

QA Sphere supports three types of test runs:

1. User Selection (Static Structure)

  • Specified by type: "static_struct"
  • Test cases can be selected by their IDs or using filters (folders, tags, priorities)
  • Test cases in the run are fixed after creation unless manually updated
  • Updates to versioned test case properties, such as title and steps, are reflected for test cases with open statuses

2. Static Runs

  • Specified by type: "static"
  • Test cases can be selected directly by IDs or using filters (folders, tags, priorities)
  • Similar to Static Structure in that test cases are fixed after creation
  • Updates to versioned test case properties, such as title and steps, are not reflected in the run, even for test cases with open statuses

3. Live Runs

  • Specified by type: "live"
  • Only dynamic selection based on folder, tag, and priority filters
  • Test cases are automatically added/removed when they match or do not match filter criteria
  • Supports multiple query plans for flexible test case selection
  • Updates to versioned test case properties, such as title and steps, are reflected for test cases with open statuses
  1. Updates to test cases are never propagated to closed runs
  2. For live and user selection runs, test case versions are fixed once the status is non-open. As a result, updates to versioned test case properties, such as title and steps, are not reflected in the run
  3. Changes to the folder and position of test cases are always propagated to all run types, except closed runs, because these changes are not versioned. This means that such updates do not create a new test case version and are applied to all existing versions of the test case

Test Case Selection

Test cases can be selected in two ways:

  1. Direct Selection: Use tcaseIds to directly specify the test cases
  2. Using filters:
    • folderIds: Select test cases from specific folders, including those within subfolders
    • tagIds: Select test cases with specific tags
    • priorities: Select test cases with specific priority levels
    • If any of these filters is not specified or is left empty, all test cases are selected without filtering based on that criterion
    • The resulting list of test cases is obtained by applying a logical AND to these conditions

This selection method is referred to as a Query Plan.

  • For static and user selection runs, only single query plan can be specified. When using filters, the system automatically resolves them to a fixed set of test cases at the time of creation
  • For live runs, only filter-based selection is allowed, and multiple query plans can be specified. The results of all query plans are combined using a union to create the final list of test cases. Additionally, as test case properties change, test cases are automatically added to or removed from the run according to the query plans
  1. Only standalone and filled test case types are allowed in a run.

List Project Runs

GET/api/public/v0/project/{project_id}/run

Returns all runs in a project with their current status.

Query Parameters

ParameterDescriptionExample
closedFilter by run statusclosed=true or closed=false
milestoneIdsFilter by milestonemilestoneIds=1&milestoneIds=2
limitMaximum number of runs to returnlimit=10

Example Request

curl \
  -H "Authorization: ApiKey your.api.key.here" \
  https://your-company.your-region-code.qasphere.com/api/public/v0/project/BD/run

Response Fields

{
  runs: Array<{
    id: number                     // Unique identifier of the test run
    type: string                   // Type of the run (`static` | `static_struct` | `live`)
    title: string                  // Title of the test run
    description: html              // Description of the test run
    projectId: string              // ID of the project this run belongs to
    project: {                     // Project details
      id: string                   //   Project unique identifier
      code: string                 //   Project code
      title: string                //   Project title
    }
    planId: number | null          // ID of the test plan to which the run belongs to (if any)
    plan: {                        // Test plan details (if any)
      title: string                //   Test plan title
    } | null
    milestoneId: number | null     // ID of associated milestone (if any)
    milestone: {                   // Milestone details (if any)
      title: string                //   Milestone Title
    } | null
    assignmentId: number | null    // ID of the assigned user (if any)
    assignment: {                  // Assignee details (if any)
      id: number                   //   User ID
      email: string                //   User email
      name: string                 //   User display name
      avatar: string               //   URL to user's avatar
      role: string                 //   User role in the project
    } | null
    configurationId: number | null // ID of the configuration associated with the run (if any)
    configuration: {               // Configuration details (if any)
      id: string                   //   Configuration ID
      title: string                //   Configuration title
      createdAt: string            //   Configuration creation timestamp
      updatedAt: string            //   Configuration last update timestamp
    } | null
    statusCounts: {                // Count of run test cases by status
      all: number                  //   Total test cases
      blocked: number              //   Blocked test cases
      failed: number               //   Failed test cases
      open: number                 //   Open test cases
      passed: number               //   Passed test cases
      skipped: number              //   Skipped test cases
      custom1: number              //   Count of test cases with first custom status
      custom2: number              //   Count of test cases with second custom status
      custom3: number              //   Count of test cases with third custom status
      custom4: number              //   Count of test cases with fourth custom status
    }
    timeSpent: number | null       // Time spent on the run
    isAutomated: boolean           // Whether the run was created using public APIs
    createdAt: string              // Run creation timestamp
    closedAt: string | null        // Run closure timestamp
    closedByUserId: number | null  // ID of user who closed the run
  }>
}

Create New Run

POST/api/public/v0/project/{project_id}/run

Creates a new test run in the project.

  1. For static/static_struct run types:
    • Only a single query plan should be specified, and either of the two selection methods (direct or filters) can be used
    • When using filters, the system automatically resolves them to a fixed set of test cases at the time of creation
  2. For live run types, only filter-based selection is permitted, and multiple query plans can be specified
  3. Within a given query plan, the filter conditions are combined using a logical AND
  4. The test case lists obtained from different query plans are combined using a union
  5. Only standalone and filled test case types are allowed in a run

Authentication

Requires an API key with at least Test Runner role permissions. See Authentication for more details.

Request Body

{
  title: string                  // Required: Run title
  description?: html             // Optional: Run description
  type: string                   // Required: Run type (`static` | `static_struct` | `live`)
  milestoneId?: number           // Optional: Associated milestone
  configurationId?: string       // Optional: Associated configuration
  assignmentId?: number          // Optional: Assigned user
  queryPlans: Array<{            // Required: Test case selection criteria
    // Direct Selection:
    tcaseIds?: Array<string>     //   Directly specify test cases

    // Using Filters:
    folderIds?: Array<number>    //   Select test cases from folders (including subfolders)
    tagIds?: Array<number>       //   Select test cases with tags
    priorities?: Array<string>   //   Select by priority (`low` | `medium` | `high`)
  }>
}

Field Constraints

  • title: Must be 1-255 characters long and unique within the project
  • description: Maximum 512 characters
  • queryPlans:
    • For non-live runs: Only one query plan is allowed
    • For live runs: Only filter based selection is allowed
  • milestoneId: The milestone must belong to the project and must not be archived
  • assignmentId: Must be an active user with permissions above Viewer role

Example Request - Live Run With Filtered Test Cases

curl \
  -H "Authorization: ApiKey your.api.key.here" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Sprint 23 Regression",
    "description": "<p>Regression test suite for Sprint 23 release</p>",
    "type": "live",
    "milestoneId": 5,
    "queryPlans": [{
      "folderIds": [1, 2],
      "tagIds": [1],
      "priorities": ["high"]
    }, {
      "folderIds": [4, 6],
      "tagIds": [],
      "priorities": ["medium", "high"]
    }]
  }' \
  https://your-company.your-region-code.qasphere.com/api/public/v0/project/BD/run

Example Request - Live Run With All Test Cases

curl \
  -H "Authorization: ApiKey your.api.key.here" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Complete Test Suite",
    "description": "<p>Run with all test cases from the project</p>",
    "type": "live",
    "milestoneId": 5,
    "queryPlans": [{
      "folderIds": [],
      "tagIds": [],
      "priorities": []
    }]
  }' \
  https://your-company.your-region-code.qasphere.com/api/public/v0/project/BD/run

Example Request - Static Run With Specific Test Cases

curl \
  -H "Authorization: ApiKey your.api.key.here" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Specific Test Cases Run",
    "type": "static",
    "queryPlans": [{
      "tcaseIds": ["1CEPaUhgH_Tvt2LZygwVRQa", "1CAPaUhgH_Tvt2LZygwVRTb", "1EEPaUhgH_Tvt2LZygwVRLm"]
    }]
  }' \
  https://your-company.your-region-code.qasphere.com/api/public/v0/project/BD/run

Response

Status: 201 Created

{
  "id": 2
}

Best Practices

  • Use live runs for ongoing test suites that should automatically update
  • Use static runs for fixed test sets like release certifications
  • Always provide descriptive titles and link runs to milestones when applicable
  • Assign runs to specific users for better accountability

Clone Existing Run

POST/api/public/v0/project/{project_id}/run/clone

Creates a new run by cloning an existing one. For live runs, the new run will reflect current test case states. The support for cloning runs with test plans via this endpoint is planned for a future release.

Authentication

Requires an API key with at least Test Runner role permissions. See Authentication for more details.

Request Body

{
  runId: number                // Required: Source run ID to clone
  title: string                // Required: New run title
  description?: html           // Optional: New description
  milestoneId?: number         // Optional: New milestone
  assignmentId?: number        // Optional: New assignee
}

Field Constraints

  • title: Must be 1-255 characters long and unique within the project
  • description: Maximum 512 characters
  • runId: Must be a valid run ID in the project
  • milestoneId: The milestone must belong to the project and must not be archived
  • assignmentId: Must be an active user with permissions above Viewer role

Example Request

curl \
  -H "Authorization: ApiKey your.api.key.here" \
  -H "Content-Type: application/json" \
  -d '{
    "runId": 1,
    "title": "Sprint 24 Regression - Clone",
    "description": "<p>Cloned regression suite for Sprint 24</p>",
    "milestoneId": 5,
    "assignmentId": 1
  }' \
  https://your-company.your-region-code.qasphere.com/api/public/v0/project/BD/run/clone

Example Response

{
  "id": 2
}

When cloning a live run, the new run will:

  • Maintain the same query plans as the original run
  • Reflect the current state of test cases (may differ from the original run)
  • Start with all test cases in 'open' status regardless of the original run's results

Close Run

POST/api/public/v0/project/{project_id}/run/{run_id}/close

Close an open test run.

Authentication

Requires an API key with at least Test Runner role permissions. See Authentication for more details.

Example Request

curl \
  -H "Authorization: ApiKey your.api.key.here" \
  -H "Content-Type: application/json" \
  https://your-company.your-region-code.qasphere.com/api/public/v0/project/BD/run/1/close

List Run Test Cases

GET/api/public/v0/project/{project_id}/run/{run_id}/tcase

Returns all test cases in a run with their current status.

Query Parameters

All query parameters are optional and some can be specified multiple times using the format param=value1&param=value2&param=value3.

ParameterTypeMultipleDescriptionAllowed ValuesExample
searchstringnoFilter test cases by title (case insensitive, partial matches)search=ui
tagsnumberyesFilter test cases by tag IDtags=12
prioritiesstringyesFilter test cases by priorityhigh, medium, lowpriorities=low
includestringyesInclude additional fields in the response which are omitted by defaultfolderinclude=folder
cf_${custom field system name}stringyesFilter test cases by custom field valueCustom field defined valuescf_automation=Automated
  • Different filters are combined with AND logic
  • Multiple values for the same filter are combined with OR logic
  • Only folder is supported for the include parameter

Example Request

Fetch all run test cases with additional folder information

curl \
  -H "Authorization: ApiKey your.api.key.here" \
  https://your-company.your-region-code.qasphere.com/api/public/v0/project/BD/run/1/tcase?include=folder

Fetch all test cases from a run with "Automation" custom field to be "Automated"

curl \
  -H "Authorization: ApiKey your.api.key.here" \
  https://your-company.your-region-code.qasphere.com/api/public/v0/project/BD/run/1/tcase?cf_automation=Automated

Fetch 20 test cases from a run sorted by title in ascending order

curl \
  -H "Authorization: ApiKey your.api.key.here" \
  https://your-company.your-region-code.qasphere.com/api/public/v0/project/BD/run/1/tcase?limit=20&sortField=title&sortOrder=asc

Fetch 10 most recent added test cases from a run

curl \
  -H "Authorization: ApiKey your.api.key.here" \
  https://your-company.your-region-code.qasphere.com/api/public/v0/project/BD/run/1/tcase?limit=10&sortField=created_at&sortOrder=desc

Fetch test cases with "backend" in their title from a run

curl \
  -H "Authorization: ApiKey your.api.key.here" \
  https://your-company.your-region-code.qasphere.com/api/public/v0/project/BD/run/1/tcase?search=backend

Fetch test cases with tag "cart" from a run

curl \
  -H "Authorization: ApiKey your.api.key.here" \
  https://your-company.your-region-code.qasphere.com/api/public/v0/project/BD/run/1/tcase?tag=cart

Fetch test cases with priority "high" from a run

curl \
  -H "Authorization: ApiKey your.api.key.here" \
  https://your-company.your-region-code.qasphere.com/api/public/v0/project/BD/run/1/tcase?priority=high

Response Fields

{
  tcases: Array<{
    id: string                // Unique identifier of the test case
    version: number           // Version number of the test case
    legacyId: string          // Legacy identifier (if any)
    type: string              // Type of the test case (`standalone` | `filled`)
    folderId: number          // ID of the folder containing the test case
    pos: number               // Position within the folder
    seq: number               // Sequence number
    title: string             // Title/description of the test case
    priority: string          // Priority level (high, medium, etc.)
    status: string            // Status of the latest result added for the run test case (open if no results are added)
    isAutomated: boolean      // Whether latest result was added using public APIs
    isEmpty: boolean          // Whether the test case is empty (has no comment and steps)
    templateTCaseId?: string  // Corresponding template test case ID, if it is a filled test case
    folder?: {                // Folder information if include=folder query parameter is passed
      id: number              //   Unique identifier for the folder
      parentId: number        //   Unique identifier of the parent of the folder (0 if it is the root folder)
      title: string           //   Title of the folder
      comment: html           //   Added comment for the folder
      pos: number             //   Position of the folder with respect to its sibling (starts with 0)
    }
  }>
}

Sample Response

{
  "tcases": [
    {
      "id": "1CGeNaNVt_Axa7TcMjUm6Zh",
      "version": 1,
      "legacyId": "",
      "type": "standalone",
      "folderId": 11848,
      "pos": 3,
      "seq": 8,
      "title": "The \"Checkout\" page with products from the cart should be shown after clicking the \"Checkout\" button",
      "priority": "high",
      "status": "open",
      "isAutomated": false,
      "isEmpty": true
    },
    {
      "id": "1CGeNaNWP_Eiq5mjzPsKSX9",
      "version": 1,
      "legacyId": "",
      "type": "filled",
      "folderId": 11848,
      "pos": 4,
      "seq": 9,
      "title": "The cart is still filled after going back from the \"Checkout\" page without submitting it",
      "priority": "medium",
      "status": "open",
      "isAutomated": false,
      "isEmpty": false
    }
  ]
}

Get Run Test Case

GET/api/public/v0/project/{project_id}/run/{run_id}/tcase/{tcase_or_legacy_id}

Get details of a single run test case using its ID, sequence or legacy ID.

Example Request

curl \
  -H "Authorization: ApiKey your.api.key.here" \
  https://your-company.your-region-code.qasphere.com/api/public/v0/project/BD/run/1/tcase/1

Response Fields

{
  id: string                     // Unique identifier of the test case
  version: number                // Version number of the test case
  legacyId: string               // Legacy identifier (if any)
  type: string                   // Test case type (`standalone` | `filled`)
  title: string                  // Title of the test case
  seq: number                    // Sequence number of the test case
  folderId: number               // Identifier of the folder where the test case is placed
  pos: number                    // Ordered position (0 based) of the test case in its folder
  priority: string               // Priority of the test case (`high` | `medium` | `low`)
  templateTCaseId: string | null // Identifier of the parent template test case (in case of `filled` test case type)
  comment: html                  // Test case precondition
  steps: Array<{                 // List of test case steps
    id: number                   //   Unique identifier of the step
    type: string                 //   Type of the step (standalone | shared)
    version: number              //   Version of the step (always 1 for standalone steps)
    isLatest: boolean            //   Whether this is the latest version of the step (always true for standalone steps)
    title?: string               //   Title of the step (only for shared steps)
    subSteps?: Array<{           //   List of sub steps (only for shared steps)
      id: number                 //     Unique identifier of the step
      type: string               //     Type of the step (shared_sub_step)
      version: number            //     Version of the step (same as parent step)
      isLatest: boolean          //     Whether this is the latest version (same as parent step)
      description: html          //     Details of the sub step
      expected: html             //     Expected result from the sub step
      deletedAt?: string         //     Date the sub step was deleted on
    }>
    description?: html           //   Details of step (only for standalone steps)
    expected?: html              //   Expected result from the step (only for standalone steps)
    deletedAt?: string           //   Date the step was deleted on
  }>
  tags: Array<{                  // List of test case tags
    id: number                   //   Unique identifier of the tag
    title: string                //   Title of the tag
  }>
  files: Array<{                 // List of files attached to the test case
    id: string                   //   Unique identifier of the file
    fileName: string             //   Name of the file
    mimeType: string             //   Mime type of the file
    size: number                 //   Size of the file
    url: string                  //   URL of the file
  }>
  requirements: Array<{          // Test case requirement (currently only single requirement is supported on UI)
    id: string                   //   Unique identifier of the requirement
    text: string                 //   Title of the requirement
    url: string                  //   URL of the requirement
  }>
  links: Array<{                 // Additional links relevant to the test case
    text: string                 //   Title of the link
    url: string                  //   URL of the link
  }>
  customFields: {                // Custom fields defined for the test case
    [key: string]: {             //   Key-value pairs of custom field system names and corresponding details for the test case
      value: string              //     Current value
      isDefault: boolean         //     Whether default value is set by the system or selected by the user
    }
  }
  authorId: number               // Unique identifier of the user who created the test case
  createdAt: string              // Test case creation timestamp (ISO 8601 format)
  status: string                 // Status of the latest result added for the run test case (open if no results are added)
  isAutomated: boolean           // Whether latest result was added using public APIs
  isLatestVersion: boolean       // Whether this is the latest version of the test case
  isEmpty: boolean               // Whether the test case is empty (has no comment and steps)
  templateTCaseId?: string       // Corresponding template test case ID, if it is a filled test case
  results: Array<{               // Results created for this test case in the run
    id: number                   //   Unique identifier of the test case result
    tcaseId: string              //   Unique identifier of the test case
    tcaseVersion: string         //   Version number of the test case
    authorId: number             //   Unique identifier of the user who added the result
    author: {                    //   Details of the user who added the result
      id: number                 //     Unique identifier of the user
      email: string              //     Email of the user
      name: string               //     Name of the user
      avatar: string | null      //     Avatar of the user
      role: string               // Role of the user (`owner` | `admin` | `user` | `test-runner` | `viewer`)
    }
    status: string               //   Result status (`passed` | `failed` | `blocked` | `skipped` | `open` | `custom1` | `custom2` | `custom3` | `custom4`)
    comment: html                //   Comments/observations while executing the test case
    links: Array<{               //   Details of issues created in external integrations
      id: number                 //     Unique identifier of the issue
      resultId: number           //     Unique identifier of the result for which the issue is created
      integrationId: string      //     Unique identifier of the external integration on which the issue is created
      integration: {             //     Details of the external integration
        id: string               //       Unique identifier of the integration
        name: string             //       Name of the integration
        type: string             // Integration type (`jira` | `github` | `custom`)
        config: object           //       Configuration for the integration (eg. url/email)
      }
      url: string                //     URL of the created issue
      text: string               //     Title of the created issue
      meta: object               //     Additional information related to the issue
    }>
    timeTaken: number | null     //  Time taken for executing the test case
    apiKeyId: string | null      //   Unique identifier of the API key, if this result was added via public APIs
    internal: boolean            //   Whether the result was added by system (eg. when test run is modified)
    createdAt: string            //   Result creation time (ISO 8601 format)
  }>
}

Sample Response

{
  "id": "1CEPaUhgH_Tvt2LZygwVRQa",
  "version": 1,
  "legacyId": "",
  "type": "standalone",
  "title": "Changing to corresponding cursor after hovering the element",
  "seq": 1,
  "folderId": 2,
  "pos": 0,
  "priority": "low",
  "templateTCaseId": null,
  "comment": "<p>The \"About Us\" page is opened</p>",
  "steps": [
    {
      "description": "<p>Test the display across various screen sizes (desktop, tablet, mobile) to ensure that blocks and buttons adjust appropriately to different viewport widths</p>",
      "expected": ""
    }
  ],
  "tags": [
    {
      "id": 1,
      "title": "About Us"
    },
    {
      "id": 2,
      "title": "Checklist"
    }
  ],
  "files": [],
  "requirements": [],
  "links": [],
  "customFields": {},
  "authorId": 1,
  "createdAt": "2024-01-01T00:00:00.000Z",
  "status": "open",
  "isAutomated": false,
  "isLatestVersion": true,
  "isEmpty": false,
  "results": [
    {
      "id": 20293,
      "tcaseId": "1CEPaUhgH_Tvt2LZygwVRQa",
      "tcaseVersion": 1,
      "authorId": 1,
      "author": {
        "id": 1,
        "email": "owner@example.com",
        "name": "System Owner",
        "avatar": null,
        "role": "owner"
      },
      "status": "blocked",
      "comment": "",
      "links": null,
      "timeTaken": null,
      "apiKeyId": null,
      "internal": false,
      "createdAt": "2024-01-01T00:00:00.000Z"
    }
  ]
}

Create Run Log

POST/api/public/v0/project/{project_id}/run/{run_id}/log

Create a log entry for a test run. Run logs can be used to record messages from CI/CD pipelines, automation frameworks, or any external system during test execution. Logs cannot be added to closed runs.

Path Parameters

  • project_id: The project identifier (can be either the project code or UUID)
  • run_id: The run identifier (numeric)

Authentication

Requires an API key with at least Test Runner role permissions. See Authentication for more details.

Request Body

{
  comment: string // Required: Log message content (HTML supported, minimum 1 character)
}

Field Constraints

  • comment: Must be at least 1 character long. HTML content is sanitized and leading/trailing whitespace is trimmed.

Example Request

curl \
  -H "Authorization: ApiKey your.api.key.here" \
  -H "Content-Type: application/json" \
  -d '{
    "comment": "<p>Build #1234 failed: 3 test cases did not pass</p>"
  }' \
  https://your-company.your-region-code.qasphere.com/api/public/v0/project/BD/run/1/log

Response Fields

FieldTypeDescription
idstringUnique identifier for the run log

Example Response

Status: 201 Created

{
  "id": "1CGeNaNVt_Axa7TcMjUm6Zh"
}

Error Responses

Status CodeDescription
400Invalid request body or empty comment
401Invalid or missing API key
403Insufficient permissions or suspended tenant or project is archived
404Project or test run not found
409Test run is closed
500Internal server error while creating log