{
  "openapi": "3.0.0",
  "info": {
    "title": "QA.tech API",
    "version": "1.0.0",
    "contact": {
      "name": "QA.tech",
      "url": "https://qa.tech",
      "email": "support@qa.tech"
    },
    "description": "API for triggering and managing AI-powered test runs"
  },
  "tags": [
    {
      "name": "Runs"
    },
    {
      "name": "Infrastructure"
    },
    {
      "name": "Test Cases"
    },
    {
      "name": "Application Builds"
    },
    {
      "name": "Status badge"
    },
    {
      "name": "Remote Tunnels"
    },
    {
      "name": "Chat"
    },
    {
      "name": "Applications"
    },
    {
      "name": "Features"
    },
    {
      "name": "Metrics"
    },
    {
      "name": "Release Checks"
    },
    {
      "name": "Projects"
    },
    {
      "name": "Knowledge"
    },
    {
      "name": "Rules"
    },
    {
      "name": "Issues"
    },
    {
      "name": "Automations"
    }
  ],
  "paths": {
    "/v1/applications": {
      "get": {
        "operationId": "ListApplications",
        "summary": "List applications",
        "description": "Lists the applications under test in the project the API key is bound to.",
        "parameters": [
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/ProjectScopedRequest"
            },
            "explode": false
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListApplicationsResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Applications"
        ]
      }
    },
    "/v1/applications/{applicationShortId}/builds": {
      "get": {
        "operationId": "ListApplicationBuilds",
        "summary": "List application builds",
        "description": "Lists mobile builds that can be used as primary or other apps in environment overrides.",
        "parameters": [
          {
            "name": "applicationShortId",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/ApplicationShortId"
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32"
            },
            "explode": false
          },
          {
            "name": "perPage",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32"
            },
            "explode": false
          },
          {
            "name": "projectShortId",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/ProjectShortId"
            },
            "explode": false
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListApplicationBuildsResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Application Builds"
        ]
      },
      "post": {
        "operationId": "ApplicationBuildCreate",
        "summary": "Create application build",
        "description": "Step 2 of 2 for attaching a mobile build: registers a file already uploaded via `application_build_upload_url`. Pass the `buildToken` returned by that tool (after you PUT the file to its `uploadUrl`). Returns `applicationBuildShortId` — use it as `environment.applicationBuildShortId` inside an `applications[]` override in `start_run_with_test_cases` / `start_run_with_test_plan`, or an `applicationOverrides[]` override in `create_chat`, to run/chat against this build.",
        "parameters": [
          {
            "name": "applicationShortId",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/ApplicationShortId"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApplicationBuildCreateResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Application Builds"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApplicationBuildCreateRequest"
              }
            }
          }
        }
      }
    },
    "/v1/applications/{applicationShortId}/builds/upload-url": {
      "post": {
        "operationId": "ApplicationBuildUploadUrl",
        "summary": "Get build upload URL",
        "description": "Step 1 of 2 for attaching a mobile build (.apk/.ipa) to a run. Returns a presigned `uploadUrl` and a `buildToken`. Next, upload the raw build file to `uploadUrl` with an HTTP PUT request (request body = the raw file bytes, `Content-Type` = the file's MIME type such as `application/octet-stream`; no auth header — the URL is presigned), then call `create_application_build` with the same `buildToken`.",
        "parameters": [
          {
            "name": "applicationShortId",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/ApplicationShortId"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApplicationBuildUploadUrlResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Application Builds"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApplicationBuildUploadUrlRequest"
              }
            }
          }
        }
      }
    },
    "/v1/applications/{applicationShortId}/environments": {
      "get": {
        "operationId": "ListApplicationEnvironments",
        "summary": "List application environments",
        "description": "List environments for a specific application",
        "parameters": [
          {
            "name": "applicationShortId",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/ApplicationShortId"
            }
          },
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/ProjectScopedRequest"
            },
            "explode": false
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListApplicationEnvironmentsResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Applications"
        ]
      }
    },
    "/v1/automations": {
      "get": {
        "operationId": "ListAutomations",
        "summary": "List automations",
        "description": "List the project's automations: \"when X, do Y\" rules that start a chat-assistant task or a test plan run on a schedule or from an API call. Includes each automation's trigger, action, enabled state, and last/next fire time.",
        "parameters": [
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/ProjectScopedRequest"
            },
            "explode": false
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListAutomationsResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Automations"
        ]
      },
      "post": {
        "operationId": "CreateAutomation",
        "summary": "Create automation",
        "description": "Create an automation. Triggers: `schedule` (5-field cron evaluated in an\nIANA timezone, optionally `once`) or `api_webhook` (fired only through the\ntrigger endpoint). Actions: `chat` starts an unattended QA.tech assistant\nconversation with the given prompt, `run_test_plan` runs a test plan (use\nlist_runs or the dashboard to find its `pln_` short id). Confirm the cron,\ntimezone and prompt with the user before creating.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateAutomationResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Automations"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateAutomationRequest"
              }
            }
          }
        }
      }
    },
    "/v1/automations/{automationId}": {
      "patch": {
        "operationId": "UpdateAutomation",
        "summary": "Update automation",
        "description": "Update an automation's name, description, enabled state, trigger or action. `trigger` and `action` replace the stored value as a whole. Set `isEnabled` to pause or resume it.",
        "parameters": [
          {
            "name": "automationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UpdateAutomationResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Automations"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateAutomationRequest"
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "DeleteAutomation",
        "summary": "Delete automation",
        "description": "Permanently delete an automation. Its past runs stay in the project's history. To pause instead, update it with `isEnabled: false`.",
        "parameters": [
          {
            "name": "automationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/ProjectScopedRequest"
            },
            "explode": false
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeleteAutomationResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Automations"
        ]
      }
    },
    "/v1/automations/{automationId}/trigger": {
      "post": {
        "operationId": "TriggerAutomation",
        "summary": "Trigger automation",
        "description": "Fire an automation on demand, regardless of its configured trigger. Use this\nfrom CI, deploy hooks, or monitoring to start the automation's chat-based\nworkflow with your own context. Returns 202 immediately.",
        "parameters": [
          {
            "name": "automationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "The request has been accepted for processing, but processing has not yet completed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TriggerAutomationResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Automations"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TriggerAutomationRequest"
              }
            }
          }
        }
      }
    },
    "/v1/badge-example.svg": {
      "get": {
        "operationId": "GetStatusBadgeExampleSvg",
        "summary": "Get example status badge",
        "description": "Get a sample status badge as SVG (no token). For live project badges use GET /v1/badge.svg.",
        "parameters": [
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/BadgeExampleSvgQuery"
            },
            "explode": false
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          }
        },
        "tags": [
          "Status badge"
        ],
        "security": [
          {}
        ]
      }
    },
    "/v1/badge.svg": {
      "get": {
        "operationId": "GetStatusBadgeSvg",
        "summary": "Get status badge",
        "description": "Get status badge as SVG. Authenticate with the token query parameter (not the API Bearer key). Project is resolved from the token.",
        "parameters": [
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/BadgeSvgQuery"
            },
            "explode": false
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          }
        },
        "tags": [
          "Status badge"
        ],
        "security": [
          {}
        ]
      }
    },
    "/v1/chat": {
      "post": {
        "operationId": "Chat",
        "summary": "Start chat conversation",
        "description": "Create a new chat conversation and send its first message.\n\nThis is the recommended way to author tests. The QA.tech agent explores the site, grounds tests in what actually exists, and sets up login and config dependencies, so the tests are reliable rather than flaky. Prefer it over `create_test_case` unless you have already verified the flow exists and gathered the details that tool requires.\n\nReturns 202 immediately with the created conversation. Processing is asynchronous: poll\n`get_chat_conversation` until conversation `status` is `completed`, `failed`, or\n`cancelled`. Assistant message `COMPLETED` is not enough — starting a test run ends\nthe current turn while the run continues. Wait at least 1s between polls. When a run\nexists, `runs[].shortId` is the handle for `get_run` / `get_run_test_case`.",
        "parameters": [],
        "responses": {
          "202": {
            "description": "The request has been accepted for processing, but processing has not yet completed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChatConversationResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Chat"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChatRequest"
              }
            }
          }
        }
      }
    },
    "/v1/chat/change-review": {
      "post": {
        "operationId": "StartChangeReviewChat",
        "summary": "Start change review chat",
        "description": "Create a new chat conversation and start an autonomous change review from either a PR URL or raw change input.",
        "parameters": [],
        "responses": {
          "202": {
            "description": "The request has been accepted for processing, but processing has not yet completed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChatConversationResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Chat"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StartChangeReviewRequest"
              }
            }
          }
        }
      }
    },
    "/v1/chat/{chatConversationShortId}": {
      "post": {
        "operationId": "AppendChatMessage",
        "summary": "Send chat message",
        "description": "Send a chat message to an existing conversation.\n\nReturns 202 immediately. Poll `get_chat_conversation` until conversation `status`\nis `completed`, `failed`, or `cancelled`. Assistant message `COMPLETED` is not\nenough while a test run is still in progress. Wait at least 1s between polls.",
        "parameters": [
          {
            "name": "chatConversationShortId",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/ChatConversationShortId"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "The request has been accepted for processing, but processing has not yet completed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChatConversationResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Chat"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChatRequest"
              }
            }
          }
        }
      },
      "get": {
        "operationId": "GetChatConversation",
        "summary": "Get chat conversation",
        "description": "Get conversation metadata, associated test runs, and recent messages (newest first).\n\nUse `limit` to control how many messages are returned (default 20). Poll until\nconversation `status` is `completed`, `failed`, or `cancelled` — not merely until the\nlatest assistant message is `COMPLETED`, because starting a test run ends that turn\nwhile the run continues in the background. `runs` lists any test runs started from\nthis chat; pass `shortId` to `get_run` (with `testCases: \"all\"`) for browser results.",
        "parameters": [
          {
            "name": "chatConversationShortId",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/ChatConversationShortId"
            }
          },
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/GetChatConversationQuery"
            },
            "explode": false
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChatConversationResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Chat"
        ]
      }
    },
    "/v1/features": {
      "get": {
        "operationId": "ListFeatures",
        "summary": "List features",
        "description": "List features in the project's feature graph. Features are LLM-clustered groupings of related UI actions discovered during crawling, and describe what the product can do.",
        "parameters": [
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/ListFeaturesQuery"
            },
            "explode": false
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListFeaturesResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Features"
        ]
      }
    },
    "/v1/features/{featureId}": {
      "get": {
        "operationId": "GetFeature",
        "summary": "Get feature",
        "description": "Fetch detail for a single feature, including pages it spans and actions that belong to it",
        "parameters": [
          {
            "name": "featureId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/ProjectScopedRequest"
            },
            "explode": false
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetFeatureResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Features"
        ]
      }
    },
    "/v1/issues": {
      "get": {
        "operationId": "ListIssues",
        "summary": "List issues",
        "description": "Lists issues QA.tech has found in the project, deduplicated across the runs where they recur and sorted by most recent occurrence (newest first). Defaults to `ACTIVE` issues; filter by `severity`, `status`, or a `since`/`until` window. Each issue includes its severity, status, type, a help URL, timestamps, and a deep link. Pass a returned `shortId` to `get_issue` for the run test cases that triggered it.",
        "parameters": [
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/ListIssuesQuery"
            },
            "explode": false
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListIssuesResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Issues"
        ]
      }
    },
    "/v1/issues/{shortId}": {
      "get": {
        "operationId": "GetIssue",
        "summary": "Get issue",
        "description": "Fetches a single issue by its short ID, including its tags and the recent run test cases where it was detected (newest first). Use the occurrences' `runTestCaseShortId` with `get_run_test_case` to inspect what the agent saw.",
        "parameters": [
          {
            "name": "shortId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/GetIssueQuery"
            },
            "explode": false
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetIssueResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Issues"
        ]
      }
    },
    "/v1/knowledge": {
      "get": {
        "operationId": "ListKnowledgeItems",
        "summary": "List knowledge items",
        "description": "List the project's knowledge base items: text notes, crawled links, uploaded PDFs, agent memories and UI icons. Returns summaries without content; fetch a single item for its full content.",
        "parameters": [
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/ListKnowledgeItemsQuery"
            },
            "explode": false
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListKnowledgeItemsResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Knowledge"
        ]
      },
      "post": {
        "operationId": "CreateKnowledgeItem",
        "summary": "Create knowledge item",
        "description": "Add an item to the project's knowledge base and index it for the QA.tech agents. Use `text` for documentation notes, `link` to crawl and index a URL, or `memory` for agent-maintained observations. PDF and icon items are managed in the dashboard.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateKnowledgeItemResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Knowledge"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateKnowledgeItemRequest"
              }
            }
          }
        }
      }
    },
    "/v1/knowledge/{knowledgeItemId}": {
      "get": {
        "operationId": "GetKnowledgeItem",
        "summary": "Get knowledge item",
        "description": "Fetch a single knowledge item including its full text content",
        "parameters": [
          {
            "name": "knowledgeItemId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/ProjectScopedRequest"
            },
            "explode": false
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetKnowledgeItemResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Knowledge"
        ]
      },
      "patch": {
        "operationId": "UpdateKnowledgeItem",
        "summary": "Update knowledge item",
        "description": "Update a text, link or memory knowledge item. Changing content or url re-indexes the item; pdf and icon items are managed in the dashboard.",
        "parameters": [
          {
            "name": "knowledgeItemId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UpdateKnowledgeItemResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Knowledge"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateKnowledgeItemRequest"
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "DeleteKnowledgeItem",
        "summary": "Delete knowledge item",
        "description": "Delete a knowledge item and remove it from the agents' knowledge index",
        "parameters": [
          {
            "name": "knowledgeItemId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/ProjectScopedRequest"
            },
            "explode": false
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeleteKnowledgeItemResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Knowledge"
        ]
      }
    },
    "/v1/metrics": {
      "get": {
        "operationId": "GetProjectMetrics",
        "summary": "Get project metrics",
        "description": "Prometheus text exposition format for the project bound to the API key.",
        "parameters": [
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/ProjectScopedRequest"
            },
            "explode": false
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          }
        },
        "tags": [
          "Metrics"
        ]
      }
    },
    "/v1/outbound-ips": {
      "get": {
        "operationId": "GetOutboundIps",
        "summary": "Get outbound IPs",
        "description": "Get the current outbound IP addresses QA.tech test runners use, for firewall rules and allowlists. No authentication required.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OutboundIpsResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Infrastructure"
        ],
        "security": [
          {}
        ]
      }
    },
    "/v1/projects": {
      "post": {
        "operationId": "CreateProject",
        "summary": "Create project",
        "description": "Create a new project in the organization the API key belongs to. Requires an organization-scoped API key with write scope.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateProjectResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Projects"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateProjectRequest"
              }
            }
          }
        }
      },
      "get": {
        "operationId": "ListProjects",
        "summary": "List projects",
        "description": "Lists the projects in the organization the API key belongs to. Organization-scoped keys see every project; project-scoped keys see only their own. Returned `shortId`s can be passed as `projectShortId` to any project-scoped tool to target that project.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListProjectsResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Projects"
        ]
      }
    },
    "/v1/release-checks": {
      "post": {
        "operationId": "StartReleaseCheck",
        "summary": "Start release check",
        "description": "Start a release check: an orchestrated pre-release report that runs your\nregression suite and/or an autonomous exploratory change review, then\ncompiles the results into a single report.\n\nRequest at least one of a regression suite (`regression`) or an exploratory\nchange review (`prUrl` or `changes`). All testing and analysis runs on\nQA.tech — it does not consume the caller's tokens or credits.\n\nReturns 202 immediately. Poll `get_release_check` until `status` is\n`completed` (or `failed`) to read the compiled report.",
        "parameters": [],
        "responses": {
          "202": {
            "description": "The request has been accepted for processing, but processing has not yet completed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReleaseCheckResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Release Checks"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReleaseCheckRequest"
              }
            }
          }
        }
      }
    },
    "/v1/release-checks/{shortId}": {
      "get": {
        "operationId": "GetReleaseCheck",
        "summary": "Get release check",
        "description": "Fetch the compiled release check report by its short ID. Poll until `status` is `completed`.",
        "parameters": [
          {
            "name": "shortId",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/ReleaseCheckShortId"
            }
          },
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/ProjectScopedRequest"
            },
            "explode": false
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReleaseCheckReport"
                }
              }
            }
          }
        },
        "tags": [
          "Release Checks"
        ]
      }
    },
    "/v1/remote-tunnels": {
      "post": {
        "operationId": "CreateRemoteTunnel",
        "summary": "Create remote tunnel",
        "description": "Create a new remote tunnel that exposes local ports via Cloudflare.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateRemoteTunnelResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Remote Tunnels"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateRemoteTunnelRequest"
              }
            }
          }
        }
      },
      "get": {
        "operationId": "ListRemoteTunnels",
        "summary": "List remote tunnels",
        "description": "List remote tunnels for the authenticated project",
        "parameters": [
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/ProjectScopedRequest"
            },
            "explode": false
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListRemoteTunnelsResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Remote Tunnels"
        ]
      }
    },
    "/v1/remote-tunnels/{runnerId}": {
      "get": {
        "operationId": "GetRemoteTunnel",
        "summary": "Get remote tunnel",
        "description": "Get a remote tunnel by runner ID",
        "parameters": [
          {
            "name": "runnerId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/ProjectScopedRequest"
            },
            "explode": false
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RemoteTunnelSummary"
                }
              }
            }
          }
        },
        "tags": [
          "Remote Tunnels"
        ]
      },
      "delete": {
        "operationId": "DeleteRemoteTunnel",
        "summary": "Delete remote tunnel",
        "description": "Tear down a remote tunnel and its DNS records",
        "parameters": [
          {
            "name": "runnerId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/ProjectScopedRequest"
            },
            "explode": false
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeleteRemoteTunnelResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Remote Tunnels"
        ]
      }
    },
    "/v1/remote-tunnels/{runnerId}/status": {
      "get": {
        "operationId": "GetRemoteTunnelStatus",
        "summary": "Get remote tunnel status",
        "description": "Get the live Cloudflare health status of a remote tunnel",
        "parameters": [
          {
            "name": "runnerId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/ProjectScopedRequest"
            },
            "explode": false
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RemoteTunnelStatusResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Remote Tunnels"
        ]
      }
    },
    "/v1/rules": {
      "get": {
        "operationId": "ListRules",
        "summary": "List rules",
        "description": "List the project's rules: standing instructions injected into the QA.tech agents. Filter by consumer to see rules for the chat assistant, the test agent, or PR review.",
        "parameters": [
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/ListRulesQuery"
            },
            "explode": false
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListRulesResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Rules"
        ]
      },
      "post": {
        "operationId": "CreateRule",
        "summary": "Create rule",
        "description": "Create a rule: a standing instruction injected into a QA.tech agent's context. Agent rules support filters to target specific applications, labels, scenarios or URL paths.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateRuleResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Rules"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateRuleRequest"
              }
            }
          }
        }
      }
    },
    "/v1/rules/{ruleId}": {
      "patch": {
        "operationId": "UpdateRule",
        "summary": "Update rule",
        "description": "Update a rule's title, content, filters or sort order. Pass null on a filter field to clear it.",
        "parameters": [
          {
            "name": "ruleId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UpdateRuleResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Rules"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateRuleRequest"
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "DeleteRule",
        "summary": "Delete rule",
        "description": "Delete a rule so it is no longer injected into the agent's context",
        "parameters": [
          {
            "name": "ruleId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/ProjectScopedRequest"
            },
            "explode": false
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeleteRuleResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Rules"
        ]
      }
    },
    "/v1/run": {
      "post": {
        "operationId": "RunProject",
        "summary": "Start test run",
        "description": "Execute a run for a given project. Supports API, GITHUB, or GITLAB trigger. For version-control triggers, provide actor, branch, commitHash, commitMessage, and repository. For GITLAB, also provide repositoryUrl so links work with GitLab.com and self-hosted instances. Use applications to override environment or device preset per run. On applications[].environment, optional customHeaders and basicAuth persist auth or protection-bypass rules on the environment; omit a field to leave stored rules unchanged, or pass an empty list to clear them.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RunResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Runs"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RunRequest"
              }
            }
          }
        }
      },
      "get": {
        "operationId": "ListRuns",
        "summary": "List runs",
        "description": "Lists runs for the project, newest first. With no filters it returns the 20 most recent runs across all time; pass `since`/`until` (ISO 8601) to scope to a window such as the last 24 hours. Returned `shortId`s work directly with `get_run` and `rerun_run`.",
        "parameters": [
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/ListRunsQuery"
            },
            "explode": false
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListRunsResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Runs"
        ]
      }
    },
    "/v1/run-test-case/{shortId}": {
      "get": {
        "operationId": "GetRunTestCase",
        "summary": "Get run test case",
        "description": "Fetches a single run test case (one test's execution within a run) by its short ID — the `<shortId>` in a `/results/test/<shortId>` URL. Returns the goal and success criteria, the result and error classification, the evaluator's full assessment (verdict summary, expected vs actual behavior, root-cause hypotheses, step-anchored key observations and raised issues), durations, and a deep link plus best-effort media URLs. Use `get_run_test_case_screenshots` to see the steps the assessment cites, `get_run_test_case_logs` for network/console evidence, `get_run_test_case_trace` for the step-by-step action trace, and `get_test_case_history` for the pass/fail trend.",
        "parameters": [
          {
            "name": "shortId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/GetRunTestCaseQuery"
            },
            "explode": false
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetRunTestCaseResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Runs"
        ]
      }
    },
    "/v1/run-test-case/{shortId}/history": {
      "get": {
        "operationId": "GetTestCaseHistory",
        "summary": "Get test case history",
        "description": "Returns the recent pass/fail history and durations for the test case behind a run test case short ID, across its most recent runs — for flaky-vs-consistent analysis.",
        "parameters": [
          {
            "name": "shortId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/GetTestCaseHistoryQuery"
            },
            "explode": false
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetTestCaseHistoryResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Runs"
        ]
      }
    },
    "/v1/run-test-case/{shortId}/logs": {
      "get": {
        "operationId": "GetRunTestCaseLogs",
        "summary": "Get run test case logs",
        "description": "Returns the telemetry captured while a run test case executed: browser network requests (`network`), browser console output (`console`), or server-side API calls made by API tests (`apiCalls`, with truncated request/response bodies). Filter by URL regex and status to find the failing request behind an error. Capped per call; narrow the filters when `hasMore` is true.",
        "parameters": [
          {
            "name": "shortId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/GetRunTestCaseLogsQuery"
            },
            "explode": false
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetRunTestCaseLogsResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Runs"
        ]
      }
    },
    "/v1/run-test-case/{shortId}/screenshots": {
      "get": {
        "operationId": "GetRunTestCaseScreenshots",
        "summary": "Get run test case screenshots",
        "description": "Returns screenshots of selected execution steps of a run test case, so the visible state can be checked directly. Step indices are the 0-based `[step:N]` references and `keyObservations[].stepIndex` from `get_run_test_case`'s assessment. Omit `steps` for the final screenshot. MCP clients receive each screenshot as an image.",
        "parameters": [
          {
            "name": "shortId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/GetRunTestCaseScreenshotsQuery"
            },
            "explode": false
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetRunTestCaseScreenshotsResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Runs"
        ]
      }
    },
    "/v1/run-test-case/{shortId}/trace": {
      "get": {
        "operationId": "GetRunTestCaseTrace",
        "summary": "Get run test case trace",
        "description": "Returns the agent's step-by-step action trace for a run test case: per step the reasoning, the tools it called with their arguments, the observed result, and a screenshot. Paginated via `limit`/`offset` so large traces don't overflow token limits.",
        "parameters": [
          {
            "name": "shortId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/GetRunTestCaseTraceQuery"
            },
            "explode": false
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetRunTestCaseTraceResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Runs"
        ]
      }
    },
    "/v1/run/{shortId}": {
      "get": {
        "operationId": "GetRun",
        "summary": "Get run",
        "description": "Fetches a run by its short ID. Pass `testCases: \"all\"` or `\"failed\"` to include nested test-case results, and `issues` to include detected issues (`all` or a category such as `accessibility`; omitted by default). Use `get_run_issues` to fetch only the issues.",
        "parameters": [
          {
            "name": "shortId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/GetRunQuery"
            },
            "explode": false
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetRunResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Runs"
        ]
      },
      "post": {
        "operationId": "RerunRunOp",
        "summary": "Rerun run",
        "description": "Reruns a previous run. Pass `failedOnly: true` to rerun only failed/skipped/errored cases, or `projectTestCaseIds` to rerun a specific subset.",
        "parameters": [
          {
            "name": "shortId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RerunResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Runs"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RerunRequest"
              }
            }
          }
        }
      }
    },
    "/v1/run/{shortId}/issues": {
      "get": {
        "operationId": "GetRunIssues",
        "summary": "Get run issues",
        "description": "Lists issues detected during a run, deduplicated and aggregated across its test cases. Returns every issue type by default; pass `issueType` to filter to one category (e.g. `accessibility`). Each issue includes its type, severity, tags, a help URL, and the test cases where it was found.",
        "parameters": [
          {
            "name": "shortId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/RunIssuesQuery"
            },
            "explode": false
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RunIssuesResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Runs"
        ]
      }
    },
    "/v1/test-cases": {
      "post": {
        "operationId": "CreateTestCase",
        "summary": "Create test case",
        "description": "Create a test case in the project. It is created in draft and a burn-in run starts automatically against the application's default environment, or against `environment` when given (e.g. a preview deployment or remote tunnel URL).\n\nIMPORTANT: gather context first, or the test will be flaky. This tool records the test exactly as you describe it. It does NOT explore the site to confirm the flow exists, so a vague or unverified goal produces low-value, flaky tests. Before calling, make sure you have:\n- Verified the functionality, pages, and UI labels actually exist in the target environment. Do not guess or assume.\n- A `goal` describing a single concrete user flow in plain UI terms, using generic data rather than specific entity names. Specific entities change over time and cause flakiness.\n- An `expectedResult` stating a UI-observable outcome a user can see on screen.\n- Prerequisites in place: a login/auth dependency via `resumeFromDependencyProjectTestCaseId` when the flow needs authentication, plus the right `configShortIds`.\n- Checked existing tests with `list_test_cases` to avoid duplicates.\n\nIf you have not gathered this context, prefer `create_chat` instead. The QA.tech chat agent crawls the site, grounds the test in what actually exists, sets up login and config dependencies, and verifies the test runs. That is how reliable tests get created. Use this tool directly only when you already know the flow exists and have the details above.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateTestCaseResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Test Cases"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTestCaseRequest"
              }
            }
          }
        }
      },
      "get": {
        "operationId": "ListTestCases",
        "summary": "List test cases",
        "description": "Lists test cases for the project, optionally filtered by application, labels, enabled state, or scenario.\n\nTo find tests by their wording, pass `query` instead of listing everything and filtering client-side. It is database websearch across name, goal, expected result, steps, and scenario name — unquoted terms are ANDed, quoted phrases match as a phrase, `OR` is alternation, and `-term` excludes.",
        "parameters": [
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/ListTestCasesQuery"
            },
            "explode": false
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListTestCasesResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Test Cases"
        ]
      }
    },
    "/v1/test-cases/{id}": {
      "get": {
        "operationId": "GetTestCase",
        "summary": "Get test case",
        "description": "Fetches a test case's authored configuration by its ID (UUID, as returned by `list_test_cases`): goal, expected result, steps, start URL path, dependencies, labels, enabled state, and scenario. This is the authored config the agent executes — for a specific run's outcome use `get_run_test_case` instead.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/GetTestCaseQuery"
            },
            "explode": false
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TestCaseDetail"
                }
              }
            }
          }
        },
        "tags": [
          "Test Cases"
        ]
      },
      "patch": {
        "operationId": "UpdateTestCase",
        "summary": "Update test case",
        "description": "Updates a test case's authored configuration. Patch semantics: only the fields you provide change; pass `null` on nullable fields (`startUrlPath`, `scenarioShortId`, `resumeFromDependencyProjectTestCaseId`) to clear them.\n\nThe edit takes effect immediately as a new published revision. To de-hardcode a test that 404s on a stale deep link, clear `startUrlPath` and set `resumeFromDependencyProjectTestCaseId` to a test that creates the entity it needs — it then starts from that test's end state with fresh data.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TestCaseDetail"
                }
              }
            }
          }
        },
        "tags": [
          "Test Cases"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateTestCaseRequest"
              }
            }
          }
        }
      }
    }
  },
  "security": [
    {
      "BearerAuth": []
    }
  ],
  "components": {
    "schemas": {
      "ApplicationBuildCreateRequest": {
        "type": "object",
        "required": [
          "platform",
          "buildToken"
        ],
        "properties": {
          "platform": {
            "$ref": "#/components/schemas/MobilePlatform"
          },
          "buildToken": {
            "type": "string",
            "description": "The `buildToken` returned by `application_build_upload_url`, after the build file was uploaded (HTTP PUT) to its `uploadUrl`."
          },
          "version": {
            "type": "string",
            "description": "Optional version label for the build (e.g. '1.2.3', 'v2.0.0-beta'). If omitted, QA.tech attempts to extract the version from the APK/IPA metadata."
          },
          "buildNumber": {
            "type": "string",
            "description": "Optional build number (e.g. '42', '1234'). This is the CFBundleVersion for iOS or versionCode for Android. If omitted, QA.tech attempts to extract it from the APK/IPA metadata."
          },
          "projectShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProjectShortId"
              }
            ],
            "description": "Target a specific project by its prefixed short ID (proj-slug_shortId or proj_shortId), as returned by the projects API. Required for organization-scoped API keys; project-scoped keys may only pass their own project's short ID."
          }
        },
        "description": "Request body for creating an application build after uploading via presigned URL"
      },
      "ApplicationBuildCreateResponse": {
        "type": "object",
        "required": [
          "applicationBuildShortId",
          "platform",
          "fileName",
          "fileSizeBytes"
        ],
        "properties": {
          "applicationBuildShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ApplicationBuildShortId"
              }
            ],
            "description": "Short ID of the created build. Use as `environment.applicationBuildShortId` in a `start_run_with_test_cases` / `start_run_with_test_plan` `applications[]` override or a `create_chat` `applicationOverrides[]` override."
          },
          "platform": {
            "$ref": "#/components/schemas/MobilePlatform"
          },
          "fileName": {
            "type": "string"
          },
          "fileSizeBytes": {
            "type": "integer",
            "format": "int64"
          },
          "version": {
            "type": "string",
            "description": "Build version string (e.g. '1.2.3'), extracted from app metadata or provided during upload."
          },
          "buildNumber": {
            "type": "string",
            "description": "Build number (e.g. '42'), extracted from app metadata or provided during upload. This is CFBundleVersion for iOS or versionCode for Android."
          }
        },
        "description": "Response with created application build metadata. Use `applicationBuildShortId` as `environment.applicationBuildShortId` in `start_run_with_test_cases` / `start_run_with_test_plan` / `create_chat` overrides."
      },
      "ApplicationBuildItem": {
        "type": "object",
        "required": [
          "applicationBuildShortId",
          "platform",
          "fileName",
          "fileSizeBytes",
          "version",
          "buildNumber",
          "appBundleId",
          "createdAt"
        ],
        "properties": {
          "applicationBuildShortId": {
            "$ref": "#/components/schemas/ApplicationBuildShortId"
          },
          "platform": {
            "$ref": "#/components/schemas/MobilePlatform"
          },
          "fileName": {
            "type": "string"
          },
          "fileSizeBytes": {
            "type": "integer",
            "format": "int64",
            "nullable": true
          },
          "version": {
            "type": "string",
            "nullable": true
          },
          "buildNumber": {
            "type": "string",
            "nullable": true
          },
          "appBundleId": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "allOf": [
              {
                "$ref": "#/components/schemas/Iso8601Timestamp"
              }
            ],
            "nullable": true
          }
        }
      },
      "ApplicationBuildShortId": {
        "type": "string",
        "pattern": "^build(-.+_.+|_.+)$"
      },
      "ApplicationBuildUploadUrlRequest": {
        "type": "object",
        "required": [
          "fileName"
        ],
        "properties": {
          "fileName": {
            "type": "string",
            "description": "Original file name (e.g. 'my-app.apk'). Preserved in storage for display and file type detection."
          },
          "projectShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProjectShortId"
              }
            ],
            "description": "Target a specific project by its prefixed short ID (proj-slug_shortId or proj_shortId), as returned by the projects API. Required for organization-scoped API keys; project-scoped keys may only pass their own project's short ID."
          }
        },
        "description": "Request body for getting a presigned upload URL"
      },
      "ApplicationBuildUploadUrlResponse": {
        "type": "object",
        "required": [
          "uploadUrl",
          "buildToken",
          "nextStep"
        ],
        "properties": {
          "uploadUrl": {
            "type": "string",
            "description": "Presigned URL to upload the raw build file to via HTTP PUT (request body = raw file bytes, `Content-Type` = the file's MIME type such as `application/octet-stream`). No auth header is required."
          },
          "buildToken": {
            "type": "string",
            "description": "Opaque token identifying this upload. Pass it unchanged to `create_application_build` once the PUT upload succeeds."
          },
          "nextStep": {
            "type": "string",
            "description": "Human-readable hint describing the next step in the upload chain."
          }
        },
        "description": "Presigned upload URL response. Upload the file to `uploadUrl`, then call `create_application_build` with `buildToken`."
      },
      "ApplicationEnvironmentOverride": {
        "anyOf": [
          {
            "$ref": "#/components/schemas/ApplicationEnvironmentOverrideByUrl"
          },
          {
            "$ref": "#/components/schemas/ApplicationEnvironmentOverrideByShortId"
          },
          {
            "$ref": "#/components/schemas/ApplicationEnvironmentOverrideByApplicationBuildShortId"
          }
        ]
      },
      "ApplicationEnvironmentOverrideByApplicationBuildShortId": {
        "type": "object",
        "required": [
          "applicationBuildShortId"
        ],
        "properties": {
          "applicationBuildShortId": {
            "$ref": "#/components/schemas/ApplicationBuildShortId"
          },
          "otherApplicationBuildShortIds": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApplicationBuildShortId"
            }
          },
          "customHeaders": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EnvironmentCustomHeaderRule"
            },
            "description": "Custom headers for the preview environment created or reused for this build. Omit to leave stored headers unchanged; pass an empty list to clear them."
          },
          "basicAuth": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EnvironmentBasicAuthRule"
            },
            "description": "Basic auth rules for the preview environment created or reused for this build. Omit to leave stored rules unchanged; pass an empty list to clear them."
          }
        },
        "description": "Use a specific application build (created via `create_application_build`). Creates or reuses an environment with this build."
      },
      "ApplicationEnvironmentOverrideByShortId": {
        "type": "object",
        "required": [
          "shortId"
        ],
        "properties": {
          "shortId": {
            "$ref": "#/components/schemas/EnvironmentShortId"
          },
          "customHeaders": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EnvironmentCustomHeaderRule"
            },
            "description": "Replace custom headers on the existing environment. Omit to leave stored headers unchanged; pass an empty list to clear them."
          },
          "basicAuth": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EnvironmentBasicAuthRule"
            },
            "description": "Replace basic auth rules on the existing environment. Omit to leave stored rules unchanged; pass an empty list to clear them."
          }
        }
      },
      "ApplicationEnvironmentOverrideByUrl": {
        "type": "object",
        "required": [
          "url"
        ],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "pattern": "^https?:\\x2f\\x2f",
            "description": "Base URL of the environment. Must use http or https."
          },
          "name": {
            "type": "string"
          },
          "customHeaders": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EnvironmentCustomHeaderRule"
            },
            "description": "Custom headers for this environment. Persisted on create and on reuse. Omit to leave stored headers unchanged; pass an empty list to clear them."
          },
          "basicAuth": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EnvironmentBasicAuthRule"
            },
            "description": "Basic auth rules for this environment. Persisted on create and on reuse. Omit to leave stored rules unchanged; pass an empty list to clear them."
          }
        }
      },
      "ApplicationItem": {
        "type": "object",
        "required": [
          "shortId",
          "name",
          "kind"
        ],
        "properties": {
          "shortId": {
            "$ref": "#/components/schemas/ApplicationShortId"
          },
          "name": {
            "type": "string"
          },
          "kind": {
            "type": "string"
          }
        }
      },
      "ApplicationOverride": {
        "type": "object",
        "required": [
          "applicationShortId"
        ],
        "properties": {
          "applicationShortId": {
            "$ref": "#/components/schemas/ApplicationShortId"
          },
          "devicePresetShortId": {
            "$ref": "#/components/schemas/DevicePresetShortId"
          },
          "environment": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ApplicationEnvironmentOverride"
              }
            ],
            "description": "Environment to use for this application. Optional customHeaders and basicAuth persist auth or protection-bypass rules on the environment."
          }
        },
        "description": "Override application, environment, or device preset for a specific run"
      },
      "ApplicationOverrideBase": {
        "type": "object",
        "required": [
          "applicationShortId"
        ],
        "properties": {
          "applicationShortId": {
            "$ref": "#/components/schemas/ApplicationShortId"
          },
          "devicePresetShortId": {
            "$ref": "#/components/schemas/DevicePresetShortId"
          }
        }
      },
      "ApplicationOverrideWithRequiredEnvironment": {
        "type": "object",
        "required": [
          "applicationShortId",
          "environment"
        ],
        "properties": {
          "applicationShortId": {
            "$ref": "#/components/schemas/ApplicationShortId"
          },
          "devicePresetShortId": {
            "$ref": "#/components/schemas/DevicePresetShortId"
          },
          "environment": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ApplicationEnvironmentOverride"
              }
            ],
            "description": "Environment to use for this application. Optional customHeaders and basicAuth persist auth or protection-bypass rules on the environment."
          }
        },
        "description": "Application override with a required environment"
      },
      "ApplicationShortId": {
        "type": "string",
        "pattern": "^app(-.+_.+|_.+)$"
      },
      "Automation": {
        "type": "object",
        "required": [
          "id",
          "name",
          "description",
          "isEnabled",
          "trigger",
          "action",
          "lastTriggeredAt",
          "nextRunAt",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "isEnabled": {
            "type": "boolean",
            "description": "Disabled automations never fire on their schedule and reject API triggers."
          },
          "trigger": {
            "$ref": "#/components/schemas/AutomationTrigger"
          },
          "action": {
            "$ref": "#/components/schemas/AutomationAction"
          },
          "lastTriggeredAt": {
            "type": "string",
            "nullable": true
          },
          "nextRunAt": {
            "type": "string",
            "nullable": true,
            "description": "Next scheduled fire time for enabled schedule automations; null otherwise."
          },
          "createdAt": {
            "type": "string"
          },
          "updatedAt": {
            "type": "string"
          }
        }
      },
      "AutomationAction": {
        "anyOf": [
          {
            "$ref": "#/components/schemas/AutomationChatAction"
          },
          {
            "$ref": "#/components/schemas/AutomationRunTestPlanAction"
          }
        ],
        "description": "What the automation does when it fires."
      },
      "AutomationApiWebhookTrigger": {
        "type": "object",
        "required": [
          "type"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "api_webhook"
            ]
          }
        },
        "description": "Only fire when called through `POST /automations/{automationId}/trigger` (CI, deploy hooks, monitoring)."
      },
      "AutomationChatAction": {
        "type": "object",
        "required": [
          "type",
          "prompt"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "chat"
            ]
          },
          "prompt": {
            "type": "string",
            "minLength": 1,
            "description": "Instructions for the assistant. It runs without a user present, so describe the full task and the expected outcome."
          }
        },
        "description": "Start a chat conversation with the QA.tech assistant that works through `prompt` autonomously."
      },
      "AutomationReservedTrigger": {
        "type": "object",
        "required": [
          "type"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "graph_change",
              "github_event"
            ]
          }
        },
        "description": "Reserved trigger types that are stored but not yet emitted."
      },
      "AutomationRunTestPlanAction": {
        "type": "object",
        "required": [
          "type",
          "testPlanShortId"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "run_test_plan"
            ]
          },
          "testPlanShortId": {
            "$ref": "#/components/schemas/TestPlanShortId"
          }
        },
        "description": "Run every test case in a test plan."
      },
      "AutomationScheduleTrigger": {
        "type": "object",
        "required": [
          "type",
          "cron"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "schedule"
            ]
          },
          "cron": {
            "type": "string",
            "minLength": 1,
            "description": "Standard 5-field cron expression (minute hour day-of-month month day-of-week), evaluated in `timezone`. Example: `0 9 * * 1` for Mondays at 09:00."
          },
          "timezone": {
            "type": "string",
            "description": "IANA timezone the cron is evaluated in, such as `Europe/Stockholm`. Defaults to `UTC`."
          },
          "once": {
            "type": "boolean",
            "description": "Fire once and then disable the automation. Pin minute, hour, day and month in `cron` when set. Defaults to `false`."
          }
        },
        "description": "Fire on a cron schedule."
      },
      "AutomationTrigger": {
        "anyOf": [
          {
            "$ref": "#/components/schemas/AutomationScheduleTrigger"
          },
          {
            "$ref": "#/components/schemas/AutomationApiWebhookTrigger"
          },
          {
            "$ref": "#/components/schemas/AutomationReservedTrigger"
          }
        ]
      },
      "AutomationTriggerInput": {
        "anyOf": [
          {
            "$ref": "#/components/schemas/AutomationScheduleTrigger"
          },
          {
            "$ref": "#/components/schemas/AutomationApiWebhookTrigger"
          }
        ],
        "description": "When the automation fires. Every automation can also be fired on demand through the trigger endpoint."
      },
      "BadgeExampleSvgQuery": {
        "type": "object",
        "required": [
          "example"
        ],
        "properties": {
          "example": {
            "allOf": [
              {
                "$ref": "#/components/schemas/StatusBadgeExampleName"
              }
            ],
            "description": "Example preset name. Required."
          },
          "label": {
            "type": "string"
          },
          "style": {
            "$ref": "#/components/schemas/StatusBadgeStyle"
          },
          "showDate": {
            "type": "boolean",
            "description": "When true, show relative time since last run."
          },
          "historyCount": {
            "type": "integer",
            "format": "int32"
          }
        },
        "description": "Query parameters for GET /v1/badge-example.svg (deterministic sample badges for docs and demos; no project token)."
      },
      "BadgeSvgQuery": {
        "type": "object",
        "required": [
          "token",
          "testPlanShortId"
        ],
        "properties": {
          "token": {
            "type": "string",
            "description": "Status badge secret (project status_badge_token). Required."
          },
          "label": {
            "type": "string"
          },
          "style": {
            "$ref": "#/components/schemas/StatusBadgeStyle"
          },
          "showDate": {
            "type": "boolean",
            "description": "When true, show relative time since last run."
          },
          "historyCount": {
            "type": "integer",
            "format": "int32"
          },
          "testPlanShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/TestPlanShortId"
              }
            ],
            "description": "Filter runs to this test plan (short id, e.g. pln_my-plan_shortid). Required with `token`."
          },
          "createdBy": {
            "type": "string",
            "description": "Filter by user id who created the run."
          },
          "trigger": {
            "allOf": [
              {
                "$ref": "#/components/schemas/StatusBadgeTriggerFilter"
              }
            ],
            "description": "Filter runs by how they were triggered."
          }
        },
        "description": "Query parameters for GET /v1/badge.svg (live status badge). Token identifies the project; do not use Bearer auth for this operation."
      },
      "ChangeReviewPostMergeOptions": {
        "type": "object",
        "required": [
          "enabled"
        ],
        "properties": {
          "enabled": {
            "type": "boolean",
            "description": "When true, run the post-merge agent after this PR merges. When false, skip it even if the GitHub App integration has it enabled."
          },
          "prompt": {
            "type": "string",
            "maxLength": 4000,
            "description": "Goal for the post-merge agent. This prompt is the entire task — the agent only changes tests when the prompt asks it to. Omit or leave empty to use the default maintenance prompt."
          }
        },
        "description": "Optional post-merge agent options for this pull request. When set, overrides the GitHub App integration post-merge settings for the agent that runs after this PR merges. Omit to use the integration settings."
      },
      "ChangeReviewRawChanges": {
        "type": "object",
        "required": [
          "changeDescription",
          "diff"
        ],
        "properties": {
          "changeDescription": {
            "type": "string",
            "minLength": 1,
            "description": "Description of the changes"
          },
          "diff": {
            "type": "string",
            "minLength": 1,
            "description": "Git diff content."
          }
        },
        "description": "Structured raw change data for change review mode"
      },
      "ChangeReviewTriageOptions": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean",
            "description": "When true, triage may skip this review even if the GitHub App integration has PR triage off. When false, never skip this review. Omit to follow the integration toggle."
          },
          "prompt": {
            "type": "string",
            "maxLength": 4000,
            "description": "PR triage prompt for this review, replacing the GitHub App integration prompt. Describes which changes to skip and which to review. Does not turn triage on by itself. Omit or leave empty to use the integration prompt."
          }
        },
        "description": "Optional triage options for this GitHub pull request review. Each field overrides the matching GitHub App integration PR triage setting for this review only. Omit a field to use the integration setting."
      },
      "ChatConversationResponse": {
        "type": "object",
        "required": [
          "shortId",
          "url",
          "createdAt",
          "updatedAt",
          "status",
          "runs"
        ],
        "properties": {
          "shortId": {
            "$ref": "#/components/schemas/ChatConversationShortId"
          },
          "url": {
            "type": "string",
            "description": "Dashboard URL for the conversation."
          },
          "title": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "source": {
            "type": "string",
            "enum": [
              "api",
              "ui",
              "github",
              "gitlab",
              "system"
            ],
            "description": "Where the conversation originated. `api` for conversations created via this API, `ui` for the dashboard, `github`/`gitlab` for VCS-triggered chats, and `system` for everything else."
          },
          "status": {
            "type": "string",
            "enum": [
              "in_progress",
              "completed",
              "failed",
              "cancelled"
            ],
            "description": "Overall conversation lifecycle. `in_progress` while the assistant is working or a background test run / research task is still going. Assistant message `COMPLETED` is not enough — starting a run ends the current turn. Poll until this is `completed`, `failed`, or `cancelled`."
          },
          "runs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChatConversationRun"
            },
            "description": "Test runs started from this conversation, newest first. Empty until a run is created. Use `shortId` with `get_run` (`testCases` = all) or nested test-case short IDs from that call with `get_run_test_case`."
          },
          "messages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChatMessageItem"
            },
            "description": "Recent messages, newest first. Empty on creation; poll `get_chat_conversation` to retrieve. Internal wake messages are omitted."
          }
        },
        "description": "Conversation data with recent messages (newest first)."
      },
      "ChatConversationRun": {
        "type": "object",
        "required": [
          "shortId",
          "status",
          "result",
          "url"
        ],
        "properties": {
          "shortId": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "description": "Run lifecycle status: `INITIATED`, `RUNNING`, `COMPLETED`, `ERROR`, or `CANCELLED`."
          },
          "result": {
            "type": "string",
            "nullable": true,
            "description": "Run outcome once complete: `PASSED`, `FAILED`, or `SKIPPED`. `null` while the run is still in progress."
          },
          "url": {
            "type": "string",
            "description": "Dashboard URL for the run."
          }
        },
        "description": "A test run started from this conversation. `shortId` works with `get_run` and `rerun_run`."
      },
      "ChatConversationShortId": {
        "type": "string",
        "pattern": "^chat(-.+_.+|_.+)$"
      },
      "ChatMessageItem": {
        "type": "object",
        "required": [
          "id",
          "role",
          "createdAt",
          "text"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "role": {
            "type": "string",
            "enum": [
              "user",
              "assistant"
            ]
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "text": {
            "type": "string",
            "description": "The plain-text body of the message."
          },
          "status": {
            "type": "string",
            "enum": [
              "INITIATED",
              "PARTIAL",
              "COMPLETED",
              "CANCELLED",
              "FAILED"
            ],
            "description": "Lifecycle status of this message. Do not treat assistant `COMPLETED` as the end of the conversation — starting a test run ends the current turn while the run continues in the background. Poll the conversation `status` instead."
          },
          "isStreaming": {
            "type": "boolean",
            "description": "True while the assistant is still streaming tokens for this message."
          }
        },
        "description": "A chat message. Tool calls and reasoning are not exposed in this version; only the text response is returned."
      },
      "ChatRequest": {
        "type": "object",
        "required": [
          "message"
        ],
        "properties": {
          "message": {
            "type": "string",
            "minLength": 1,
            "description": "The message text to send. Example: 'Generate a login flow test for staging'."
          },
          "applicationOverrides": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApplicationOverrideWithRequiredEnvironment"
            },
            "description": "Optional per-application environment overrides. Optional customHeaders and basicAuth on environment persist auth or protection-bypass rules."
          },
          "projectShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProjectShortId"
              }
            ],
            "description": "Target a specific project by its prefixed short ID (proj-slug_shortId or proj_shortId), as returned by the projects API. Required for organization-scoped API keys; project-scoped keys may only pass their own project's short ID."
          }
        },
        "description": "Request body for sending a chat message"
      },
      "ConfigShortId": {
        "type": "string",
        "pattern": "^cfg(-.+_.+|_.+)$"
      },
      "CreatableKnowledgeItemType": {
        "type": "string",
        "enum": [
          "text",
          "link",
          "memory"
        ],
        "description": "Knowledge item types that can be created through the API. `pdf` and `icon` items require file uploads and are managed in the dashboard."
      },
      "CreateAutomationRequest": {
        "type": "object",
        "required": [
          "name",
          "trigger",
          "action"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "description": {
            "type": "string",
            "maxLength": 500
          },
          "isEnabled": {
            "type": "boolean",
            "description": "Defaults to `true`."
          },
          "trigger": {
            "$ref": "#/components/schemas/AutomationTriggerInput"
          },
          "action": {
            "$ref": "#/components/schemas/AutomationAction"
          },
          "projectShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProjectShortId"
              }
            ],
            "description": "Target a specific project by its prefixed short ID (proj-slug_shortId or proj_shortId), as returned by the projects API. Required for organization-scoped API keys; project-scoped keys may only pass their own project's short ID."
          }
        }
      },
      "CreateAutomationResponse": {
        "type": "object",
        "required": [
          "success",
          "automation"
        ],
        "properties": {
          "success": {
            "type": "boolean"
          },
          "automation": {
            "$ref": "#/components/schemas/Automation"
          }
        }
      },
      "CreateKnowledgeItemRequest": {
        "type": "object",
        "required": [
          "type",
          "title"
        ],
        "properties": {
          "type": {
            "$ref": "#/components/schemas/CreatableKnowledgeItemType"
          },
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "content": {
            "type": "string",
            "minLength": 1,
            "maxLength": 50000,
            "description": "Text content. Required for text and memory items, not allowed for link items."
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "URL to crawl and index. Required for link items, not allowed for other types."
          },
          "excludePaths": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Path patterns to exclude while crawling a link item, e.g. /blog/*"
          },
          "projectShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProjectShortId"
              }
            ],
            "description": "Target a specific project by its prefixed short ID (proj-slug_shortId or proj_shortId), as returned by the projects API. Required for organization-scoped API keys; project-scoped keys may only pass their own project's short ID."
          }
        }
      },
      "CreateKnowledgeItemResponse": {
        "type": "object",
        "required": [
          "success",
          "item"
        ],
        "properties": {
          "success": {
            "type": "boolean"
          },
          "item": {
            "$ref": "#/components/schemas/KnowledgeItem"
          }
        }
      },
      "CreateProjectRequest": {
        "type": "object",
        "required": [
          "name",
          "url"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100,
            "description": "Display name for the new project"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "URL of the default environment for the project's web application"
          }
        },
        "description": "Request body for creating a new project in the organization the API key belongs to"
      },
      "CreateProjectResponse": {
        "type": "object",
        "required": [
          "project"
        ],
        "properties": {
          "project": {
            "$ref": "#/components/schemas/CreatedProject"
          }
        }
      },
      "CreateRemoteTunnelRequest": {
        "type": "object",
        "required": [
          "ports"
        ],
        "properties": {
          "ports": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PortMappingRequest"
            },
            "description": "One or more local ports to expose via the tunnel"
          },
          "public": {
            "type": "boolean",
            "description": "If true, the tunnel is publicly accessible without Cloudflare Access authentication"
          },
          "projectShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProjectShortId"
              }
            ],
            "description": "Target a specific project by its prefixed short ID (proj-slug_shortId or proj_shortId), as returned by the projects API. Required for organization-scoped API keys; project-scoped keys may only pass their own project's short ID."
          }
        },
        "description": "Request body to create a new remote tunnel"
      },
      "CreateRemoteTunnelResponse": {
        "type": "object",
        "required": [
          "runnerId",
          "hostnames",
          "tunnelToken",
          "expiresAt"
        ],
        "properties": {
          "runnerId": {
            "type": "string",
            "description": "Our identifier for this runner, used in subsequent API calls"
          },
          "hostnames": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HostnameInfo"
            },
            "description": "Public hostnames mapped to local ports"
          },
          "tunnelToken": {
            "type": "string",
            "description": "cloudflared token to start the tunnel daemon"
          },
          "expiresAt": {
            "type": "string",
            "description": "ISO timestamp when this tunnel will expire"
          }
        },
        "description": "Response after successfully creating a remote tunnel"
      },
      "CreateRuleRequest": {
        "type": "object",
        "required": [
          "consumer",
          "title",
          "content"
        ],
        "properties": {
          "consumer": {
            "$ref": "#/components/schemas/RuleConsumer"
          },
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "content": {
            "type": "string",
            "minLength": 1,
            "maxLength": 10000
          },
          "applicationShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ApplicationShortId"
              }
            ],
            "description": "Only apply the rule to tests running against this application (agent rules only)"
          },
          "labelFilter": {
            "type": "string",
            "description": "Only apply the rule to test cases carrying this label (agent rules only)"
          },
          "scenarioShortIds": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ScenarioShortId"
            },
            "description": "Only apply the rule to test cases in these scenarios (agent rules only)"
          },
          "urlPathFilter": {
            "type": "string",
            "description": "Only apply the rule to tests whose start URL path contains this substring (agent rules only)"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32",
            "description": "Rules are applied in ascending sort order"
          },
          "projectShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProjectShortId"
              }
            ],
            "description": "Target a specific project by its prefixed short ID (proj-slug_shortId or proj_shortId), as returned by the projects API. Required for organization-scoped API keys; project-scoped keys may only pass their own project's short ID."
          }
        }
      },
      "CreateRuleResponse": {
        "type": "object",
        "required": [
          "success",
          "rule"
        ],
        "properties": {
          "success": {
            "type": "boolean"
          },
          "rule": {
            "$ref": "#/components/schemas/ProjectRule"
          }
        }
      },
      "CreateTestCaseRequest": {
        "type": "object",
        "required": [
          "name",
          "goal",
          "applicationShortId"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "goal": {
            "type": "string",
            "minLength": 1
          },
          "expectedResult": {
            "type": "string"
          },
          "resumeFromDependencyProjectTestCaseId": {
            "type": "string"
          },
          "waitForDependenciesProjectTestCaseIds": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "configShortIds": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConfigShortId"
            }
          },
          "applicationShortId": {
            "$ref": "#/components/schemas/ApplicationShortId"
          },
          "scenarioShortId": {
            "$ref": "#/components/schemas/ScenarioShortId"
          },
          "environment": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ApplicationEnvironmentOverride"
              }
            ],
            "description": "Environment of `applicationShortId` to run the initial burn-in against (e.g. a preview URL or remote tunnel URL). Omit to use the application's default environment. Optional customHeaders and basicAuth persist auth or protection-bypass rules on the environment."
          },
          "projectShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProjectShortId"
              }
            ],
            "description": "Target a specific project by its prefixed short ID (proj-slug_shortId or proj_shortId), as returned by the projects API. Required for organization-scoped API keys; project-scoped keys may only pass their own project's short ID."
          }
        },
        "description": "Request body for creating a new test case linked to a project"
      },
      "CreateTestCaseResponse": {
        "type": "object",
        "required": [
          "success",
          "testCase"
        ],
        "properties": {
          "success": {
            "type": "boolean"
          },
          "testCase": {
            "$ref": "#/components/schemas/TestCase"
          }
        }
      },
      "CreatedProject": {
        "type": "object",
        "required": [
          "shortId",
          "name",
          "slug",
          "url",
          "defaultApplicationShortId",
          "organization"
        ],
        "properties": {
          "shortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProjectShortId"
              }
            ],
            "description": "Prefixed project short ID (proj-slug_shortId); pass this back as projectShortId on other endpoints."
          },
          "name": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "defaultApplicationShortId": {
            "type": "string",
            "allOf": [
              {
                "$ref": "#/components/schemas/ApplicationShortId"
              }
            ],
            "nullable": true
          },
          "organization": {
            "$ref": "#/components/schemas/CreatedProjectOrganization"
          }
        },
        "description": "The newly created project"
      },
      "CreatedProjectOrganization": {
        "type": "object",
        "required": [
          "uuid",
          "name"
        ],
        "properties": {
          "uuid": {
            "type": "string"
          },
          "name": {
            "type": "string"
          }
        },
        "description": "Organization the created project belongs to"
      },
      "DeleteAutomationResponse": {
        "type": "object",
        "required": [
          "success",
          "id"
        ],
        "properties": {
          "success": {
            "type": "boolean"
          },
          "id": {
            "type": "string",
            "description": "Id of the deleted automation"
          }
        }
      },
      "DeleteKnowledgeItemResponse": {
        "type": "object",
        "required": [
          "success",
          "id"
        ],
        "properties": {
          "success": {
            "type": "boolean"
          },
          "id": {
            "type": "string",
            "description": "Id of the deleted knowledge item"
          }
        }
      },
      "DeleteRemoteTunnelResponse": {
        "type": "object",
        "required": [
          "deleted"
        ],
        "properties": {
          "deleted": {
            "type": "boolean"
          }
        },
        "description": "Response after deleting a remote tunnel"
      },
      "DeleteRuleResponse": {
        "type": "object",
        "required": [
          "success",
          "id"
        ],
        "properties": {
          "success": {
            "type": "boolean"
          },
          "id": {
            "type": "string",
            "description": "Id of the deleted rule"
          }
        }
      },
      "DevicePresetShortId": {
        "type": "string",
        "pattern": "^preset(-.+_.+|_.+)$"
      },
      "EmailNotificationOverride": {
        "type": "object",
        "required": [
          "type",
          "recipients"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "email"
            ]
          },
          "recipients": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Email addresses to notify for this run. Replaces test-plan email recipients when provided."
          },
          "notifyOn": {
            "type": "string",
            "enum": [
              "failure",
              "always"
            ],
            "description": "`always` (default) sends on every completion; `failure` sends only when the result is not PASSED."
          },
          "enabled": {
            "type": "boolean",
            "description": "Set to `false` to suppress email for this run. Defaults to `true` when `recipients` is non-empty."
          }
        }
      },
      "EnvironmentBasicAuthRule": {
        "type": "object",
        "required": [
          "domains",
          "username",
          "password"
        ],
        "properties": {
          "domains": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Host patterns that receive these credentials. `*.preview.example.com` matches the apex and any subdomain."
          },
          "username": {
            "type": "string",
            "pattern": "^[^:]+$",
            "description": "Basic auth username. May not contain `:`."
          },
          "password": {
            "type": "string",
            "description": "Basic auth password. Applied by the platform on matching requests; generated test code cannot read it."
          }
        },
        "description": "Host patterns (`*.preview.example.com` or an exact host) and the HTTP Basic Auth credentials to send to matching hosts. Browser, crawler, and API tests send `Authorization: Basic` to matching hosts only. When provided on an environment override, the rules are persisted on the environment."
      },
      "EnvironmentBasicAuthRuleSummary": {
        "type": "object",
        "required": [
          "domains",
          "username"
        ],
        "properties": {
          "domains": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Host patterns that receive these credentials."
          },
          "username": {
            "type": "string",
            "description": "Basic auth username."
          }
        },
        "description": "Basic auth rule as returned on reads. The password is write-only and never returned."
      },
      "EnvironmentCustomHeaderRule": {
        "type": "object",
        "required": [
          "domains",
          "headers"
        ],
        "properties": {
          "domains": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Host patterns that receive these headers. `*.preview.example.com` matches the apex and any subdomain."
          },
          "headers": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Header name to value. Applied by the platform on matching requests; generated test code cannot read the values."
          }
        },
        "description": "Host patterns (`*.preview.example.com` or an exact host) and the headers to attach to matching requests. Used for auth, deployment-protection bypass, and similar platform access. When provided on an environment override, the rules are persisted on the environment."
      },
      "EnvironmentItem": {
        "type": "object",
        "required": [
          "shortId",
          "name",
          "url",
          "isProduction"
        ],
        "properties": {
          "shortId": {
            "$ref": "#/components/schemas/EnvironmentShortId"
          },
          "name": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "nullable": true
          },
          "isProduction": {
            "type": "boolean"
          },
          "otherApplicationBuildShortIds": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApplicationBuildShortId"
            }
          },
          "customHeaders": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EnvironmentCustomHeaderRule"
            },
            "description": "Custom headers applied to matching hosts when tests run against this environment."
          },
          "basicAuth": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EnvironmentBasicAuthRuleSummary"
            },
            "description": "Basic auth rules sent to matching hosts when tests run against this environment. Passwords are write-only and never returned."
          }
        }
      },
      "EnvironmentShortId": {
        "type": "string",
        "pattern": "^env(-.+_.+|_.+)$"
      },
      "FeatureActionItem": {
        "type": "object",
        "required": [
          "text",
          "type",
          "element",
          "page",
          "entityId",
          "entityName",
          "entityDescription",
          "similarActionCount"
        ],
        "properties": {
          "text": {
            "type": "string",
            "nullable": true,
            "description": "Visible label or closest text anchor for the action"
          },
          "type": {
            "type": "string",
            "description": "Action type (e.g. click, type, select)"
          },
          "element": {
            "type": "string",
            "description": "Element kind (e.g. button, input, link)"
          },
          "page": {
            "type": "string",
            "nullable": true,
            "description": "Page path where the action lives, or null for mobile contexts"
          },
          "entityId": {
            "type": "string",
            "nullable": true,
            "description": "Entity id if this action is an instance of a reusable entity"
          },
          "entityName": {
            "type": "string",
            "nullable": true,
            "description": "Entity name (e.g. PaymentButton)"
          },
          "entityDescription": {
            "type": "string",
            "nullable": true,
            "description": "Entity description"
          },
          "similarActionCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true,
            "description": "When actions were collapsed by entity, how many similar actions this sample represents"
          }
        },
        "description": "A UI action that belongs to a feature"
      },
      "FeatureDetail": {
        "type": "object",
        "required": [
          "id",
          "name",
          "description",
          "pages",
          "actions"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true,
            "description": "LLM-generated description, or null for undescribed features (matches the list view)"
          },
          "pages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FeaturePage"
            }
          },
          "actions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FeatureActionItem"
            }
          }
        },
        "description": "Detailed view of a single feature including pages and actions"
      },
      "FeatureItem": {
        "type": "object",
        "required": [
          "id",
          "name",
          "description",
          "actionCount"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Stable feature identifier from the graph"
          },
          "name": {
            "type": "string",
            "description": "Human-readable feature name"
          },
          "description": {
            "type": "string",
            "nullable": true,
            "description": "LLM-generated description of what the feature does"
          },
          "actionCount": {
            "type": "integer",
            "format": "int32",
            "description": "Number of distinct UI actions clustered under this feature"
          }
        },
        "description": "Summary of a feature in the project's feature graph"
      },
      "FeaturePage": {
        "type": "object",
        "required": [
          "path",
          "description"
        ],
        "properties": {
          "path": {
            "type": "string",
            "description": "Normalized URL path (e.g. /checkout)"
          },
          "description": {
            "type": "string",
            "nullable": true,
            "description": "Description of what the page does, derived during crawling"
          }
        },
        "description": "A page touched by a feature"
      },
      "GetChatConversationQuery": {
        "type": "object",
        "properties": {
          "limit": {
            "type": "integer",
            "format": "int32",
            "default": 20
          },
          "projectShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProjectShortId"
              }
            ],
            "description": "Target a specific project by its prefixed short ID (proj-slug_shortId or proj_shortId), as returned by the projects API. Required for organization-scoped API keys; project-scoped keys may only pass their own project's short ID."
          }
        }
      },
      "GetFeatureResponse": {
        "type": "object",
        "required": [
          "feature"
        ],
        "properties": {
          "feature": {
            "$ref": "#/components/schemas/FeatureDetail"
          }
        },
        "description": "Response for fetching a single feature detail"
      },
      "GetIssueQuery": {
        "type": "object",
        "properties": {
          "projectShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProjectShortId"
              }
            ],
            "description": "Target a specific project by its prefixed short ID (proj-slug_shortId or proj_shortId), as returned by the projects API. Required for organization-scoped API keys; project-scoped keys may only pass their own project's short ID."
          }
        }
      },
      "GetIssueResponse": {
        "type": "object",
        "required": [
          "issue"
        ],
        "properties": {
          "issue": {
            "$ref": "#/components/schemas/IssueDetail"
          }
        }
      },
      "GetKnowledgeItemResponse": {
        "type": "object",
        "required": [
          "item"
        ],
        "properties": {
          "item": {
            "$ref": "#/components/schemas/KnowledgeItem"
          }
        }
      },
      "GetRunQuery": {
        "type": "object",
        "properties": {
          "testCases": {
            "type": "string",
            "enum": [
              "failed",
              "all"
            ]
          },
          "issues": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "all"
                ]
              },
              {
                "$ref": "#/components/schemas/RunIssueCategory"
              }
            ],
            "description": "Include issues detected during the run. Omitted by default to keep responses small. Pass `all` for every issue, or a category (e.g. `accessibility`) to include only that type."
          },
          "projectShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProjectShortId"
              }
            ],
            "description": "Target a specific project by its prefixed short ID (proj-slug_shortId or proj_shortId), as returned by the projects API. Required for organization-scoped API keys; project-scoped keys may only pass their own project's short ID."
          }
        }
      },
      "GetRunResponse": {
        "type": "object",
        "required": [
          "shortId",
          "status",
          "result",
          "id",
          "runTestCases"
        ],
        "properties": {
          "shortId": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "description": "Run lifecycle status: `INITIATED`, `RUNNING`, `COMPLETED`, `ERROR`, or `CANCELLED`."
          },
          "result": {
            "type": "string",
            "nullable": true,
            "description": "Run outcome once status is `COMPLETED`: `PASSED`, `FAILED`, or `SKIPPED`. `null` while the run is still in progress."
          },
          "id": {
            "type": "string"
          },
          "runTestCases": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RunTestCase"
            }
          },
          "issues": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RunIssue"
            },
            "description": "Issues detected during the run, deduplicated across its test cases. Only present when requested via the `issues` query parameter."
          }
        }
      },
      "GetRunTestCaseLogsQuery": {
        "type": "object",
        "required": [
          "kind"
        ],
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "network",
              "console",
              "apiCalls"
            ],
            "description": "Which log to read: `network` (browser requests), `console` (browser console), or `apiCalls` (server-side API calls made by API tests)."
          },
          "urlPattern": {
            "type": "string",
            "description": "Case-insensitive regex matched against the URL (`network`, `apiCalls`)."
          },
          "statusFilter": {
            "type": "string",
            "enum": [
              "all",
              "errors",
              "success"
            ],
            "description": "`errors` (4xx/5xx/failed), `success` (2xx/3xx), or `all` (default). Applies to `network` and `apiCalls`.",
            "default": "all"
          },
          "includeWarnings": {
            "type": "boolean",
            "description": "Include console warnings (`console` only)."
          },
          "includeInfo": {
            "type": "boolean",
            "description": "Include info-level console logs (`console` only)."
          },
          "projectShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProjectShortId"
              }
            ],
            "description": "Target a specific project by its prefixed short ID (proj-slug_shortId or proj_shortId), as returned by the projects API. Required for organization-scoped API keys; project-scoped keys may only pass their own project's short ID."
          }
        }
      },
      "GetRunTestCaseLogsResponse": {
        "type": "object",
        "required": [
          "runTestCaseShortId",
          "kind",
          "totalMatched",
          "returned",
          "hasMore"
        ],
        "properties": {
          "runTestCaseShortId": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "network",
              "console",
              "apiCalls"
            ]
          },
          "totalMatched": {
            "type": "integer",
            "format": "int32",
            "description": "Entries matching the filters, before the per-call cap."
          },
          "returned": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          },
          "message": {
            "type": "string",
            "description": "Set when nothing was captured, or to hint at a broader filter."
          },
          "network": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RunTestCaseNetworkEntry"
            }
          },
          "console": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RunTestCaseConsoleEntry"
            }
          },
          "apiCalls": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RunTestCaseApiCallEntry"
            }
          }
        },
        "description": "Captured browser/API telemetry for a run test case. Capped per call; `hasMore` signals that narrower filters are needed."
      },
      "GetRunTestCaseQuery": {
        "type": "object",
        "properties": {
          "projectShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProjectShortId"
              }
            ],
            "description": "Target a specific project by its prefixed short ID (proj-slug_shortId or proj_shortId), as returned by the projects API. Required for organization-scoped API keys; project-scoped keys may only pass their own project's short ID."
          }
        }
      },
      "GetRunTestCaseResponse": {
        "type": "object",
        "required": [
          "id",
          "shortId",
          "name",
          "status",
          "result",
          "resultTitle",
          "evaluationThought",
          "errorCode",
          "classification",
          "promptGoal",
          "promptExamples",
          "runShortId",
          "projectTestCaseId",
          "startedAt",
          "completedAt",
          "durationMs",
          "url",
          "screenshotUrl",
          "recordingUrl",
          "outboundIpAddress",
          "assessment"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "shortId": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "description": "Run lifecycle status: `INITIATED`, `RUNNING`, `COMPLETED`, `ERROR`, or `CANCELLED`."
          },
          "result": {
            "type": "string",
            "nullable": true,
            "description": "Outcome once complete: `PASSED`, `FAILED`, or `SKIPPED`. `null` while still running."
          },
          "resultTitle": {
            "type": "string",
            "nullable": true,
            "description": "Short human-readable summary of the result."
          },
          "evaluationThought": {
            "type": "string",
            "nullable": true,
            "description": "The evaluator's reasoning for the pass/fail verdict."
          },
          "errorCode": {
            "type": "string",
            "nullable": true,
            "description": "Error classification when the test did not cleanly pass/fail, e.g. `TEST_FAILED` (real product failure) vs an `AGENT_`/`PLATFORM_` execution miss. `null` for a clean pass."
          },
          "classification": {
            "type": "string",
            "nullable": true,
            "description": "`POSITIVE` (expected to succeed) or `NEGATIVE` (expected to fail)."
          },
          "promptGoal": {
            "type": "string",
            "nullable": true,
            "description": "The test's goal / instructions."
          },
          "promptExamples": {
            "type": "string",
            "nullable": true,
            "description": "The success criteria / examples the evaluator checks against."
          },
          "runShortId": {
            "type": "string",
            "description": "Short ID of the run this test case belongs to. Use with `get_run`."
          },
          "projectTestCaseId": {
            "type": "string",
            "description": "Stable project test case ID. Use with `get_test_case_history` to see the pass/fail trend."
          },
          "startedAt": {
            "type": "string",
            "nullable": true
          },
          "completedAt": {
            "type": "string",
            "nullable": true
          },
          "durationMs": {
            "type": "integer",
            "format": "int32",
            "nullable": true,
            "description": "Wall-clock duration in milliseconds, when both timestamps are present."
          },
          "url": {
            "type": "string",
            "description": "Deep link to the recording and trace in the QA.tech UI. Always works; the media URLs below may be time-limited."
          },
          "screenshotUrl": {
            "type": "string",
            "nullable": true,
            "description": "Best-effort link to the final screenshot. May be a time-limited URL; use `url` for a durable view."
          },
          "recordingUrl": {
            "type": "string",
            "nullable": true,
            "description": "Best-effort link to the session video recording, if captured. May be a time-limited URL; use `url` for a durable view."
          },
          "outboundIpAddress": {
            "type": "string",
            "nullable": true,
            "description": "Public egress IP address seen by the application under test. null if not yet resolved or unavailable."
          },
          "assessment": {
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/RunTestCaseAssessment"
              }
            ],
            "nullable": true,
            "description": "The evaluator's full assessment report. `null` when the test has not been assessed yet."
          }
        },
        "description": "Detailed view of a single run test case (one test's execution within a run), for root-cause investigation. Resolve the `<shortId>` from a `/results/test/<shortId>` URL."
      },
      "GetRunTestCaseScreenshotsQuery": {
        "type": "object",
        "properties": {
          "steps": {
            "type": "array",
            "items": {
              "type": "integer",
              "format": "int32"
            },
            "maxItems": 6,
            "description": "0-based execution steps to fetch (the `stepIndex` of key observations and the `[step:N]` references in the assessment). Max 6. Omit for the final screenshot."
          },
          "projectShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProjectShortId"
              }
            ],
            "description": "Target a specific project by its prefixed short ID (proj-slug_shortId or proj_shortId), as returned by the projects API. Required for organization-scoped API keys; project-scoped keys may only pass their own project's short ID."
          }
        }
      },
      "GetRunTestCaseScreenshotsResponse": {
        "type": "object",
        "required": [
          "runTestCaseShortId",
          "stepCount",
          "screenshots"
        ],
        "properties": {
          "runTestCaseShortId": {
            "type": "string"
          },
          "stepCount": {
            "type": "integer",
            "format": "int32",
            "description": "Number of execution steps; valid `steps` are 0 to `stepCount - 1`."
          },
          "screenshots": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RunTestCaseScreenshot"
            }
          }
        },
        "description": "Screenshots for selected execution steps of a run test case."
      },
      "GetRunTestCaseTraceQuery": {
        "type": "object",
        "properties": {
          "limit": {
            "type": "integer",
            "format": "int32",
            "minimum": 1,
            "maximum": 200,
            "description": "Maximum number of steps to return (1-200). Defaults to 50.",
            "default": 50
          },
          "offset": {
            "type": "integer",
            "format": "int32",
            "minimum": 0,
            "description": "Number of steps to skip for pagination. Defaults to 0."
          },
          "projectShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProjectShortId"
              }
            ],
            "description": "Target a specific project by its prefixed short ID (proj-slug_shortId or proj_shortId), as returned by the projects API. Required for organization-scoped API keys; project-scoped keys may only pass their own project's short ID."
          }
        }
      },
      "GetRunTestCaseTraceResponse": {
        "type": "object",
        "required": [
          "runTestCaseShortId",
          "total",
          "limit",
          "offset",
          "steps"
        ],
        "properties": {
          "runTestCaseShortId": {
            "type": "string"
          },
          "total": {
            "type": "integer",
            "format": "int32",
            "description": "Total number of steps available across the whole trace."
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "steps": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RunTestCaseStep"
            }
          }
        },
        "description": "Agent step trace for a run test case, paginated so large traces don't overflow."
      },
      "GetTestCaseHistoryQuery": {
        "type": "object",
        "properties": {
          "limit": {
            "type": "integer",
            "format": "int32",
            "minimum": 1,
            "maximum": 50,
            "description": "Maximum number of past executions to return (1-50). Defaults to 20.",
            "default": 20
          },
          "projectShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProjectShortId"
              }
            ],
            "description": "Target a specific project by its prefixed short ID (proj-slug_shortId or proj_shortId), as returned by the projects API. Required for organization-scoped API keys; project-scoped keys may only pass their own project's short ID."
          }
        }
      },
      "GetTestCaseHistoryResponse": {
        "type": "object",
        "required": [
          "projectTestCaseId",
          "name",
          "total",
          "limit",
          "history"
        ],
        "properties": {
          "projectTestCaseId": {
            "type": "string",
            "description": "Stable project test case ID these executions belong to."
          },
          "name": {
            "type": "string"
          },
          "total": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "history": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TestCaseHistoryItem"
            }
          }
        },
        "description": "Recent pass/fail history for a single test case across its most recent runs."
      },
      "GetTestCaseQuery": {
        "type": "object",
        "properties": {
          "projectShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProjectShortId"
              }
            ],
            "description": "Target a specific project by its prefixed short ID (proj-slug_shortId or proj_shortId), as returned by the projects API. Required for organization-scoped API keys; project-scoped keys may only pass their own project's short ID."
          }
        }
      },
      "GitHubTriggerFields": {
        "type": "object",
        "properties": {
          "actor": {
            "type": "string",
            "description": "Username that triggered the CI job. Example: `octocat`."
          },
          "branch": {
            "type": "string",
            "description": "Branch the run was triggered from. Example: `main` or `refs/heads/main`."
          },
          "commitHash": {
            "type": "string",
            "description": "Full commit SHA the run was triggered for. Used to link the run back to the commit."
          },
          "commitMessage": {
            "type": "string",
            "description": "Commit message subject for the triggering commit."
          },
          "repository": {
            "type": "string",
            "description": "Repository the run was triggered from, as `owner/name`. Example: `QAdottech/qatech`."
          }
        },
        "description": "Git metadata used to attribute the run in the dashboard. Populate these from your CI context (e.g. the GitHub Actions `github.*` context)."
      },
      "HostnameInfo": {
        "type": "object",
        "required": [
          "localPort",
          "url"
        ],
        "properties": {
          "localPort": {
            "type": "integer",
            "format": "int32",
            "description": "The local port this hostname maps to"
          },
          "url": {
            "type": "string",
            "description": "The public HTTPS URL for this port"
          }
        },
        "description": "A single hostname mapping returned by the tunnel"
      },
      "Iso8601Timestamp": {
        "type": "string",
        "pattern": "^\\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])([Tt ]([01]\\d|2[0-3]):[0-5]\\d(:[0-5]\\d)?(\\.\\d+)?([Zz]|[+-]([01]\\d|2[0-3]):?[0-5]\\d)?)?$"
      },
      "IssueDetail": {
        "type": "object",
        "required": [
          "shortId",
          "title",
          "description",
          "severity",
          "status",
          "issueType",
          "helpUrl",
          "createdAt",
          "lastOccurredAt",
          "url",
          "tags",
          "occurrences"
        ],
        "properties": {
          "shortId": {
            "type": "string",
            "description": "Stable short ID. Pass to `get_issue` for full detail, or open `url` in the dashboard."
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "severity": {
            "type": "string",
            "description": "`MINOR`, `MAJOR`, or `CRITICAL`. Higher severity sorts first when occurrence times tie."
          },
          "status": {
            "type": "string",
            "description": "`ACTIVE` or `IGNORED`."
          },
          "issueType": {
            "type": "string",
            "description": "The category of the issue, e.g. `ACCESSIBILITY`, `CONSOLE`, `HOSTING`, or `FAILED_TEST`."
          },
          "helpUrl": {
            "type": "string",
            "nullable": true,
            "description": "Link to remediation guidance for the issue, when available."
          },
          "createdAt": {
            "type": "string",
            "description": "When the issue was first detected."
          },
          "lastOccurredAt": {
            "type": "string",
            "nullable": true,
            "description": "When the issue was most recently detected. `null` if it has not been recomputed since creation."
          },
          "url": {
            "type": "string",
            "description": "Deep link to the issue in the QA.tech dashboard."
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Freeform labels attached to the issue."
          },
          "occurrences": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/IssueOccurrence"
            },
            "description": "Recent run test cases where this issue was detected, newest first."
          }
        },
        "description": "Full detail for a single issue, including where it was detected."
      },
      "IssueListItem": {
        "type": "object",
        "required": [
          "shortId",
          "title",
          "description",
          "severity",
          "status",
          "issueType",
          "helpUrl",
          "createdAt",
          "lastOccurredAt",
          "url"
        ],
        "properties": {
          "shortId": {
            "type": "string",
            "description": "Stable short ID. Pass to `get_issue` for full detail, or open `url` in the dashboard."
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "severity": {
            "type": "string",
            "description": "`MINOR`, `MAJOR`, or `CRITICAL`. Higher severity sorts first when occurrence times tie."
          },
          "status": {
            "type": "string",
            "description": "`ACTIVE` or `IGNORED`."
          },
          "issueType": {
            "type": "string",
            "description": "The category of the issue, e.g. `ACCESSIBILITY`, `CONSOLE`, `HOSTING`, or `FAILED_TEST`."
          },
          "helpUrl": {
            "type": "string",
            "nullable": true,
            "description": "Link to remediation guidance for the issue, when available."
          },
          "createdAt": {
            "type": "string",
            "description": "When the issue was first detected."
          },
          "lastOccurredAt": {
            "type": "string",
            "nullable": true,
            "description": "When the issue was most recently detected. `null` if it has not been recomputed since creation."
          },
          "url": {
            "type": "string",
            "description": "Deep link to the issue in the QA.tech dashboard."
          }
        },
        "description": "An issue QA.tech has found in the project, deduplicated across the runs where it recurs."
      },
      "IssueOccurrence": {
        "type": "object",
        "required": [
          "runShortId",
          "runTestCaseShortId",
          "testCaseName",
          "detectedAt"
        ],
        "properties": {
          "runShortId": {
            "type": "string",
            "description": "Short ID of the run the issue was detected in."
          },
          "runTestCaseShortId": {
            "type": "string",
            "description": "Short ID of the run test case, usable with `get_run_test_case`."
          },
          "testCaseName": {
            "type": "string"
          },
          "detectedAt": {
            "type": "string",
            "nullable": true,
            "description": "When that test case started. `null` if it never started."
          }
        },
        "description": "A run test case where the issue was detected."
      },
      "KnowledgeItem": {
        "type": "object",
        "required": [
          "id",
          "type",
          "title",
          "url",
          "status",
          "createdAt",
          "updatedAt",
          "content"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "type": {
            "$ref": "#/components/schemas/KnowledgeItemType"
          },
          "title": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "nullable": true,
            "description": "Source URL for link items, null for other types"
          },
          "status": {
            "type": "string",
            "description": "Ingestion status, e.g. PENDING, PROCESSING, COMPLETED or FAILED"
          },
          "createdAt": {
            "type": "string"
          },
          "updatedAt": {
            "type": "string"
          },
          "content": {
            "type": "string",
            "nullable": true,
            "description": "Text content for text and memory items, null for other types"
          }
        }
      },
      "KnowledgeItemSummary": {
        "type": "object",
        "required": [
          "id",
          "type",
          "title",
          "url",
          "status",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "type": {
            "$ref": "#/components/schemas/KnowledgeItemType"
          },
          "title": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "nullable": true,
            "description": "Source URL for link items, null for other types"
          },
          "status": {
            "type": "string",
            "description": "Ingestion status, e.g. PENDING, PROCESSING, COMPLETED or FAILED"
          },
          "createdAt": {
            "type": "string"
          },
          "updatedAt": {
            "type": "string"
          }
        }
      },
      "KnowledgeItemType": {
        "type": "string",
        "enum": [
          "pdf",
          "link",
          "text",
          "icon",
          "memory"
        ],
        "description": "All knowledge item types. `pdf` and `icon` items are managed in the dashboard."
      },
      "ListApplicationBuildsResponse": {
        "type": "object",
        "required": [
          "builds",
          "page",
          "perPage",
          "total",
          "totalPages",
          "hasMore"
        ],
        "properties": {
          "builds": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApplicationBuildItem"
            }
          },
          "page": {
            "type": "integer",
            "format": "int32"
          },
          "perPage": {
            "type": "integer",
            "format": "int32"
          },
          "total": {
            "type": "integer",
            "format": "int64"
          },
          "totalPages": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        }
      },
      "ListApplicationEnvironmentsResponse": {
        "type": "object",
        "required": [
          "environments"
        ],
        "properties": {
          "environments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EnvironmentItem"
            }
          }
        }
      },
      "ListApplicationsResponse": {
        "type": "object",
        "required": [
          "applications"
        ],
        "properties": {
          "applications": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApplicationItem"
            }
          }
        }
      },
      "ListAutomationsResponse": {
        "type": "object",
        "required": [
          "automations"
        ],
        "properties": {
          "automations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Automation"
            }
          }
        }
      },
      "ListFeaturesQuery": {
        "type": "object",
        "properties": {
          "applicationShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ApplicationShortId"
              }
            ],
            "description": "Scope the list to one application; omit for all features in the project"
          },
          "projectShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProjectShortId"
              }
            ],
            "description": "Target a specific project by its prefixed short ID (proj-slug_shortId or proj_shortId), as returned by the projects API. Required for organization-scoped API keys; project-scoped keys may only pass their own project's short ID."
          }
        },
        "description": "Query parameters for listing features"
      },
      "ListFeaturesResponse": {
        "type": "object",
        "required": [
          "features"
        ],
        "properties": {
          "features": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FeatureItem"
            }
          }
        },
        "description": "Response for listing features in the project's feature graph"
      },
      "ListIssuesQuery": {
        "type": "object",
        "properties": {
          "severity": {
            "type": "string",
            "enum": [
              "MINOR",
              "MAJOR",
              "CRITICAL"
            ],
            "description": "Filter to issues of this severity. Omitted returns every severity."
          },
          "status": {
            "type": "string",
            "enum": [
              "ACTIVE",
              "IGNORED",
              "all"
            ],
            "description": "Filter by issue status. Defaults to `ACTIVE` (open issues that still need attention). Pass `IGNORED` for dismissed issues, or `all` to include both.",
            "default": "ACTIVE"
          },
          "since": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Iso8601Timestamp"
              }
            ],
            "description": "Only include issues last seen at or after this ISO 8601 timestamp."
          },
          "until": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Iso8601Timestamp"
              }
            ],
            "description": "Only include issues last seen at or before this ISO 8601 timestamp."
          },
          "orderDirection": {
            "type": "string",
            "enum": [
              "asc",
              "desc"
            ],
            "description": "Sort direction by most recent occurrence. Defaults to `desc` (newest first).",
            "default": "desc"
          },
          "limit": {
            "type": "integer",
            "format": "int32",
            "minimum": 1,
            "maximum": 100,
            "description": "Maximum number of issues to return (1-100). Defaults to 20.",
            "default": 20
          },
          "offset": {
            "type": "integer",
            "format": "int32",
            "minimum": 0,
            "description": "Number of issues to skip for pagination. Defaults to 0."
          },
          "projectShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProjectShortId"
              }
            ],
            "description": "Target a specific project by its prefixed short ID (proj-slug_shortId or proj_shortId), as returned by the projects API. Required for organization-scoped API keys; project-scoped keys may only pass their own project's short ID."
          }
        },
        "description": "Filters for listing issues QA.tech has found in a project. Every filter is optional; with no filters the most recently seen `ACTIVE` issues are returned, newest first."
      },
      "ListIssuesResponse": {
        "type": "object",
        "required": [
          "issues",
          "total",
          "limit",
          "offset"
        ],
        "properties": {
          "issues": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/IssueListItem"
            }
          },
          "total": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          }
        },
        "description": "Issues found in the project, newest first, with pagination."
      },
      "ListKnowledgeItemsQuery": {
        "type": "object",
        "properties": {
          "type": {
            "allOf": [
              {
                "$ref": "#/components/schemas/KnowledgeItemType"
              }
            ],
            "description": "Filter by knowledge item type"
          },
          "projectShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProjectShortId"
              }
            ],
            "description": "Target a specific project by its prefixed short ID (proj-slug_shortId or proj_shortId), as returned by the projects API. Required for organization-scoped API keys; project-scoped keys may only pass their own project's short ID."
          }
        }
      },
      "ListKnowledgeItemsResponse": {
        "type": "object",
        "required": [
          "items"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/KnowledgeItemSummary"
            }
          }
        }
      },
      "ListProjectsResponse": {
        "type": "object",
        "required": [
          "projects"
        ],
        "properties": {
          "projects": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ProjectListItem"
            }
          }
        }
      },
      "ListRemoteTunnelsResponse": {
        "type": "object",
        "required": [
          "tunnels"
        ],
        "properties": {
          "tunnels": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RemoteTunnelSummary"
            }
          }
        },
        "description": "Response for listing active remote tunnels"
      },
      "ListRulesQuery": {
        "type": "object",
        "properties": {
          "consumer": {
            "allOf": [
              {
                "$ref": "#/components/schemas/RuleConsumer"
              }
            ],
            "description": "Filter by the agent the rule applies to"
          },
          "projectShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProjectShortId"
              }
            ],
            "description": "Target a specific project by its prefixed short ID (proj-slug_shortId or proj_shortId), as returned by the projects API. Required for organization-scoped API keys; project-scoped keys may only pass their own project's short ID."
          }
        }
      },
      "ListRulesResponse": {
        "type": "object",
        "required": [
          "rules"
        ],
        "properties": {
          "rules": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ProjectRule"
            }
          }
        }
      },
      "ListRunItem": {
        "type": "object",
        "required": [
          "shortId",
          "status",
          "result",
          "trigger",
          "branch",
          "commitHash",
          "testPlanShortId",
          "applicationShortIds",
          "startedAt",
          "finishedAt",
          "createdAt",
          "passedCount",
          "failedCount",
          "erroredCount",
          "skippedCount",
          "cancelledCount",
          "totalCount",
          "url"
        ],
        "properties": {
          "shortId": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "result": {
            "type": "string",
            "nullable": true
          },
          "trigger": {
            "type": "string"
          },
          "branch": {
            "type": "string",
            "nullable": true
          },
          "commitHash": {
            "type": "string",
            "nullable": true
          },
          "testPlanShortId": {
            "type": "string",
            "nullable": true
          },
          "applicationShortIds": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Applications the run executed against. Empty when the run had no environment association."
          },
          "startedAt": {
            "type": "string",
            "nullable": true
          },
          "finishedAt": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string"
          },
          "passedCount": {
            "type": "integer",
            "format": "int32"
          },
          "failedCount": {
            "type": "integer",
            "format": "int32"
          },
          "erroredCount": {
            "type": "integer",
            "format": "int32"
          },
          "skippedCount": {
            "type": "integer",
            "format": "int32"
          },
          "cancelledCount": {
            "type": "integer",
            "format": "int32"
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "url": {
            "type": "string"
          }
        }
      },
      "ListRunsQuery": {
        "type": "object",
        "properties": {
          "applicationShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ApplicationShortId"
              }
            ],
            "description": "Scope to runs that executed against this application."
          },
          "testPlanShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/TestPlanShortId"
              }
            ],
            "description": "Scope to runs triggered for this test plan."
          },
          "status": {
            "type": "string",
            "enum": [
              "running",
              "passed",
              "failed",
              "errored",
              "cancelled"
            ],
            "description": "Filter by run outcome. `running` covers initiated/running runs; `passed`/`failed` match the run result; `errored`/`cancelled` match the run status."
          },
          "trigger": {
            "type": "string",
            "enum": [
              "API",
              "GITHUB",
              "GITLAB",
              "MANUAL",
              "SCHEDULE",
              "CHAT"
            ],
            "description": "Filter by how the run was triggered."
          },
          "branch": {
            "type": "string",
            "minLength": 1,
            "description": "Filter GitHub- or GitLab-triggered runs by branch name."
          },
          "commitHash": {
            "type": "string",
            "minLength": 1,
            "description": "Filter GitHub- or GitLab-triggered runs by commit hash."
          },
          "since": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Iso8601Timestamp"
              }
            ],
            "description": "Only include runs started at or after this ISO 8601 timestamp."
          },
          "until": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Iso8601Timestamp"
              }
            ],
            "description": "Only include runs started at or before this ISO 8601 timestamp."
          },
          "orderBy": {
            "type": "string",
            "enum": [
              "startedAt",
              "createdAt",
              "completedAt"
            ],
            "description": "Field to sort by. Defaults to `startedAt`.",
            "default": "startedAt"
          },
          "orderDirection": {
            "type": "string",
            "enum": [
              "asc",
              "desc"
            ],
            "description": "Sort direction. Defaults to `desc` (newest first).",
            "default": "desc"
          },
          "limit": {
            "type": "integer",
            "format": "int32",
            "minimum": 1,
            "maximum": 100,
            "description": "Maximum number of runs to return (1-100). Defaults to 20.",
            "default": 20
          },
          "offset": {
            "type": "integer",
            "format": "int32",
            "minimum": 0,
            "description": "Number of runs to skip for pagination. Defaults to 0."
          },
          "projectShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProjectShortId"
              }
            ],
            "description": "Target a specific project by its prefixed short ID (proj-slug_shortId or proj_shortId), as returned by the projects API. Required for organization-scoped API keys; project-scoped keys may only pass their own project's short ID."
          }
        },
        "description": "Filters for listing runs. Every filter is optional; with no filters the most recent runs across all time are returned, newest first."
      },
      "ListRunsResponse": {
        "type": "object",
        "required": [
          "runs",
          "total",
          "limit",
          "offset"
        ],
        "properties": {
          "runs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ListRunItem"
            }
          },
          "total": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          }
        }
      },
      "ListTestCaseItem": {
        "type": "object",
        "required": [
          "id",
          "name",
          "isEnabled",
          "labels",
          "references",
          "classification",
          "applicationShortId",
          "applicationName",
          "goal",
          "expectedResult",
          "createdAt",
          "lastRun"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "isEnabled": {
            "type": "boolean"
          },
          "labels": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "references": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TestCaseReference"
            }
          },
          "classification": {
            "type": "string"
          },
          "applicationShortId": {
            "$ref": "#/components/schemas/ApplicationShortId"
          },
          "applicationName": {
            "type": "string"
          },
          "goal": {
            "type": "string",
            "nullable": true
          },
          "expectedResult": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string"
          },
          "steps": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TestCaseStep"
            },
            "description": "Step-by-step definition, present when includeSteps is set"
          },
          "lastRun": {
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/TestCaseLastRun"
              }
            ],
            "nullable": true
          }
        }
      },
      "ListTestCasesQuery": {
        "type": "object",
        "properties": {
          "applicationShortId": {
            "$ref": "#/components/schemas/ApplicationShortId"
          },
          "labels": {
            "type": "string"
          },
          "isEnabled": {
            "type": "boolean"
          },
          "query": {
            "type": "string",
            "minLength": 1,
            "description": "Database websearch over each test's name, goal, expected result, steps, and scenario name. Same syntax as a web search: unquoted terms are ANDed (create canvas), quoted phrases match as a phrase, OR for alternatives (canvas OR login), and -term to exclude. Combine with scenarioShortId to search a scenario tree. total counts the matching tests."
          },
          "scenarioShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ScenarioShortId"
              }
            ],
            "description": "Only return tests filed in this scenario (folder). Includes nested sub-scenarios unless `includeDescendantScenarios` is false."
          },
          "includeDescendantScenarios": {
            "type": "boolean",
            "description": "Whether a `scenarioShortId` filter also covers tests in nested sub-scenarios.",
            "default": true
          },
          "includeSteps": {
            "type": "boolean",
            "description": "Include the step-by-step definition of each test case in the response",
            "default": false
          },
          "limit": {
            "type": "integer",
            "format": "int32",
            "minimum": 1,
            "maximum": 1000,
            "default": 100
          },
          "offset": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "projectShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProjectShortId"
              }
            ],
            "description": "Target a specific project by its prefixed short ID (proj-slug_shortId or proj_shortId), as returned by the projects API. Required for organization-scoped API keys; project-scoped keys may only pass their own project's short ID."
          }
        }
      },
      "ListTestCasesResponse": {
        "type": "object",
        "required": [
          "testCases",
          "total",
          "limit",
          "offset"
        ],
        "properties": {
          "testCases": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ListTestCaseItem"
            }
          },
          "total": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          }
        }
      },
      "MobilePlatform": {
        "type": "string",
        "enum": [
          "ios",
          "android"
        ],
        "description": "Mobile platform for application builds"
      },
      "NoneNotificationOverride": {
        "type": "object",
        "required": [
          "type"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "none"
            ]
          }
        }
      },
      "NotificationOverride": {
        "anyOf": [
          {
            "$ref": "#/components/schemas/SlackNotificationOverride"
          },
          {
            "$ref": "#/components/schemas/EmailNotificationOverride"
          },
          {
            "$ref": "#/components/schemas/TeamsNotificationOverride"
          },
          {
            "$ref": "#/components/schemas/NoneNotificationOverride"
          }
        ],
        "description": "Per-run notification override. Use type none to suppress all notifications for the run, including project defaults."
      },
      "OutboundIpsResponse": {
        "type": "object",
        "required": [
          "ipAddresses",
          "webIpAddresses",
          "mobileIpAddresses"
        ],
        "properties": {
          "ipAddresses": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Combined list of all QA.tech outbound IP addresses (web + mobile). Use this if you want a single allowlist."
          },
          "webIpAddresses": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Web testing outbound IP addresses only."
          },
          "mobileIpAddresses": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Mobile testing outbound IP addresses only (Appetize streaming servers)."
          }
        }
      },
      "PortMappingRequest": {
        "type": "object",
        "required": [
          "localPort"
        ],
        "properties": {
          "localPort": {
            "type": "integer",
            "format": "int32",
            "minimum": 1,
            "maximum": 65535,
            "description": "Local port to expose (1-65535)"
          },
          "protocol": {
            "type": "string",
            "enum": [
              "http",
              "https"
            ],
            "description": "Protocol for the local service (defaults to http)"
          },
          "subdomain": {
            "type": "string",
            "description": "Optional subdomain label for this port (e.g. 'api' -> r-{id}-api.quack.run)"
          }
        },
        "description": "A single port mapping to expose through the tunnel"
      },
      "ProjectListItem": {
        "type": "object",
        "required": [
          "shortId",
          "name",
          "slug",
          "url",
          "defaultApplicationShortId"
        ],
        "properties": {
          "shortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProjectShortId"
              }
            ],
            "description": "Prefixed project short ID (proj-slug_shortId); pass this back as projectShortId on other endpoints."
          },
          "name": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "defaultApplicationShortId": {
            "type": "string",
            "allOf": [
              {
                "$ref": "#/components/schemas/ApplicationShortId"
              }
            ],
            "nullable": true
          }
        },
        "description": "A project in the organization, usable as a `projectShortId` target."
      },
      "ProjectRule": {
        "type": "object",
        "required": [
          "id",
          "consumer",
          "title",
          "content",
          "applicationShortId",
          "labelFilter",
          "scenarioShortIds",
          "urlPathFilter",
          "sortOrder",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "consumer": {
            "$ref": "#/components/schemas/RuleConsumer"
          },
          "title": {
            "type": "string"
          },
          "content": {
            "type": "string"
          },
          "applicationShortId": {
            "type": "string",
            "allOf": [
              {
                "$ref": "#/components/schemas/ApplicationShortId"
              }
            ],
            "nullable": true,
            "description": "When set, the rule only applies to tests running against this application"
          },
          "labelFilter": {
            "type": "string",
            "nullable": true,
            "description": "When set, the rule only applies to test cases carrying this label"
          },
          "scenarioShortIds": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ScenarioShortId"
            },
            "nullable": true,
            "description": "When set, the rule only applies to test cases in these scenarios"
          },
          "urlPathFilter": {
            "type": "string",
            "nullable": true,
            "description": "When set, the rule only applies to tests whose start URL path contains this substring"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32",
            "description": "Rules are applied in ascending sort order"
          },
          "createdAt": {
            "type": "string"
          },
          "updatedAt": {
            "type": "string"
          }
        }
      },
      "ProjectScopedRequest": {
        "type": "object",
        "properties": {
          "projectShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProjectShortId"
              }
            ],
            "description": "Target a specific project by its prefixed short ID (proj-slug_shortId or proj_shortId), as returned by the projects API. Required for organization-scoped API keys; project-scoped keys may only pass their own project's short ID."
          }
        },
        "description": "Mixin for project-scoped requests: an optional per-call project override."
      },
      "ProjectShortId": {
        "type": "string",
        "pattern": "^proj(-.+_.+|_.+)$"
      },
      "ReleaseCheckCategory": {
        "type": "object",
        "required": [
          "key",
          "label",
          "score",
          "checks",
          "scoredCount",
          "passedCount",
          "failedCount",
          "manualCount",
          "naCount",
          "unverifiedCount"
        ],
        "properties": {
          "key": {
            "$ref": "#/components/schemas/ReleaseCheckCategoryKey"
          },
          "label": {
            "type": "string"
          },
          "score": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "checks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ReleaseCheckCheck"
            }
          },
          "scoredCount": {
            "type": "integer",
            "format": "int32"
          },
          "passedCount": {
            "type": "integer",
            "format": "int32"
          },
          "failedCount": {
            "type": "integer",
            "format": "int32"
          },
          "manualCount": {
            "type": "integer",
            "format": "int32"
          },
          "naCount": {
            "type": "integer",
            "format": "int32"
          },
          "unverifiedCount": {
            "type": "integer",
            "format": "int32"
          }
        },
        "description": "A scored category aggregating its checks. Score is a 0-100 severity-weighted pass rate, or null when no checks were scored (all manual/na/unverified)."
      },
      "ReleaseCheckCategoryKey": {
        "type": "string",
        "enum": [
          "functional",
          "ux_content",
          "accessibility",
          "trust_legal",
          "ecommerce",
          "compatibility_health",
          "brand"
        ],
        "description": "User-facing category a launch check belongs to."
      },
      "ReleaseCheckChange": {
        "type": "object",
        "required": [
          "summary"
        ],
        "properties": {
          "summary": {
            "type": "string",
            "minLength": 1,
            "description": "Short statement of what this change does or intends. Example: 'Add a discount-code field to checkout'."
          },
          "details": {
            "type": "string",
            "description": "Longer description: the user's prompt, the PR body, or the ticket description behind this change."
          },
          "kind": {
            "type": "string",
            "enum": [
              "feature",
              "fix",
              "refactor",
              "content",
              "config",
              "other"
            ],
            "description": "Kind of change, used to focus testing."
          },
          "source": {
            "type": "string",
            "enum": [
              "user_prompt",
              "pull_request",
              "ticket",
              "commit",
              "changelog",
              "other"
            ],
            "description": "Where this change description came from."
          },
          "reference": {
            "type": "string",
            "description": "Optional URL or identifier for the change (PR link, ticket key)."
          },
          "diff": {
            "type": "string",
            "description": "Optional diff for this change."
          }
        },
        "description": "A single intended change in the release, described by the calling agent. This intent layer is richer than a diff: it tells the review agent what the change was meant to achieve so it can verify the outcome, not just detect what bytes changed."
      },
      "ReleaseCheckCheck": {
        "type": "object",
        "required": [
          "id",
          "title",
          "status",
          "automatable"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Stable catalog id, e.g. 'functional.signup'."
          },
          "title": {
            "type": "string"
          },
          "status": {
            "$ref": "#/components/schemas/ReleaseCheckCheckStatus"
          },
          "automatable": {
            "type": "boolean",
            "description": "Whether QA.tech can evaluate this check today (vs. human-only)."
          },
          "severity": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ReleaseCheckSeverity"
              }
            ],
            "description": "Severity of the issue when status is 'fail'."
          },
          "evidence": {
            "type": "string",
            "description": "Evidence: a short observation backing the status."
          },
          "recommendation": {
            "type": "string"
          },
          "screenshotUrl": {
            "type": "string",
            "description": "Durable screenshot URL evidencing the finding (mainly on fails)."
          },
          "testRunShortId": {
            "type": "string",
            "description": "Short id of the run that produced the evidence, for a 'view run' link."
          }
        },
        "description": "A single launch check evaluated during the review."
      },
      "ReleaseCheckCheckStatus": {
        "type": "string",
        "enum": [
          "pass",
          "fail",
          "na",
          "manual",
          "unverified"
        ],
        "description": "Status of a single launch check. pass/fail are scored; na is excluded; manual/unverified are surfaced but not scored."
      },
      "ReleaseCheckCoverageItem": {
        "type": "object",
        "required": [
          "section",
          "coverage"
        ],
        "properties": {
          "section": {
            "type": "string"
          },
          "coverage": {
            "type": "string",
            "enum": [
              "automated",
              "partial",
              "manual",
              "skipped"
            ]
          },
          "notes": {
            "type": "string"
          }
        },
        "description": "How well a checklist section was covered by this check."
      },
      "ReleaseCheckFinding": {
        "type": "object",
        "required": [
          "title",
          "severity",
          "category",
          "description",
          "isBlocker"
        ],
        "properties": {
          "title": {
            "type": "string"
          },
          "severity": {
            "$ref": "#/components/schemas/ReleaseCheckSeverity"
          },
          "category": {
            "type": "string",
            "description": "Checklist category this finding belongs to, e.g. 'Signup and onboarding'."
          },
          "description": {
            "type": "string"
          },
          "recommendation": {
            "type": "string",
            "description": "Recommended fix or next step."
          },
          "evidence": {
            "type": "string",
            "description": "Evidence: a test link, screenshot URL, or short observation."
          },
          "isBlocker": {
            "type": "boolean",
            "description": "Whether this finding is critical (highlighted as a top issue to fix). Informational only; it does not block a release."
          }
        },
        "description": "A single issue the review agent found, classified by severity."
      },
      "ReleaseCheckHealthSignals": {
        "type": "object",
        "required": [
          "consoleErrors",
          "networkFailures",
          "openIssues"
        ],
        "properties": {
          "consoleErrors": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "networkFailures": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "openIssues": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Currently open project issues (console/failed-test) surfaced alongside the run."
          }
        },
        "description": "Technical health signals observed while testing. Extension point for future static checks and issue reporters."
      },
      "ReleaseCheckIntentVerification": {
        "type": "object",
        "required": [
          "changeSummary",
          "status"
        ],
        "properties": {
          "changeSummary": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "verified",
              "failed",
              "not_verified"
            ]
          },
          "notes": {
            "type": "string"
          }
        },
        "description": "Verification of one intended change against the live app."
      },
      "ReleaseCheckPageTested": {
        "type": "object",
        "required": [
          "label",
          "screenshotUrl"
        ],
        "properties": {
          "label": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "screenshotUrl": {
            "type": "string"
          }
        },
        "description": "A page the review exercised, with a screenshot, for the 'pages tested' filmstrip."
      },
      "ReleaseCheckProgress": {
        "type": "object",
        "required": [
          "message",
          "updatedAt"
        ],
        "properties": {
          "message": {
            "type": "string",
            "description": "Short, user-facing status line for what the agent is doing right now."
          },
          "testsRun": {
            "type": "integer",
            "format": "int32",
            "description": "How many tests have finished running so far this run."
          },
          "changesVerified": {
            "type": "integer",
            "format": "int32",
            "description": "How many intended changes have been verified so far."
          },
          "changesTotal": {
            "type": "integer",
            "format": "int32",
            "description": "Total intended changes to verify (denominator for changesVerified)."
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "description": "When this progress was last updated."
          }
        },
        "description": "Rolling latest progress reported by the review agent while the check runs. Overwritten on each update (no history). Null until the agent posts its first update or once the check has finished. Counters are advisory live values; final numbers come from automatedTestSummary / intentVerification."
      },
      "ReleaseCheckRegressionInput": {
        "type": "object",
        "properties": {
          "testPlanShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/TestPlanShortId"
              }
            ],
            "description": "Run an existing test plan as the regression baseline."
          },
          "testCaseIds": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Run a specific set of project test case IDs as the regression baseline."
          }
        },
        "description": "Regression suite selection for a release check. Provide a test plan or explicit test case IDs; omit both to let the agent decide what to run."
      },
      "ReleaseCheckReport": {
        "type": "object",
        "required": [
          "shortId",
          "url",
          "releaseName",
          "status",
          "verdict",
          "summary",
          "progress",
          "categories",
          "overallScore",
          "findings",
          "intentVerification",
          "pagesTested",
          "checklistCoverage",
          "healthSignals",
          "manualFollowUps",
          "automatedTestSummary",
          "markdown",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "shortId": {
            "$ref": "#/components/schemas/ReleaseCheckShortId"
          },
          "url": {
            "type": "string",
            "description": "Dashboard URL for the release check's launch-readiness report."
          },
          "releaseName": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/ReleaseCheckStatus"
          },
          "verdict": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ReleaseCheckVerdict"
              }
            ],
            "nullable": true,
            "description": "Overall launch verdict. Null while the review is still running."
          },
          "summary": {
            "type": "string",
            "nullable": true,
            "description": "Narrative summary of the release's readiness. Null until the agent finishes."
          },
          "progress": {
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/ReleaseCheckProgress"
              }
            ],
            "nullable": true,
            "description": "Rolling latest progress while the check is running. Null once it finishes or before the first update."
          },
          "categories": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ReleaseCheckCategory"
            },
            "description": "Scored categories, each aggregating its checks. Empty until the agent finishes."
          },
          "overallScore": {
            "type": "integer",
            "format": "int32",
            "nullable": true,
            "description": "Overall 0-100 score (weighted average of scored categories). Null while running or when nothing was scored."
          },
          "findings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ReleaseCheckFinding"
            }
          },
          "intentVerification": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ReleaseCheckIntentVerification"
            }
          },
          "pagesTested": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ReleaseCheckPageTested"
            },
            "description": "Key pages exercised during the review, with screenshots."
          },
          "checklistCoverage": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ReleaseCheckCoverageItem"
            }
          },
          "healthSignals": {
            "$ref": "#/components/schemas/ReleaseCheckHealthSignals"
          },
          "manualFollowUps": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "automatedTestSummary": {
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/ReleaseCheckTestSummary"
              }
            ],
            "nullable": true,
            "description": "Automated test totals. Null until tests have run."
          },
          "markdown": {
            "type": "string",
            "description": "Human-readable Markdown rendering of the report."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "description": "Compiled launch-readiness report, synthesized by the review agent."
      },
      "ReleaseCheckRequest": {
        "type": "object",
        "properties": {
          "releaseName": {
            "type": "string",
            "description": "Human-readable name for this release, e.g. 'v2.3.0' or 'June checkout revamp'."
          },
          "releaseSummary": {
            "type": "string",
            "description": "Short description of what this release contains."
          },
          "context": {
            "type": "string",
            "description": "Free-text focus areas, risk areas, or instructions for the review."
          },
          "changes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ReleaseCheckChange"
            },
            "description": "The intended changes in this release (user prompts, PR descriptions, tickets). The review agent verifies each one behaves as described."
          },
          "regression": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ReleaseCheckRegressionInput"
              }
            ],
            "description": "Regression baseline to run as part of the check."
          },
          "prUrl": {
            "type": "string",
            "format": "uri",
            "description": "Optional pull request URL to enrich the review with diffs and deployment info. Requires vcsProviderId."
          },
          "vcsProviderId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/VcsProviderId"
              }
            ],
            "description": "VCS provider for prUrl."
          },
          "applicationOverrides": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApplicationOverrideWithRequiredEnvironment"
            },
            "description": "Per-application environment overrides identifying the build/URL under review."
          },
          "projectShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProjectShortId"
              }
            ],
            "description": "Target a specific project by its prefixed short ID (proj-slug_shortId or proj_shortId), as returned by the projects API. Required for organization-scoped API keys; project-scoped keys may only pass their own project's short ID."
          }
        },
        "description": "Request body for starting a release check.\n\nThe calling agent describes the release and its intended changes; QA.tech runs\nan autonomous launch-review agent that tests the current state of the app\nagainst an end-user launch checklist, verifies the intended changes, and\nsynthesizes an informational launch-readiness report (Lighthouse-style: it\nscores the app and highlights what needs attention, it does not block a\nrelease). All testing and analysis runs on QA.tech and does not consume the\ncaller's tokens.\n\nProvide at least one of `changes`, `regression`, or `prUrl` so the agent has\nsomething concrete to review."
      },
      "ReleaseCheckResponse": {
        "type": "object",
        "required": [
          "shortId",
          "url",
          "status"
        ],
        "properties": {
          "shortId": {
            "$ref": "#/components/schemas/ReleaseCheckShortId"
          },
          "url": {
            "type": "string",
            "description": "Dashboard URL for the release check's launch-readiness report."
          },
          "status": {
            "$ref": "#/components/schemas/ReleaseCheckStatus"
          },
          "reviewShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ChatConversationShortId"
              }
            ],
            "description": "Short ID of the launch-review conversation driving this check."
          }
        },
        "description": "Lightweight response returned immediately after starting a release check."
      },
      "ReleaseCheckSeverity": {
        "type": "string",
        "enum": [
          "critical",
          "high",
          "medium",
          "low"
        ],
        "description": "Severity of a release finding, per the launch checklist severity guide."
      },
      "ReleaseCheckShortId": {
        "type": "string",
        "pattern": "^rc(-.+_.+|_.+)$"
      },
      "ReleaseCheckStatus": {
        "type": "string",
        "enum": [
          "pending",
          "running",
          "completed",
          "failed"
        ],
        "description": "Lifecycle status of a release check."
      },
      "ReleaseCheckTestSummary": {
        "type": "object",
        "required": [
          "passed",
          "failed",
          "total",
          "runShortIds"
        ],
        "properties": {
          "passed": {
            "type": "integer",
            "format": "int32"
          },
          "failed": {
            "type": "integer",
            "format": "int32"
          },
          "total": {
            "type": "integer",
            "format": "int32"
          },
          "runShortIds": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "description": "Aggregate of the automated tests run during the check."
      },
      "ReleaseCheckVerdict": {
        "type": "string",
        "enum": [
          "ready",
          "needs_attention",
          "not_ready"
        ],
        "description": "Overall launch verdict, set once the review agent finishes."
      },
      "RemoteTunnelStatusResponse": {
        "type": "object",
        "required": [
          "status",
          "connections",
          "hostnames"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "inactive",
              "degraded",
              "healthy"
            ],
            "description": "inactive = no connections, degraded = 1-3 connections, healthy = 4+ connections"
          },
          "connections": {
            "type": "integer",
            "format": "int32",
            "description": "Number of active Cloudflare edge connections"
          },
          "hostnames": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HostnameInfo"
            },
            "description": "Public hostnames for this tunnel"
          }
        },
        "description": "Live health status of a remote tunnel from Cloudflare"
      },
      "RemoteTunnelSummary": {
        "type": "object",
        "required": [
          "runnerId",
          "hostnames",
          "createdAt",
          "expiresAt",
          "isExpired"
        ],
        "properties": {
          "runnerId": {
            "type": "string"
          },
          "hostnames": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HostnameInfo"
            }
          },
          "createdAt": {
            "type": "string"
          },
          "expiresAt": {
            "type": "string"
          },
          "isExpired": {
            "type": "boolean",
            "description": "Whether the tunnel is expired (expires_at is in the past)"
          }
        },
        "description": "Summary of an active remote tunnel"
      },
      "RerunRequest": {
        "type": "object",
        "properties": {
          "failedOnly": {
            "type": "boolean",
            "description": "Rerun only failed/skipped/errored test cases from the original run."
          },
          "projectTestCaseIds": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Rerun only these test cases, by project test case ID (UUID)."
          },
          "skipAgentCache": {
            "type": "boolean",
            "description": "Set to `true` to run every test in this run without the agent cache, so the agent works out each step fresh instead of reusing cached outputs. Applies to this run only. Omitted or `false` keeps each test's own Agent Cache setting."
          },
          "projectShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProjectShortId"
              }
            ],
            "description": "Target a specific project by its prefixed short ID (proj-slug_shortId or proj_shortId), as returned by the projects API. Required for organization-scoped API keys; project-scoped keys may only pass their own project's short ID."
          }
        },
        "description": "Request body to rerun a prior run. Provide either `failedOnly` or `projectTestCaseIds`, not both (sending both returns 400). Send an empty object to rerun everything."
      },
      "RerunResponse": {
        "type": "object",
        "required": [
          "success",
          "run"
        ],
        "properties": {
          "success": {
            "type": "boolean"
          },
          "run": {
            "$ref": "#/components/schemas/RerunRun"
          }
        }
      },
      "RerunRun": {
        "type": "object",
        "required": [
          "id",
          "shortId",
          "url",
          "testCount"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "shortId": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "testCount": {
            "type": "integer",
            "format": "int32"
          }
        }
      },
      "RuleConsumer": {
        "type": "string",
        "enum": [
          "chat",
          "agent",
          "pr_review"
        ],
        "description": "Which QA.tech agent the rule applies to: `chat` steers the AI chat assistant, `agent` steers the test agent during runs, `pr_review` steers PR review checks."
      },
      "Run": {
        "type": "object",
        "required": [
          "id",
          "shortId",
          "url",
          "testCount",
          "testPlan"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "shortId": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "testCount": {
            "type": "integer",
            "format": "int32"
          },
          "testPlan": {
            "$ref": "#/components/schemas/TestPlan"
          }
        }
      },
      "RunIssue": {
        "type": "object",
        "required": [
          "id",
          "shortId",
          "title",
          "description",
          "severity",
          "issueType",
          "helpUrl",
          "tags",
          "status",
          "testCases"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "shortId": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "severity": {
            "type": "string"
          },
          "issueType": {
            "type": "string",
            "description": "The category of the issue, e.g. `ACCESSIBILITY`, `CONSOLE`, `HOSTING`, or `FAILED_TEST`."
          },
          "helpUrl": {
            "type": "string",
            "nullable": true
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "status": {
            "type": "string"
          },
          "testCases": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RunIssueTestCase"
            },
            "description": "Test cases in the run where this issue was detected."
          }
        },
        "description": "An issue detected during the run, deduplicated and aggregated across the test cases that triggered it."
      },
      "RunIssueCategory": {
        "type": "string",
        "enum": [
          "accessibility",
          "console",
          "hosting",
          "failed_test"
        ],
        "description": "Category of issue detected during a run."
      },
      "RunIssueTestCase": {
        "type": "object",
        "required": [
          "shortId",
          "name"
        ],
        "properties": {
          "shortId": {
            "type": "string"
          },
          "name": {
            "type": "string"
          }
        }
      },
      "RunIssuesQuery": {
        "type": "object",
        "properties": {
          "issueType": {
            "allOf": [
              {
                "$ref": "#/components/schemas/RunIssueCategory"
              }
            ],
            "description": "Filter to a single issue category. Omitted returns issues of every type."
          },
          "projectShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProjectShortId"
              }
            ],
            "description": "Target a specific project by its prefixed short ID (proj-slug_shortId or proj_shortId), as returned by the projects API. Required for organization-scoped API keys; project-scoped keys may only pass their own project's short ID."
          }
        }
      },
      "RunIssuesResponse": {
        "type": "object",
        "required": [
          "runShortId",
          "issues"
        ],
        "properties": {
          "runShortId": {
            "type": "string"
          },
          "issues": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RunIssue"
            }
          }
        },
        "description": "Issues detected during a run."
      },
      "RunParametersOverrides": {
        "type": "object",
        "properties": {
          "configs": {
            "type": "object",
            "additionalProperties": {},
            "description": "Config identifier → full config object (replaces stored config data when present)."
          },
          "configsByEnvironment": {
            "type": "object",
            "additionalProperties": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": "Environment id → config identifier → full config object."
          }
        },
        "description": "Optional run-time parameter overrides merged into the blueprint (after test plan defaults). Use `configs` to replace full config payloads by config short id (map keys are strings such as `cfg_...` or human-readable slugs); use `configsByEnvironment` for environment-specific overrides (outer key is environment UUID)."
      },
      "RunRequest": {
        "type": "object",
        "properties": {
          "trigger": {
            "type": "string",
            "enum": [
              "API",
              "GITHUB",
              "GITLAB"
            ]
          },
          "actor": {
            "type": "string",
            "description": "Username that triggered the CI job. Example: `octocat`."
          },
          "branch": {
            "type": "string",
            "description": "Branch the run was triggered from. Example: `main` or `refs/heads/main`."
          },
          "commitHash": {
            "type": "string",
            "description": "Full commit SHA the run was triggered for. Used to link the run back to the commit."
          },
          "commitMessage": {
            "type": "string",
            "description": "Commit message subject for the triggering commit."
          },
          "repository": {
            "type": "string",
            "description": "Repository the run was triggered from, as `owner/name`. Example: `QAdottech/qatech`."
          },
          "repositoryUrl": {
            "type": "string",
            "format": "uri",
            "pattern": "^https?:\\x2f\\x2f",
            "description": "Base repository URL for GitLab, including the origin and project path. Supports self-hosted GitLab instances."
          },
          "testPlanShortId": {
            "$ref": "#/components/schemas/TestPlanShortId"
          },
          "testCaseIds": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "applications": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApplicationOverride"
            },
            "description": "Per-run application overrides. On environment, optional customHeaders and basicAuth persist auth or protection-bypass rules. Omit either field to leave stored rules unchanged; pass an empty list to clear them."
          },
          "notifications": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NotificationOverride"
            }
          },
          "parameters": {
            "$ref": "#/components/schemas/RunParametersOverrides"
          },
          "skipAgentCache": {
            "type": "boolean",
            "description": "Set to `true` to run every test in this run without the agent cache, so the agent works out each step fresh instead of reusing cached outputs. Applies to this run only. Omitted or `false` keeps each test's own Agent Cache setting."
          },
          "projectShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProjectShortId"
              }
            ],
            "description": "Target a specific project by its prefixed short ID (proj-slug_shortId or proj_shortId), as returned by the projects API. Required for organization-scoped API keys; project-scoped keys may only pass their own project's short ID."
          }
        },
        "description": "Request body for triggering a test run. Supports GitHub and GitLab trigger fields, application overrides, and optional `parameters` for config overrides (merged into the blueprint)."
      },
      "RunResponse": {
        "type": "object",
        "required": [
          "success",
          "run"
        ],
        "properties": {
          "success": {
            "type": "boolean"
          },
          "run": {
            "$ref": "#/components/schemas/Run"
          }
        }
      },
      "RunSummary": {
        "type": "object",
        "required": [
          "shortId",
          "status",
          "result"
        ],
        "properties": {
          "shortId": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "description": "Run lifecycle status: `INITIATED`, `RUNNING`, `COMPLETED`, `ERROR`, or `CANCELLED`."
          },
          "result": {
            "type": "string",
            "nullable": true,
            "description": "Run outcome once status is `COMPLETED`: `PASSED`, `FAILED`, or `SKIPPED`. `null` while the run is still in progress."
          }
        }
      },
      "RunTestCase": {
        "type": "object",
        "required": [
          "id",
          "shortId",
          "name",
          "status",
          "result",
          "resultTitle",
          "evaluationThought",
          "errorCode",
          "classification",
          "promptGoal",
          "promptExamples"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "shortId": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "result": {
            "type": "string",
            "nullable": true
          },
          "resultTitle": {
            "type": "string",
            "nullable": true
          },
          "evaluationThought": {
            "type": "string",
            "nullable": true,
            "description": "The evaluator's reasoning for the pass/fail verdict."
          },
          "errorCode": {
            "type": "string",
            "nullable": true,
            "description": "Error classification when the test did not cleanly pass/fail, e.g. `TEST_FAILED` (real product failure) vs an `AGENT_`/`PLATFORM_` execution miss. `null` for a clean pass."
          },
          "classification": {
            "type": "string",
            "nullable": true,
            "description": "`POSITIVE` (expected to succeed) or `NEGATIVE` (expected to fail)."
          },
          "promptGoal": {
            "type": "string",
            "nullable": true
          },
          "promptExamples": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "RunTestCaseApiCallEntry": {
        "type": "object",
        "required": [
          "url",
          "method",
          "statusCode",
          "success",
          "durationMs"
        ],
        "properties": {
          "url": {
            "type": "string"
          },
          "method": {
            "type": "string"
          },
          "statusCode": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "success": {
            "type": "boolean"
          },
          "textResult": {
            "type": "string",
            "nullable": true
          },
          "durationMs": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "requestHeaders": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "requestBody": {
            "type": "string"
          },
          "requestBodyTruncated": {
            "type": "boolean"
          },
          "responseBody": {
            "type": "string"
          },
          "responseBodyTruncated": {
            "type": "boolean"
          },
          "errorMessage": {
            "type": "string"
          }
        },
        "description": "A server-side API call the agent made (API application tests), with truncated bodies."
      },
      "RunTestCaseAssessment": {
        "type": "object",
        "required": [
          "shortDescription",
          "confidence",
          "expectedBehavior",
          "actualBehavior",
          "notesAndHypotheses",
          "keyObservations",
          "issues"
        ],
        "properties": {
          "shortDescription": {
            "type": "string",
            "nullable": true,
            "description": "The evaluator's verdict summary, with `[step:N]` references into the execution."
          },
          "confidence": {
            "type": "integer",
            "format": "int32",
            "nullable": true,
            "description": "Evaluator confidence in the verdict, 0-100."
          },
          "expectedBehavior": {
            "type": "string",
            "nullable": true
          },
          "actualBehavior": {
            "type": "string",
            "nullable": true
          },
          "notesAndHypotheses": {
            "type": "string",
            "nullable": true,
            "description": "The evaluator's hypotheses about the root cause."
          },
          "keyObservations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RunTestCaseKeyObservation"
            }
          },
          "issues": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RunTestCaseAssessmentIssue"
            }
          }
        },
        "description": "The evaluator's structured assessment of a run test case."
      },
      "RunTestCaseAssessmentIssue": {
        "type": "object",
        "required": [
          "severity",
          "title",
          "description",
          "category"
        ],
        "properties": {
          "severity": {
            "type": "string",
            "description": "`CRITICAL`, `MAJOR`, or `MINOR`."
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "category": {
            "type": "string",
            "description": "Issue category, e.g. `unexpected_behavior`, `network_error`, `data_mismatch`."
          }
        },
        "description": "An issue the evaluator raised while assessing the execution."
      },
      "RunTestCaseConsoleEntry": {
        "type": "object",
        "required": [
          "level",
          "message",
          "relativeTimestampSeconds"
        ],
        "properties": {
          "level": {
            "type": "string",
            "description": "`error`, `warning`, or `log`."
          },
          "message": {
            "type": "string"
          },
          "source": {
            "type": "string",
            "nullable": true
          },
          "line": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "column": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "relativeTimestampSeconds": {
            "type": "integer",
            "format": "int32",
            "description": "Seconds since the first captured console entry."
          }
        },
        "description": "A browser console entry captured during the execution."
      },
      "RunTestCaseKeyObservation": {
        "type": "object",
        "required": [
          "stepIndex",
          "observation"
        ],
        "properties": {
          "stepIndex": {
            "type": "integer",
            "format": "int32",
            "nullable": true,
            "description": "0-based execution step the observation refers to (the `[step:N]` references in the report). Pass it to `get_run_test_case_screenshots`. `null` when not tied to a step."
          },
          "observation": {
            "type": "string"
          }
        },
        "description": "One observation the evaluator anchored to a step of the execution."
      },
      "RunTestCaseNetworkEntry": {
        "type": "object",
        "required": [
          "url",
          "method",
          "statusCode",
          "isError"
        ],
        "properties": {
          "url": {
            "type": "string"
          },
          "method": {
            "type": "string"
          },
          "statusCode": {
            "type": "integer",
            "format": "int32",
            "description": "HTTP status. `0` means the request never completed (aborted, CORS, DNS)."
          },
          "durationMs": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "isError": {
            "type": "boolean"
          },
          "errorText": {
            "type": "string",
            "description": "Browser error text for failed requests, e.g. `net::ERR_ABORTED`."
          },
          "crossOriginInfo": {
            "type": "string"
          },
          "customExtraHeaders": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Names of custom headers (from the environment or device preset) attached to the request. Values are never included."
          }
        },
        "description": "A browser network request captured during the execution."
      },
      "RunTestCaseScreenshot": {
        "type": "object",
        "required": [
          "stepIndex",
          "pageUrl",
          "url",
          "mimeType",
          "data",
          "error"
        ],
        "properties": {
          "stepIndex": {
            "type": "integer",
            "format": "int32",
            "nullable": true,
            "description": "0-based execution step. `null` for the final screenshot."
          },
          "pageUrl": {
            "type": "string",
            "nullable": true,
            "description": "The page URL the agent was on at this step."
          },
          "url": {
            "type": "string",
            "nullable": true,
            "description": "Source image URL. May be time-limited."
          },
          "mimeType": {
            "type": "string",
            "nullable": true,
            "description": "Image media type, e.g. `image/jpeg`. MCP clients receive the image itself as an image content block."
          },
          "data": {
            "type": "string",
            "nullable": true,
            "description": "Base64-encoded image bytes."
          },
          "error": {
            "type": "string",
            "nullable": true,
            "description": "Why the screenshot could not be returned, if it could not."
          }
        },
        "description": "A screenshot of one execution step."
      },
      "RunTestCaseStep": {
        "type": "object",
        "required": [
          "index",
          "startedAt",
          "endedAt",
          "durationMs",
          "reasoning",
          "toolCalls",
          "toolResult",
          "screenshotUrl"
        ],
        "properties": {
          "index": {
            "type": "integer",
            "format": "int32",
            "description": "1-based position of the step within the full trace."
          },
          "startedAt": {
            "type": "string",
            "nullable": true
          },
          "endedAt": {
            "type": "string",
            "nullable": true
          },
          "durationMs": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "reasoning": {
            "type": "string",
            "nullable": true,
            "description": "The agent's reasoning for this step."
          },
          "toolCalls": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RunTestCaseToolCall"
            }
          },
          "toolResult": {
            "type": "string",
            "nullable": true,
            "description": "The tool result observed after the action. Truncated for large outputs."
          },
          "screenshotUrl": {
            "type": "string",
            "nullable": true,
            "description": "Screenshot captured around this step, if any. May be a time-limited URL."
          }
        },
        "description": "One reason→act step in the agent's trace."
      },
      "RunTestCaseToolCall": {
        "type": "object",
        "required": [
          "name",
          "arguments"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Tool name, e.g. `click`, `type`, `navigate`, `evaluate`."
          },
          "arguments": {
            "type": "object",
            "additionalProperties": {},
            "description": "Arguments the agent passed to the tool."
          }
        },
        "description": "A single tool the agent invoked within a step."
      },
      "ScenarioShortId": {
        "type": "string",
        "pattern": "^scenario(-.+_.+|_.+)$"
      },
      "SlackNotificationOverride": {
        "type": "object",
        "required": [
          "type"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "slack"
            ]
          },
          "channel": {
            "type": "string",
            "description": "Slack channel ID (e.g. `C0478ABCDEF`). Required unless `enabled` is `false`. The QA.tech Slack bot must have access to the channel."
          },
          "notifyOn": {
            "type": "string",
            "enum": [
              "failure",
              "always"
            ],
            "description": "`always` (default) sends run-started and final-result messages; `failure` sends only the final summary when the result is not PASSED."
          },
          "enabled": {
            "type": "boolean",
            "description": "Set to `false` to suppress Slack for this run, including project defaults."
          }
        }
      },
      "StartChangeReviewFromPrRequest": {
        "type": "object",
        "required": [
          "mode",
          "prUrl",
          "vcsProviderId",
          "applicationOverrides"
        ],
        "properties": {
          "mode": {
            "type": "string",
            "enum": [
              "pr"
            ]
          },
          "prUrl": {
            "type": "string",
            "format": "uri"
          },
          "vcsProviderId": {
            "$ref": "#/components/schemas/VcsProviderId"
          },
          "applicationOverrides": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApplicationOverrideWithRequiredEnvironment"
            },
            "description": "Required per-application environment overrides. Optional customHeaders and basicAuth on environment persist auth or protection-bypass rules."
          },
          "context": {
            "type": "string"
          },
          "forceNewConversation": {
            "type": "boolean",
            "description": "Force a brand-new chat instead of reusing the pull request's existing review conversation. Defaults to false, so repeated reviews of the same PR share one chat unless that chat is archived.",
            "default": false
          },
          "postMerge": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ChangeReviewPostMergeOptions"
              }
            ],
            "description": "Optional post-merge options for this PR. Stored on the review conversation and applied when the PR merges. Overrides GitHub App integration settings for this PR only."
          },
          "triage": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ChangeReviewTriageOptions"
              }
            ],
            "description": "Optional PR triage options for this review. GitHub pull requests only. Overrides the GitHub App integration PR triage toggle and prompt for this review."
          },
          "actor": {
            "type": "string",
            "description": "Username that triggered the CI job. Example: `octocat`."
          },
          "branch": {
            "type": "string",
            "description": "Branch the run was triggered from. Example: `main` or `refs/heads/main`."
          },
          "commitHash": {
            "type": "string",
            "description": "Full commit SHA the run was triggered for. Used to link the run back to the commit."
          },
          "commitMessage": {
            "type": "string",
            "description": "Commit message subject for the triggering commit."
          },
          "repository": {
            "type": "string",
            "description": "Repository the run was triggered from, as `owner/name`. Example: `QAdottech/qatech`."
          },
          "projectShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProjectShortId"
              }
            ],
            "description": "Target a specific project by its prefixed short ID (proj-slug_shortId or proj_shortId), as returned by the projects API. Required for organization-scoped API keys; project-scoped keys may only pass their own project's short ID."
          }
        },
        "description": "Start a change review chat using a pull request URL"
      },
      "StartChangeReviewFromRawChangesRequest": {
        "type": "object",
        "required": [
          "mode",
          "changes",
          "applicationOverrides"
        ],
        "properties": {
          "mode": {
            "type": "string",
            "enum": [
              "rawChanges"
            ]
          },
          "changes": {
            "$ref": "#/components/schemas/ChangeReviewRawChanges"
          },
          "applicationOverrides": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApplicationOverrideWithRequiredEnvironment"
            },
            "description": "Required per-application environment overrides. Optional customHeaders and basicAuth on environment persist auth or protection-bypass rules."
          },
          "context": {
            "type": "string"
          },
          "actor": {
            "type": "string",
            "description": "Username that triggered the CI job. Example: `octocat`."
          },
          "branch": {
            "type": "string",
            "description": "Branch the run was triggered from. Example: `main` or `refs/heads/main`."
          },
          "commitHash": {
            "type": "string",
            "description": "Full commit SHA the run was triggered for. Used to link the run back to the commit."
          },
          "commitMessage": {
            "type": "string",
            "description": "Commit message subject for the triggering commit."
          },
          "repository": {
            "type": "string",
            "description": "Repository the run was triggered from, as `owner/name`. Example: `QAdottech/qatech`."
          },
          "projectShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProjectShortId"
              }
            ],
            "description": "Target a specific project by its prefixed short ID (proj-slug_shortId or proj_shortId), as returned by the projects API. Required for organization-scoped API keys; project-scoped keys may only pass their own project's short ID."
          }
        },
        "description": "Start a change review chat using raw change data"
      },
      "StartChangeReviewRequest": {
        "anyOf": [
          {
            "$ref": "#/components/schemas/StartChangeReviewFromPrRequest"
          },
          {
            "$ref": "#/components/schemas/StartChangeReviewFromRawChangesRequest"
          }
        ],
        "description": "Request body for starting a change review chat"
      },
      "StatusBadgeExampleName": {
        "type": "string",
        "enum": [
          "failing",
          "passing",
          "pending",
          "running",
          "rainbow",
          "partial",
          "error",
          "skipped",
          "cancelled",
          "mixed",
          "trend-improving",
          "trend-declining",
          "trend-fluctuating",
          "trend-stable",
          "zero-tests"
        ],
        "description": "Named presets for GET /v1/badge-example.svg (deterministic sample SVGs)."
      },
      "StatusBadgeStyle": {
        "type": "string",
        "enum": [
          "minimal",
          "standard",
          "detailed",
          "trend"
        ],
        "description": "Display style of the status badge."
      },
      "StatusBadgeTriggerFilter": {
        "type": "string",
        "enum": [
          "ANY",
          "MANUAL",
          "SCHEDULE",
          "API",
          "GITHUB",
          "GITLAB"
        ],
        "description": "Permitted values for filtering a status badge by run trigger. Omit the parameter to include all triggers; use ANY for the same behavior explicitly."
      },
      "TeamsNotificationOverride": {
        "type": "object",
        "required": [
          "type"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "teams"
            ]
          },
          "notifyOn": {
            "type": "string",
            "enum": [
              "failure",
              "always"
            ],
            "description": "`always` (default) or `failure`. Uses the project Microsoft Teams integration webhook."
          },
          "enabled": {
            "type": "boolean",
            "description": "Set to `false` to suppress Teams for this run, including project defaults. Defaults to `true`."
          }
        }
      },
      "TestCase": {
        "type": "object",
        "required": [
          "id",
          "name",
          "url"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "url": {
            "type": "string"
          }
        }
      },
      "TestCaseDetail": {
        "type": "object",
        "required": [
          "id",
          "name",
          "isEnabled",
          "labels",
          "references",
          "classification",
          "applicationShortId",
          "applicationName",
          "scenarioShortId",
          "scenarioName",
          "goal",
          "expectedResult",
          "steps",
          "startUrlPath",
          "resumeFromDependencyProjectTestCaseId",
          "waitForDependenciesProjectTestCaseIds",
          "createdAt",
          "updatedAt",
          "url"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Project test case ID (UUID). Works with `update_test_case`, `start_run_with_test_cases` (`testCaseIds`), and `rerun_run` (`projectTestCaseIds`)."
          },
          "name": {
            "type": "string"
          },
          "isEnabled": {
            "type": "boolean"
          },
          "labels": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "references": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TestCaseReference"
            }
          },
          "classification": {
            "type": "string",
            "enum": [
              "POSITIVE",
              "NEGATIVE"
            ],
            "description": "`POSITIVE` (expected to succeed) or `NEGATIVE` (expected to fail)."
          },
          "applicationShortId": {
            "$ref": "#/components/schemas/ApplicationShortId"
          },
          "applicationName": {
            "type": "string"
          },
          "scenarioShortId": {
            "type": "string",
            "allOf": [
              {
                "$ref": "#/components/schemas/ScenarioShortId"
              }
            ],
            "nullable": true,
            "description": "Scenario (folder grouping related test cases) the test belongs to. `null` when ungrouped."
          },
          "scenarioName": {
            "type": "string",
            "nullable": true
          },
          "goal": {
            "type": "string",
            "nullable": true,
            "description": "The test's goal — what the agent tries to achieve."
          },
          "expectedResult": {
            "type": "string",
            "nullable": true,
            "description": "The expected result / success criteria the evaluator checks against."
          },
          "steps": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Authored step instructions, in order. Empty when the test only has a goal."
          },
          "startUrlPath": {
            "type": "string",
            "nullable": true,
            "description": "URL path the agent navigates to before executing (e.g. `/dashboard`). `null` means the test starts from its RESUME_FROM dependency's end state, or the application's base URL when it has no dependency."
          },
          "resumeFromDependencyProjectTestCaseId": {
            "type": "string",
            "nullable": true,
            "description": "Test case whose output state this test resumes from (RESUME_FROM). `null` when the test starts fresh."
          },
          "waitForDependenciesProjectTestCaseIds": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Test cases that must finish before this one runs (WAIT_FOR — ordering only, no state carry-over)."
          },
          "createdAt": {
            "type": "string"
          },
          "updatedAt": {
            "type": "string",
            "nullable": true
          },
          "url": {
            "type": "string",
            "description": "Deep link to edit the test case in the QA.tech UI."
          }
        },
        "description": "A test case's authored configuration — what the agent is instructed to do — as distinct from a run's result (see `get_run_test_case`)."
      },
      "TestCaseHistoryItem": {
        "type": "object",
        "required": [
          "runTestCaseShortId",
          "runShortId",
          "status",
          "result",
          "errorCode",
          "startedAt",
          "completedAt",
          "durationMs",
          "url"
        ],
        "properties": {
          "runTestCaseShortId": {
            "type": "string"
          },
          "runShortId": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "description": "Run lifecycle status: `INITIATED`, `RUNNING`, `COMPLETED`, `ERROR`, or `CANCELLED`."
          },
          "result": {
            "type": "string",
            "nullable": true,
            "description": "Outcome: `PASSED`, `FAILED`, or `SKIPPED`. `null` while still running."
          },
          "errorCode": {
            "type": "string",
            "nullable": true,
            "description": "Error classification, when present."
          },
          "startedAt": {
            "type": "string",
            "nullable": true
          },
          "completedAt": {
            "type": "string",
            "nullable": true
          },
          "durationMs": {
            "type": "integer",
            "format": "int32",
            "nullable": true,
            "description": "Wall-clock duration in milliseconds, when both timestamps are present."
          },
          "url": {
            "type": "string",
            "description": "Deep link to this execution's recording and trace in the QA.tech UI."
          }
        },
        "description": "One past execution of a test case, for flaky-vs-consistent analysis."
      },
      "TestCaseLastRun": {
        "type": "object",
        "required": [
          "shortId",
          "status",
          "result",
          "completedAt"
        ],
        "properties": {
          "shortId": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "description": "Run lifecycle status: `INITIATED`, `RUNNING`, `COMPLETED`, `ERROR`, or `CANCELLED`."
          },
          "result": {
            "type": "string",
            "nullable": true,
            "description": "Run outcome once status is `COMPLETED`: `PASSED`, `FAILED`, or `SKIPPED`. `null` while the run is still in progress."
          },
          "completedAt": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "TestCaseReference": {
        "type": "object",
        "required": [
          "kind",
          "key",
          "url",
          "title"
        ],
        "properties": {
          "kind": {
            "type": "string"
          },
          "key": {
            "type": "string",
            "nullable": true
          },
          "url": {
            "type": "string",
            "nullable": true
          },
          "title": {
            "type": "string",
            "nullable": true
          }
        },
        "description": "A clickable entity referenced by a test case (PR, issue, TMS case, or chat)."
      },
      "TestCaseStep": {
        "type": "object",
        "required": [
          "instruction"
        ],
        "properties": {
          "instruction": {
            "type": "string"
          },
          "expectedResult": {
            "type": "string"
          }
        },
        "description": "A single step in a test case definition"
      },
      "TestPlan": {
        "type": "object",
        "required": [
          "name",
          "shortId"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "shortId": {
            "$ref": "#/components/schemas/TestPlanShortId"
          }
        }
      },
      "TestPlanShortId": {
        "type": "string",
        "pattern": "^pln(-.+_.+|_.+)$"
      },
      "TriggerAutomationRequest": {
        "type": "object",
        "properties": {
          "context": {
            "type": "object",
            "additionalProperties": {},
            "description": "Free-form context for this trigger, such as the deployment version or environment name."
          }
        },
        "description": "Optional payload forwarded to the automation as trigger context. Any JSON object; it is surfaced verbatim to the agent that runs the automation."
      },
      "TriggerAutomationResponse": {
        "type": "object",
        "required": [
          "automationId",
          "triggered"
        ],
        "properties": {
          "automationId": {
            "type": "string",
            "description": "The automation that was queued."
          },
          "triggered": {
            "type": "boolean",
            "description": "Always true; the automation runs asynchronously and its work appears as a chat conversation in the project."
          }
        }
      },
      "UpdateAutomationRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "description": {
            "type": "string",
            "nullable": true,
            "maxLength": 500,
            "description": "Set to null to clear the description"
          },
          "isEnabled": {
            "type": "boolean",
            "description": "Re-enabling a schedule automation restarts it from the next upcoming tick."
          },
          "trigger": {
            "allOf": [
              {
                "$ref": "#/components/schemas/AutomationTriggerInput"
              }
            ],
            "description": "Replaces the whole trigger"
          },
          "action": {
            "allOf": [
              {
                "$ref": "#/components/schemas/AutomationAction"
              }
            ],
            "description": "Replaces the whole action"
          },
          "projectShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProjectShortId"
              }
            ],
            "description": "Target a specific project by its prefixed short ID (proj-slug_shortId or proj_shortId), as returned by the projects API. Required for organization-scoped API keys; project-scoped keys may only pass their own project's short ID."
          }
        }
      },
      "UpdateAutomationResponse": {
        "type": "object",
        "required": [
          "success",
          "automation"
        ],
        "properties": {
          "success": {
            "type": "boolean"
          },
          "automation": {
            "$ref": "#/components/schemas/Automation"
          }
        }
      },
      "UpdateKnowledgeItemRequest": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "content": {
            "type": "string",
            "minLength": 1,
            "maxLength": 50000,
            "description": "New text content. Only valid for text and memory items; triggers re-indexing."
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "New URL to crawl. Only valid for link items; triggers a re-crawl."
          },
          "projectShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProjectShortId"
              }
            ],
            "description": "Target a specific project by its prefixed short ID (proj-slug_shortId or proj_shortId), as returned by the projects API. Required for organization-scoped API keys; project-scoped keys may only pass their own project's short ID."
          }
        }
      },
      "UpdateKnowledgeItemResponse": {
        "type": "object",
        "required": [
          "success",
          "item"
        ],
        "properties": {
          "success": {
            "type": "boolean"
          },
          "item": {
            "$ref": "#/components/schemas/KnowledgeItem"
          }
        }
      },
      "UpdateRuleRequest": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "content": {
            "type": "string",
            "minLength": 1,
            "maxLength": 10000
          },
          "applicationShortId": {
            "type": "string",
            "allOf": [
              {
                "$ref": "#/components/schemas/ApplicationShortId"
              }
            ],
            "nullable": true,
            "description": "Set to an application short id to scope the rule, or null to clear the filter"
          },
          "labelFilter": {
            "type": "string",
            "nullable": true,
            "description": "Set to a label to scope the rule, or null to clear the filter"
          },
          "scenarioShortIds": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ScenarioShortId"
            },
            "nullable": true,
            "description": "Set to scenario short ids to scope the rule, or null to clear the filter"
          },
          "urlPathFilter": {
            "type": "string",
            "nullable": true,
            "description": "Set to a URL path substring to scope the rule, or null to clear the filter"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32",
            "description": "Rules are applied in ascending sort order"
          },
          "projectShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProjectShortId"
              }
            ],
            "description": "Target a specific project by its prefixed short ID (proj-slug_shortId or proj_shortId), as returned by the projects API. Required for organization-scoped API keys; project-scoped keys may only pass their own project's short ID."
          }
        }
      },
      "UpdateRuleResponse": {
        "type": "object",
        "required": [
          "success",
          "rule"
        ],
        "properties": {
          "success": {
            "type": "boolean"
          },
          "rule": {
            "$ref": "#/components/schemas/ProjectRule"
          }
        }
      },
      "UpdateTestCaseRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "goal": {
            "type": "string",
            "minLength": 1,
            "description": "The test's goal — what the agent tries to achieve."
          },
          "expectedResult": {
            "type": "string",
            "description": "The expected result, stated as a UI-observable outcome that proves the goal was met."
          },
          "steps": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Full replacement list of step instructions, one action per step in user-visible UI language. Pass an empty array to remove all steps and rely on the goal alone."
          },
          "startUrlPath": {
            "type": "string",
            "nullable": true,
            "description": "URL path the agent navigates to before executing (e.g. `/dashboard`). Pass `null` to clear it so the test starts from its RESUME_FROM dependency's end state (or the application's base URL without one) — do not set a path on a test that has a RESUME_FROM dependency, as it would navigate away from the dependency's end state."
          },
          "labels": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Full replacement list of labels."
          },
          "isEnabled": {
            "type": "boolean"
          },
          "classification": {
            "type": "string",
            "enum": [
              "POSITIVE",
              "NEGATIVE"
            ],
            "description": "`POSITIVE` (expected to succeed) or `NEGATIVE` (expected to fail)."
          },
          "scenarioShortId": {
            "type": "string",
            "allOf": [
              {
                "$ref": "#/components/schemas/ScenarioShortId"
              }
            ],
            "nullable": true,
            "description": "Move the test into an existing scenario (folder). Pass `null` to remove it from its current scenario."
          },
          "resumeFromDependencyProjectTestCaseId": {
            "type": "string",
            "nullable": true,
            "description": "Test case (UUID) whose output state this test resumes from — the preferred way to give a test fresh, valid data instead of hardcoded entities. Pass `null` to remove the RESUME_FROM dependency. Combine with `startUrlPath: null` so the test actually starts from the dependency's end state."
          },
          "waitForDependenciesProjectTestCaseIds": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Full replacement list of test cases (UUIDs) that must finish before this one runs (WAIT_FOR — ordering only). Pass an empty array to remove all WAIT_FOR dependencies. Must not overlap with the RESUME_FROM dependency."
          },
          "projectShortId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProjectShortId"
              }
            ],
            "description": "Target a specific project by its prefixed short ID (proj-slug_shortId or proj_shortId), as returned by the projects API. Required for organization-scoped API keys; project-scoped keys may only pass their own project's short ID."
          }
        },
        "description": "Patch-style update: omitted fields are left unchanged. Nullable fields (`startUrlPath`, `scenarioShortId`, `resumeFromDependencyProjectTestCaseId`) accept `null` to clear the current value."
      },
      "VcsProviderId": {
        "type": "string",
        "enum": [
          "github",
          "gitlab"
        ],
        "description": "Supported VCS providers for pull request URL review mode"
      }
    },
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "Bearer"
      }
    }
  },
  "servers": [
    {
      "url": "https://api.qa.tech",
      "description": "Production",
      "variables": {}
    }
  ]
}
