{"openapi":"3.0.0","info":{"title":"TestArmy API","version":"1.0.0","description":"AI-powered browser automation API for QA testing. Automate web testing workflows using natural language prompts."},"servers":[{"url":"https://tester.army/api","description":"Production API server"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"API Key","description":"API key authentication using Bearer token format"}},"schemas":{"ErrorResponse":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]},"ProjectDetail":{"type":"object","properties":{"browserRegion":{"type":"string","nullable":true,"enum":["eu","us",null],"description":"Default proxy exit region for web runs. null keeps the provider's default networking. Web projects only."},"prTestingEnabled":{"type":"boolean","description":"Test PR deployments automatically."},"prTestingInstructions":{"type":"string","nullable":true,"maxLength":2000,"description":"Free-form instructions for the PR exploration agent."},"prTestingDebounceMinutes":{"type":"integer","minimum":0,"maximum":60,"description":"Quiet period before a PR deployment is tested. 0 disables debouncing."},"prTestingBlockMerge":{"type":"boolean","description":"Conclude the GitHub check run as failed when tests fail, so a required TesterArmy check blocks the merge. Off by default."},"includeExampleMobileApp":{"type":"boolean","description":"Offer the example app as a run target. Mobile projects only."},"autoDeleteOldestMobileApp":{"type":"boolean","description":"Delete the oldest unused app builds when an upload exceeds the storage quota. Mobile projects only."},"accessibilityAuditEnabled":{"type":"boolean","description":"Scan visited pages with axe-core during web runs and report critical accessibility violations as non-blocking warnings. On by default. Web projects only."},"id":{"type":"string","format":"uuid"},"shortId":{"type":"string","nullable":true},"name":{"type":"string"},"url":{"type":"string","nullable":true},"projectType":{"type":"string","enum":["web","mobile"]},"description":{"type":"string","nullable":true},"environments":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"string","enum":["production","pr_preview","static"]},"url":{"type":"string","nullable":true}},"required":["id","name","slug","kind","url"]}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","shortId","name","url","projectType","description","environments"]},"DynamicPrRunRequest":{"anyOf":[{"type":"object","properties":{"targetUrl":{"type":"string","format":"uri"},"platform":{"type":"string","enum":["web"]},"pullRequest":{"type":"object","properties":{"provider":{"type":"string","enum":["github"],"default":"github"},"number":{"type":"integer","minimum":0,"exclusiveMinimum":true},"title":{"type":"string","minLength":1,"maxLength":500},"description":{"type":"string","maxLength":65536},"baseBranch":{"type":"string","minLength":1,"maxLength":255},"headBranch":{"type":"string","minLength":1,"maxLength":255},"commitSha":{"type":"string","minLength":1,"maxLength":100}},"required":["number","title","commitSha"],"additionalProperties":false}},"required":["targetUrl","pullRequest"],"additionalProperties":false},{"type":"object","properties":{"platform":{"type":"string","enum":["ios","android"]},"pullRequest":{"type":"object","properties":{"provider":{"type":"string","enum":["github"],"default":"github"},"number":{"type":"integer","minimum":0,"exclusiveMinimum":true},"title":{"type":"string","minLength":1,"maxLength":500},"description":{"type":"string","maxLength":65536},"baseBranch":{"type":"string","minLength":1,"maxLength":255},"headBranch":{"type":"string","minLength":1,"maxLength":255},"commitSha":{"type":"string","minLength":1,"maxLength":100}},"required":["number","title","commitSha"],"additionalProperties":false},"mobile":{"type":"object","properties":{"appId":{"type":"string","format":"uuid"},"bundleId":{"type":"string","minLength":1},"artifactUrl":{"type":"string","format":"uri"},"artifactFilename":{"type":"string","minLength":1},"buildId":{"type":"string","minLength":1}},"additionalProperties":false},"simulatorRegion":{"type":"string","enum":["eu-north1","us-west1"]},"deeplink":{"type":"string","maxLength":2048,"format":"uri","description":"Deep link the test harness opens on the device after launching the app and before any test step runs (e.g. an Expo update-channel or backend-selection link). Applied deterministically; the QA agent is told the setup is already done."}},"required":["platform","pullRequest"],"additionalProperties":false}]},"DiscoveryRunResponse":{"type":"object","properties":{"status":{"type":"string","enum":["queued"]},"runId":{"type":"string","format":"uuid"},"projectId":{"type":"string","format":"uuid"},"platform":{"type":"string","enum":["web","ios","android"]}},"required":["status","runId","projectId","platform"]},"DiscoveryRunRequest":{"type":"object","properties":{"goal":{"type":"string","minLength":8,"maxLength":2000,"description":"The exploration goal for the free-roam QA agent, e.g. \"Explore the checkout flow and find bugs\". The agent decides what to test; there is no predefined step list."},"targetUrl":{"type":"string","format":"uri","description":"Optional URL to explore instead of the project's production URL. Web only."},"platform":{"type":"string","enum":["web","ios","android"],"description":"Target platform; defaults to web. Mobile platforms explore the uploaded app."},"appId":{"type":"string","description":"Uploaded mobile app ID to explore. Defaults to the project's latest app for the platform."},"deviceModel":{"type":"string","enum":["iphone","ipad"],"description":"Mobile device variant within the platform (e.g. ipad on iOS). Omit for the default phone-sized device."}},"required":["goal"],"additionalProperties":false},"ProjectEnvironment":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"string","enum":["production","pr_preview","static"]},"url":{"type":"string","nullable":true}},"required":["id","name","slug","kind","url"]},"CredentialSummary":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["login","inbox"]},"authMethod":{"type":"string","enum":["password","google","github","custom"]},"label":{"type":"string"},"description":{"type":"string","nullable":true},"username":{"type":"string"},"hasAuthInstructions":{"type":"boolean"},"hasTotpSecret":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","kind","authMethod","label","description","username","hasAuthInstructions","hasTotpSecret","createdAt"]},"ProjectMemory":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"category":{"type":"string","enum":["site_structure","test_insights","user_preferences"]},"title":{"type":"string"},"content":{"type":"string"},"importance":{"type":"string","enum":["high","medium","low"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","category","title","content","importance","createdAt","updatedAt"]},"ProjectIssue":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"projectId":{"type":"string","format":"uuid"},"testId":{"type":"string","nullable":true,"format":"uuid"},"status":{"type":"string","enum":["open","resolved","false_positive"],"description":"Triage status. Resolved issues reopen automatically if a run surfaces them again."},"issueType":{"type":"string","enum":["issue","warning"]},"source":{"type":"string","enum":["agent_report","step_failure"],"description":"How the tracker learned about the issue: an explicit agent report or a failed test step."},"name":{"type":"string"},"description":{"type":"string"},"url":{"type":"string","nullable":true},"severity":{"type":"integer","nullable":true,"description":"1 (low) to 5 (critical), when reported."},"category":{"type":"string","nullable":true},"reproductionSteps":{"type":"array","nullable":true,"items":{"type":"string"}},"expectedBehavior":{"type":"string","nullable":true},"actualBehavior":{"type":"string","nullable":true},"screenshotUrl":{"type":"string","nullable":true},"environment":{"type":"string","enum":["production","staging","preview","custom"],"description":"Deployment bucket the issue is tracked on."},"environmentName":{"type":"string","description":"Resolved environment label (\"Production\", \"Staging\", \"QA EU\", ...). Issues are tracked per environment: the same bug on different environments is separate issues."},"occurrenceCount":{"type":"integer","description":"Number of runs that surfaced this issue."},"firstSeenRunId":{"type":"string","nullable":true,"format":"uuid"},"lastSeenRunId":{"type":"string","nullable":true,"format":"uuid"},"lastSeenAt":{"type":"string","format":"date-time"},"resolvedAt":{"type":"string","nullable":true,"format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","projectId","testId","status","issueType","source","name","description","url","severity","category","reproductionSteps","expectedBehavior","actualBehavior","screenshotUrl","environment","environmentName","occurrenceCount","firstSeenRunId","lastSeenRunId","lastSeenAt","resolvedAt","createdAt","updatedAt"]},"ProjectIssueOccurrence":{"type":"object","properties":{"runId":{"type":"string","format":"uuid"},"runTitle":{"type":"string","nullable":true},"tMs":{"type":"integer","nullable":true,"description":"Recording offset (ms) when the issue was reported in that run."},"createdAt":{"type":"string","format":"date-time"}},"required":["runId","runTitle","tMs","createdAt"]},"ProjectFileSummary":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"projectId":{"type":"string","nullable":true,"format":"uuid"},"filename":{"type":"string"},"mediaType":{"type":"string"},"fileSize":{"type":"integer"},"description":{"type":"string","nullable":true},"summary":{"type":"string","nullable":true},"createdAt":{"type":"string","nullable":true,"format":"date-time"}},"required":["id","projectId","filename","mediaType","fileSize","description","summary","createdAt"]},"TestDefinition":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"description":{"type":"string","nullable":true},"enabled":{"type":"boolean"},"platform":{"type":"string","enum":["web","mobile"]},"settings":{"$ref":"#/components/schemas/TestSettings"},"steps":{"type":"array","items":{"$ref":"#/components/schemas/TestStep"}},"projectId":{"type":"string","format":"uuid"},"projectUrl":{"type":"string","nullable":true,"format":"uri"},"projectName":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","title","steps"]},"TestSettings":{"type":"object","properties":{"executionMode":{"type":"string","enum":["fast","deep"],"description":"deep uses a higher-effort model for complex steps."},"browserRegion":{"type":"string","nullable":true,"enum":["eu","us",null],"description":"Per-test proxy exit region. null falls back to the project's region."},"simulatorRegion":{"type":"string","enum":["eu-north1","us-west1"],"description":"Region the simulator or emulator runs in. Mobile tests only."},"viewport":{"type":"string","nullable":true,"enum":["desktop","desktop-hd","mobile","tablet",null],"description":"Browser viewport preset: desktop (1280x800), desktop-hd (1920x1080), mobile (390x844), tablet (768x1024). null restores the default. Web tests only."},"webSearchEnabled":{"type":"boolean","description":"Allow the test to use internet search for factual checks."},"prepGroupId":{"type":"string","nullable":true,"format":"uuid","description":"Group whose preparation test a solo run of this test uses."}}},"TestStep":{"oneOf":[{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":2000},"type":{"type":"string","enum":["act"]},"disabled":{"type":"boolean","description":"When true, the step stays saved on the test but is skipped during runs."}},"required":["title","type"]},{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":2000},"type":{"type":"string","enum":["assert"]},"disabled":{"type":"boolean","description":"When true, the step stays saved on the test but is skipped during runs."}},"required":["title","type"]},{"type":"object","properties":{"title":{"type":"string","maxLength":2000},"type":{"type":"string","enum":["login"]},"credentialId":{"type":"string","format":"uuid"},"temporaryEmail":{"type":"boolean"},"disabled":{"type":"boolean","description":"When true, the step stays saved on the test but is skipped during runs."}},"required":["title","type"]},{"type":"object","properties":{"title":{"type":"string","maxLength":2000},"type":{"type":"string","enum":["files"]},"fileIds":{"type":"array","items":{"type":"string","format":"uuid"}},"disabled":{"type":"boolean","description":"When true, the step stays saved on the test but is skipped during runs."}},"required":["title","type","fileIds"]},{"type":"object","properties":{"title":{"type":"string","maxLength":2000},"type":{"type":"string","enum":["screenshot"]},"disabled":{"type":"boolean","description":"When true, the step stays saved on the test but is skipped during runs."}},"required":["type"]},{"type":"object","properties":{"title":{"type":"string","maxLength":2000},"type":{"type":"string","enum":["javascript"]},"code":{"type":"string","maxLength":10000,"description":"JavaScript run in the browser page. Runs as an awaited function body; passes if it completes without throwing (returns nothing or { success: true }) and fails if it returns { success: false, reason } or throws. Web tests only."},"disabled":{"type":"boolean","description":"When true, the step stays saved on the test but is skipped during runs."}},"required":["type","code"]},{"type":"object","properties":{"title":{"type":"string","maxLength":2000},"type":{"type":"string","enum":["microphone"]},"fileId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"string","enum":[""]}],"description":"Project file ID (UUID) of the audio file (e.g. MP3) to play through the microphone. Empty string marks an unconfigured draft that must have a file attached before the test runs."},"mode":{"type":"string","enum":["blocking","loop"],"description":"blocking: the agent waits for playback to finish before continuing. loop: playback repeats until the run ends and the agent continues immediately. Web tests only."},"disabled":{"type":"boolean","description":"When true, the step stays saved on the test but is skipped during runs."}},"required":["type","fileId","mode"]}]},"TestDetail":{"allOf":[{"$ref":"#/components/schemas/TestDefinition"},{"type":"object","properties":{"groups":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"isDefault":{"type":"boolean"}},"required":["id","name","isDefault"]}}}}]},"GroupDetail":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"isDefault":{"type":"boolean"},"runMode":{"type":"string","enum":["concurrent","sequential"]},"prepTestId":{"type":"string","nullable":true,"format":"uuid"},"projectId":{"type":"string","format":"uuid"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","name","isDefault","runMode","prepTestId","projectId"]},"RunListResponse":{"type":"object","properties":{"runs":{"type":"array","items":{"$ref":"#/components/schemas/RunResponse"},"description":"List of runs"},"nextCursor":{"type":"string","nullable":true,"description":"Cursor for fetching the next page"}},"required":["runs"]},"RunResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Unique run identifier"},"type":{"type":"string","enum":["ci","test","discovery"],"description":"Run type"},"status":{"type":"string","enum":["queued","running","completed","failed","cancelled"],"description":"Current run status"},"platform":{"type":"string","nullable":true,"enum":["web","ios","android",null],"description":"Target platform"},"deviceModel":{"type":"string","nullable":true,"enum":["iphone","ipad",null],"description":"Non-default mobile device variant within the run platform (e.g. ipad on iOS). Null means the platform default phone-sized device; explicitly requested defaults are stored as null."},"source":{"type":"string","nullable":true,"enum":["api","github_action","github_app","scheduled","webhook","structured_test",null],"description":"Run source"},"projectId":{"type":"string","nullable":true,"format":"uuid","description":"Linked project ID"},"input":{"type":"object","additionalProperties":{"nullable":true},"description":"Original request input"},"output":{"anyOf":[{"$ref":"#/components/schemas/TestOutput"},{"$ref":"#/components/schemas/PlannerSkippedOutput"},{"nullable":true}],"description":"Run output when completed or skipped"},"testPlan":{"type":"object","nullable":true,"properties":{"instructions":{"type":"string","description":"Natural language instructions for the QA agent"},"focusAreas":{"type":"array","items":{"type":"string"},"description":"Focus areas derived from changed files"},"complexity":{"type":"string","enum":["simple","moderate","complex"],"description":"Estimated test complexity (affects timeout)"},"changeType":{"type":"string","enum":["frontend","backend","mixed","infra"],"description":"Classify this PR: frontend = UI/component changes, backend = API/DB/service changes with no visible UI effect, mixed = both, infra = CI/config/docs only"},"steps":{"type":"array","items":{"oneOf":[{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":500,"description":"Concise description of what to do or verify"},"type":{"type":"string","enum":["act"],"description":"Perform an action"}},"required":["title","type"]},{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":500,"description":"Concise description of what to do or verify"},"type":{"type":"string","enum":["assert"],"description":"Verify a condition"}},"required":["title","type"]},{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":500,"description":"Concise description of the login step"},"type":{"type":"string","enum":["login"],"description":"Authenticate using a credential"},"credentialId":{"type":"string","description":"ID of the credential to use"},"temporaryEmail":{"type":"boolean","description":"Set to true to create a temporary email inbox at run time"}},"required":["title","type"]},{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":500,"description":"Description of what page state to capture"},"type":{"type":"string","enum":["screenshot"],"description":"Capture visual evidence of the current page state"}},"required":["title","type"]}]},"minItems":1,"maxItems":10,"description":"Ordered list of concrete test steps the agent must execute one-by-one"},"executionConfig":{"type":"object","properties":{"viewport":{"type":"object","properties":{"width":{"type":"integer","minimum":320,"maximum":3840},"height":{"type":"integer","minimum":240,"maximum":2160}},"required":["width","height"]}},"description":"Pre-run execution configuration selected by the planner."}},"required":["instructions","focusAreas","complexity","changeType","steps"],"description":"Generated test plan (CI runs only)"},"error":{"type":"object","nullable":true,"properties":{"code":{"type":"string","description":"Stable machine-readable error code"},"message":{"type":"string","description":"Human-readable error message"},"stage":{"type":"string","description":"Run lifecycle stage where the error occurred (e.g. provider_acquisition)"},"retryable":{"type":"boolean","description":"Whether re-running the test could succeed without changes"}},"required":["code","message"],"description":"Error details when failed"},"durationMs":{"type":"number","nullable":true,"description":"Execution time in milliseconds"},"webhookUrl":{"type":"string","nullable":true,"format":"uri","description":"Webhook delivery URL"},"webhookStatus":{"type":"string","nullable":true,"enum":["pending","delivered","failed",null],"description":"Webhook delivery status"},"testId":{"type":"string","nullable":true,"format":"uuid","description":"Linked test ID"},"stepResults":{"type":"array","nullable":true,"items":{"$ref":"#/components/schemas/StepResult"},"description":"Step-level results for structured test runs"},"userName":{"type":"string","nullable":true,"description":"Display name of the user who triggered the run"},"externalRef":{"type":"object","nullable":true,"additionalProperties":{"nullable":true},"description":"External integration metadata (e.g. GitHub PR/deployment IDs)"},"executionMode":{"type":"string","nullable":true,"enum":["fast","deep",null],"description":"Execution mode used for this run"},"autoRetryCount":{"type":"integer","nullable":true,"description":"Number of times the run was automatically retried after a temporary failure. Failed attempts are not counted toward usage."},"createdAt":{"type":"string","format":"date-time","description":"When the run was created"},"startedAt":{"type":"string","nullable":true,"format":"date-time","description":"When execution started"},"completedAt":{"type":"string","nullable":true,"format":"date-time","description":"When execution finished"}},"required":["id","type","status","input","createdAt"]},"TestOutput":{"type":"object","properties":{"featureName":{"type":"string","description":"Name of the feature being tested"},"result":{"type":"string","enum":["PASS","FAILED","BLOCKED"],"description":"Test result - PASS if no issues found, FAILED if any issues were reported, BLOCKED if an environment/setup problem or an agent automation limit prevented a product verdict"},"blockedReason":{"$ref":"#/components/schemas/BlockedReason"},"description":{"type":"string","description":"Short summary of what was tested and the final result; include a compact grouped issue summary only when the user explicitly asks for one"},"issues":{"type":"array","items":{"$ref":"#/components/schemas/Issue"},"default":[],"description":"Issues reported during the session via the report_issue tool"},"screenshots":{"type":"array","items":{"type":"string"},"description":"Array of screenshot URLs captured during testing"},"steps":{"type":"array","items":{"$ref":"#/components/schemas/TestOutputStep"},"description":"Per-step summaries with timing information"},"uiActionIntervals":{"type":"array","items":{"$ref":"#/components/schemas/UiActionInterval"},"description":"Recording-time windows when the agent was visibly acting on screen (clicks, typing, scrolling, navigation); used by replay smart speed"},"recording":{"type":"object","properties":{"storageKey":{"type":"string","description":"Internal storage key of the recording artifact"},"fileName":{"type":"string","description":"Recording file name"},"mediaType":{"type":"string","description":"Recording media type (video/mp4)"}},"required":["storageKey","fileName","mediaType"],"description":"Pointer to the run's video recording artifact, present on completed runs that captured a recording. The bytes are not fetchable through the public API; use the dashboard or a share link to view the recording."}},"required":["featureName","result","description","screenshots"]},"BlockedReason":{"type":"object","properties":{"category":{"type":"string","enum":["environment","seed_data","credentials","test_setup","automation"],"description":"Why the run was blocked: environment outage, missing seed data, or an agent automation limit"},"summary":{"type":"string","description":"Plain-language explanation of what blocked the run"},"errorCodes":{"type":"array","items":{"type":"string","enum":["AUTH_CREDENTIAL_UNAVAILABLE","AUTH_CREDENTIAL_INVALID","AUTH_BASIC_REQUIRED","VERCEL_BYPASS_REQUIRED","ENVIRONMENT_UNAVAILABLE","SEED_DATA_MISSING","MOBILE_RELEASE_BUILD_REQUIRED","VIEWPORT_RESIZE_UNSUPPORTED","STEP_TOOL_LIMIT_EXHAUSTED","STEP_DEADLINE_EXHAUSTED","STEP_NO_CONCLUSION"]},"description":"Step error codes that produced the blocked verdict"}},"required":["category","summary","errorCodes"],"description":"Structured explanation, present only when result is BLOCKED"},"Issue":{"type":"object","properties":{"type":{"type":"string","enum":["issue","warning"],"default":"issue","description":"issue = confirmed bug, warning = non-blocking observation"},"name":{"type":"string","description":"Short name of the issue (e.g. 'Login form rejects valid email')"},"description":{"type":"string","description":"What was tested, what happened, and what was expected"},"url":{"type":"string","minLength":1,"maxLength":2048,"description":"Where the issue happened: the exact page URL on web, or the app identifier and screen on mobile (e.g. com.example.app/login)"},"severity":{"type":"integer","minimum":1,"maximum":5,"description":"Issue severity from 1 (minor) to 5 (critical)"},"reproductionSteps":{"type":"array","items":{"type":"string"},"description":"Short reproduction steps in execution order"},"expectedBehavior":{"type":"string","description":"What should have happened"},"actualBehavior":{"type":"string","description":"What actually happened"},"screenshotUrl":{"type":"string","description":"Screenshot URL showing the issue"},"tMs":{"type":"integer","description":"Milliseconds elapsed since the recording reference time when the issue was reported"},"accessibility":{"$ref":"#/components/schemas/IssueAccessibilityDetail"}},"required":["name","description","url"]},"IssueAccessibilityDetail":{"type":"object","properties":{"ruleId":{"type":"string","description":"axe-core rule id, e.g. image-alt"},"impact":{"type":"string","enum":["minor","moderate","serious","critical"]},"helpUrl":{"type":"string","description":"Deque University fix-guidance URL"},"wcagTags":{"type":"array","items":{"type":"string"},"description":"axe rule tags (wcag2a, wcag21aa, ...)"},"nodeCount":{"type":"integer","minimum":0,"description":"Total failing nodes across pages"},"pageCount":{"type":"integer","minimum":0,"description":"Total distinct pages where the rule failed; `urls` is a bounded sample"},"urls":{"type":"array","items":{"type":"string"},"description":"Pages where the rule failed (bounded sample)"},"sampleTargets":{"type":"array","items":{"type":"string"},"description":"CSS selector paths to example failing elements (bounded sample)"}},"required":["ruleId","impact","helpUrl","wcagTags","nodeCount","urls","sampleTargets"],"description":"Structured detail present on warnings produced by the automated axe-core accessibility audit"},"TestOutputStep":{"type":"object","properties":{"stepIndex":{"type":"integer"},"title":{"type":"string"},"type":{"type":"string","enum":["act","assert","login","files","screenshot","javascript","microphone"]},"status":{"type":"string","enum":["passed","failed"]},"summary":{"type":"string"},"error":{"type":"string","nullable":true},"errorCode":{"type":"string","enum":["AUTH_CREDENTIAL_UNAVAILABLE","AUTH_CREDENTIAL_INVALID","AUTH_BASIC_REQUIRED","VERCEL_BYPASS_REQUIRED","ENVIRONMENT_UNAVAILABLE","SEED_DATA_MISSING","MOBILE_RELEASE_BUILD_REQUIRED","VIEWPORT_RESIZE_UNSUPPORTED","STEP_TOOL_LIMIT_EXHAUSTED","STEP_DEADLINE_EXHAUSTED","STEP_NO_CONCLUSION"]},"startedAtMs":{"type":"integer","description":"Milliseconds elapsed since recording reference when the step started"},"completedAtMs":{"type":"integer","description":"Milliseconds elapsed since recording reference when the step completed"},"reusableActionTrace":{"$ref":"#/components/schemas/ReusableActionTrace"}},"required":["stepIndex","title","status"]},"ReusableActionTrace":{"type":"object","properties":{"version":{"type":"number","enum":[1]},"stepKey":{"type":"string","maxLength":160},"stepTitle":{"type":"string","maxLength":200},"stepType":{"type":"string","enum":["act","assert","login","files","screenshot","javascript","microphone"]},"actions":{"type":"array","items":{"$ref":"#/components/schemas/ReusableActionStep"},"minItems":1,"maxItems":50},"truncated":{"type":"boolean","description":"Actions were dropped at a cap; the trace is guidance-only, never replayable"},"startPath":{"type":"string","maxLength":300,"description":"Pathname where the step began at record time"},"startScreen":{"type":"string","maxLength":120,"description":"Mobile: app under test (bundle id / package name) when the step began"},"startScreenSignature":{"type":"string","maxLength":32,"description":"Mobile: hashed structural signature of the starting screen (shadow data in v1)"},"confidence":{"type":"string","enum":["medium","high"]}},"required":["version","stepKey","stepTitle","actions","confidence"]},"ReusableActionStep":{"type":"object","properties":{"order":{"type":"integer","minimum":0},"toolName":{"type":"string","maxLength":64},"summary":{"type":"string","maxLength":300},"gap":{"type":"boolean","description":"Placeholder for a tool the recorder saw run but did not capture (tool name only, no payload) - e.g. a file upload or a failed state-changing attempt. Gaps keep the trace honest about what actually happened: during cached replay, read-only gaps are skipped and state-changing gaps stop the replay so the agent performs that part live instead of it being silently skipped"},"navigated":{"type":"boolean","description":"The action changed the page URL at record time; replay keeps its full settle pipeline"},"target":{"$ref":"#/components/schemas/ReusableActionTarget"},"source":{"allOf":[{"$ref":"#/components/schemas/ReusableActionTarget"},{"description":"Drag-and-drop source endpoint, when the action has two targets"}]},"input":{"type":"object","properties":{"url":{"type":"string","maxLength":300},"field":{"type":"string","enum":["username","password","totp"]},"option":{"type":"string","maxLength":120},"key":{"type":"string","maxLength":60},"direction":{"type":"string","enum":["up","down","left","right"]},"amount":{"type":"integer"},"deltaX":{"type":"number"},"deltaY":{"type":"number"},"targetPosition":{"type":"string","enum":["center","top","bottom","left","right"]},"focused":{"type":"boolean"},"sequentially":{"type":"boolean"},"text":{"type":"string","maxLength":140},"assertion":{"type":"string","maxLength":300},"role":{"type":"string","maxLength":60},"name":{"type":"string","maxLength":120},"durationMs":{"type":"integer","minimum":0,"exclusiveMinimum":true},"latitude":{"type":"number"},"longitude":{"type":"number"},"state":{"type":"string","enum":["offline","online"]}}}},"required":["order","toolName","summary"]},"ReusableActionTarget":{"type":"object","properties":{"kind":{"type":"string","enum":["role","css","vision","focused","none","mobile"]},"role":{"type":"string","maxLength":60},"name":{"type":"string","maxLength":120},"nth":{"type":"integer","minimum":0},"selector":{"type":"string","maxLength":240},"element":{"type":"string","maxLength":140},"type":{"type":"string","maxLength":80,"description":"Mobile: raw platform element class (XCUIElementTypeButton, android.widget.Button)"},"identifier":{"type":"string","maxLength":120,"description":"Mobile: platform identifier when the app sets one (AXUniqueId / resource-id)"},"label":{"type":"string","maxLength":120,"description":"Mobile: stable accessible label (labels mirroring a typed value are excluded)"},"matchCount":{"type":"integer","minimum":0,"description":"Mobile: same-signature match count at record time; relocation rejects when the live count differs"}},"required":["kind"]},"UiActionInterval":{"type":"object","properties":{"startMs":{"type":"integer","minimum":0,"description":"Milliseconds elapsed since the recording reference time when the action began"},"endMs":{"type":"integer","minimum":0,"description":"Milliseconds elapsed since the recording reference time when the action finished"},"kind":{"type":"string","enum":["click","type","scroll","navigate","other"],"description":"Coarse action category; absent on runs recorded before kinds were tracked"}},"required":["startMs","endMs"]},"PlannerSkippedOutput":{"type":"object","properties":{"kind":{"type":"string","enum":["planner_skipped"]},"reason":{"type":"string","minLength":1,"maxLength":2000}},"required":["kind","reason"]},"StepResult":{"type":"object","properties":{"stepIndex":{"type":"integer","description":"Zero-based index of the saved test step"},"status":{"type":"string","enum":["pending","running","passed","failed","skipped","cancelled"],"description":"Step execution status"},"startedAt":{"type":"string","nullable":true,"description":"ISO timestamp when the step started"},"completedAt":{"type":"string","nullable":true,"description":"ISO timestamp when the step completed"},"error":{"type":"string","nullable":true,"description":"Human-readable step failure description"},"errorCode":{"type":"string","nullable":true,"enum":["AUTH_CREDENTIAL_UNAVAILABLE","AUTH_CREDENTIAL_INVALID","AUTH_BASIC_REQUIRED","VERCEL_BYPASS_REQUIRED","ENVIRONMENT_UNAVAILABLE","SEED_DATA_MISSING","MOBILE_RELEASE_BUILD_REQUIRED","VIEWPORT_RESIZE_UNSUPPORTED","STEP_TOOL_LIMIT_EXHAUSTED","STEP_DEADLINE_EXHAUSTED","STEP_NO_CONCLUSION",null],"description":"Machine-readable step failure code"},"summary":{"type":"string","nullable":true,"description":"Agent summary of what happened"},"retried":{"type":"boolean","description":"Whether the step was retried"},"startedAtMs":{"type":"integer","nullable":true,"description":"Milliseconds elapsed since recording reference when the step started"},"completedAtMs":{"type":"integer","nullable":true,"description":"Milliseconds elapsed since recording reference when the step completed"}},"required":["stepIndex","status","startedAt","completedAt","error","retried"]},"RunMessagesResponse":{"type":"object","properties":{"messages":{"type":"array","items":{"$ref":"#/components/schemas/RunMessage"},"description":"Full agent transcript ordered by creation time"}},"required":["messages"]},"RunMessage":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Message ID"},"role":{"type":"string","enum":["user","assistant"],"description":"Message author"},"parts":{"type":"array","items":{"anyOf":[{"$ref":"#/components/schemas/RunMessageTextPart"},{"$ref":"#/components/schemas/RunMessageToolPart"}]},"description":"Ordered transcript parts: `text`/`reasoning` entries carry what the agent said, `tool` entries carry each tool call with its input and output."},"createdAt":{"type":"string","format":"date-time","description":"When the message was recorded"}},"required":["id","role","parts","createdAt"]},"RunMessageTextPart":{"type":"object","properties":{"type":{"type":"string","enum":["text","reasoning"],"description":"What the agent said or reasoned"},"text":{"type":"string","description":"Agent text"}},"required":["type","text"]},"RunMessageToolPart":{"type":"object","properties":{"type":{"type":"string","enum":["tool"]},"toolName":{"type":"string","description":"Tool the agent called (e.g. ui_navigate, ui_click)"},"status":{"type":"string","enum":["completed","error","pending"],"description":"Tool call outcome; absent on redacted calls"},"summary":{"type":"string","description":"One-line human-readable description of what the tool call did; read these in order to follow the run without parsing raw payloads"},"input":{"nullable":true,"description":"Tool call input"},"output":{"nullable":true,"description":"Tool call output when the call completed"},"errorText":{"type":"string","description":"Failure description when the call errored"},"redacted":{"type":"boolean","description":"True when a credential-bearing tool call was redacted"}},"required":["type","toolName"]},"RunTelemetryResponse":{"type":"object","properties":{"version":{"type":"number","enum":[1],"description":"Telemetry payload schema version"},"console":{"type":"array","items":{"$ref":"#/components/schemas/RunTelemetryConsoleEntry"},"description":"Browser console entries in capture order"},"network":{"type":"array","items":{"$ref":"#/components/schemas/RunTelemetryNetworkEntry"},"description":"Network requests in capture order (document, fetch, and XHR prioritized)"},"counts":{"type":"object","properties":{"console":{"type":"integer","description":"Console entries captured"},"network":{"type":"integer","description":"Network entries captured"},"droppedConsole":{"type":"integer","description":"Console entries dropped after the buffer cap"},"droppedNetwork":{"type":"integer","description":"Network entries dropped after the buffer cap"}},"required":["console","network","droppedConsole","droppedNetwork"],"description":"Capture counts including entries dropped by ring-buffer limits"}},"required":["version","console","network","counts"]},"RunTelemetryConsoleEntry":{"type":"object","properties":{"seq":{"type":"integer","description":"Monotonic sequence number across console and network entries"},"ts":{"type":"string","description":"ISO timestamp of the entry"},"type":{"type":"string","enum":["console_log","console_error"],"description":"Entry kind"},"level":{"type":"string","description":"Console level (log, info, warning, error, debug, ...)"},"text":{"type":"string","description":"Console message text"},"args":{"type":"array","items":{"type":"string"},"description":"Stringified console arguments"},"url":{"type":"string","description":"Page URL when the entry was emitted"},"sourceUrl":{"type":"string","description":"Script URL that emitted the entry"},"line":{"type":"integer"},"column":{"type":"integer"},"stack":{"type":"string","description":"Stack trace for errors"}},"required":["seq","ts","type","level","text"]},"RunTelemetryNetworkEntry":{"type":"object","properties":{"seq":{"type":"integer","description":"Monotonic sequence number across console and network entries"},"ts":{"type":"string","description":"ISO timestamp of the request"},"requestId":{"type":"string","description":"Browser request identifier"},"url":{"type":"string","description":"Request URL (credential query params redacted)"},"method":{"type":"string","description":"HTTP method"},"resourceType":{"type":"string","description":"Browser resource type (document, fetch, xhr, ...)"},"status":{"type":"integer","description":"HTTP response status"},"statusText":{"type":"string"},"mimeType":{"type":"string"},"durationMs":{"type":"number","description":"Request duration in milliseconds"},"requestHeaders":{"type":"object","additionalProperties":{"type":"string"},"description":"Allowlisted request headers"},"responseHeaders":{"type":"object","additionalProperties":{"type":"string"},"description":"Allowlisted response headers"},"requestBody":{"type":"string","description":"JSON request body preview with secrets redacted (fetch/XHR only, truncated)"},"responseBody":{"type":"string","description":"JSON response body preview with secrets redacted (fetch/XHR only, truncated)"},"failure":{"type":"object","properties":{"errorText":{"type":"string"},"canceled":{"type":"boolean"}},"description":"Present when the request failed before receiving a response"}},"required":["seq","ts","requestId","url"]},"BatchStatusResponse":{"type":"object","properties":{"batchId":{"type":"string","format":"uuid","description":"Batch ID"},"status":{"type":"string","enum":["queued","running","completed","failed","cancelled"],"description":"Aggregate batch status: running while any run is in flight, failed when any finished run failed, completed when all finished runs passed, cancelled when every run was cancelled"},"counts":{"type":"object","properties":{"total":{"type":"integer","minimum":0},"queued":{"type":"integer","minimum":0},"running":{"type":"integer","minimum":0},"completed":{"type":"integer","minimum":0},"failed":{"type":"integer","minimum":0},"cancelled":{"type":"integer","minimum":0}},"required":["total","queued","running","completed","failed","cancelled"],"description":"Run counts by status"},"runs":{"type":"array","items":{"$ref":"#/components/schemas/BatchStatusRun"},"description":"Child runs ordered by creation time"}},"required":["batchId","status","counts","runs"]},"BatchStatusRun":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Run ID"},"testId":{"type":"string","nullable":true,"format":"uuid","description":"Saved test the run executed"},"status":{"type":"string","enum":["queued","running","completed","failed","cancelled"],"description":"Run status"},"result":{"type":"string","nullable":true,"enum":["PASS","FAILED","BLOCKED",null],"description":"Test verdict when the run finished with an output. BLOCKED means an environment or setup problem prevented a product verdict"},"errorCode":{"type":"string","nullable":true,"description":"Run error code when execution failed"},"durationMs":{"type":"integer","nullable":true,"description":"Execution time in milliseconds"},"createdAt":{"type":"string","format":"date-time","description":"When the run was created"},"startedAt":{"type":"string","nullable":true,"format":"date-time","description":"When execution started"},"completedAt":{"type":"string","nullable":true,"format":"date-time","description":"When execution finished"}},"required":["id","testId","status","result","errorCode","durationMs","createdAt","startedAt","completedAt"]}},"parameters":{}},"paths":{"/v1/projects":{"get":{"summary":"List projects","description":"List projects available to the authenticated API key's team.","tags":["Projects"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"List of projects","content":{"application/json":{"schema":{"type":"object","properties":{"projects":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"shortId":{"type":"string"},"name":{"type":"string"},"url":{"type":"string","nullable":true,"format":"uri"},"projectType":{"type":"string","enum":["web","mobile"]},"environments":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"string","enum":["production","pr_preview","static"]},"url":{"type":"string","nullable":true}},"required":["id","name","slug","kind","url"]}}},"required":["id","shortId","name","url","projectType"]}}},"required":["projects"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}},"post":{"summary":"Create a project","description":"Create a project for the authenticated API key's team.","tags":["Projects"],"security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"url":{"type":"string","minLength":1,"maxLength":500,"description":"Required for web projects; optional for mobile projects."},"projectType":{"type":"string","enum":["web","mobile"]},"description":{"type":"string","nullable":true,"maxLength":2000}},"required":["name"]}}}},"responses":{"201":{"description":"Project created","content":{"application/json":{"schema":{"type":"object","properties":{"project":{"$ref":"#/components/schemas/ProjectDetail"}},"required":["project"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"403":{"description":"Project limit exceeded for the current plan","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"},"currentCount":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":0}},"required":["error","message","currentCount","limit"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}}},"/v1/projects/{projectId}":{"get":{"summary":"Get a project","description":"Get a single project by ID or shortId.","tags":["Projects"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Project ID or shortId"},"required":true,"description":"Project ID or shortId","name":"projectId","in":"path"}],"responses":{"200":{"description":"Project details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDetail"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"404":{"description":"Not Found - Resource does not exist or is not accessible","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}},"patch":{"summary":"Update a project","description":"Update project name, URL, description, or settings.","tags":["Projects"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Project ID"},"required":true,"description":"Project ID","name":"projectId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"browserRegion":{"type":"string","nullable":true,"enum":["eu","us",null],"description":"Default proxy exit region for web runs. null keeps the provider's default networking. Web projects only."},"prTestingEnabled":{"type":"boolean","description":"Test PR deployments automatically."},"prTestingInstructions":{"type":"string","nullable":true,"maxLength":2000,"description":"Free-form instructions for the PR exploration agent."},"prTestingDebounceMinutes":{"type":"integer","minimum":0,"maximum":60,"description":"Quiet period before a PR deployment is tested. 0 disables debouncing."},"prTestingBlockMerge":{"type":"boolean","description":"Conclude the GitHub check run as failed when tests fail, so a required TesterArmy check blocks the merge. Off by default."},"includeExampleMobileApp":{"type":"boolean","description":"Offer the example app as a run target. Mobile projects only."},"autoDeleteOldestMobileApp":{"type":"boolean","description":"Delete the oldest unused app builds when an upload exceeds the storage quota. Mobile projects only."},"accessibilityAuditEnabled":{"type":"boolean","description":"Scan visited pages with axe-core during web runs and report critical accessibility violations as non-blocking warnings. On by default. Web projects only."},"name":{"type":"string","minLength":1,"maxLength":255},"url":{"type":"string","minLength":1,"maxLength":500},"description":{"type":"string","nullable":true,"maxLength":2000}}}}}},"responses":{"200":{"description":"Project updated","content":{"application/json":{"schema":{"type":"object","properties":{"project":{"$ref":"#/components/schemas/ProjectDetail"}},"required":["project"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}},"delete":{"summary":"Delete a project","description":"Delete a project. Cascades to groups, tests, runs, and associated artifacts.","tags":["Projects"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Project ID"},"required":true,"description":"Project ID","name":"projectId","in":"path"}],"responses":{"200":{"description":"Project deleted","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean","enum":[true]},"id":{"type":"string","format":"uuid"}},"required":["deleted","id"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}}},"/v1/projects/{projectId}/pull-request-runs":{"post":{"summary":"Trigger a dynamic pull request run","description":"Trigger the dynamic PR agent from CI using PR metadata. Callers do not send changed files; TesterArmy enriches with changed files and GitHub reporting only when the project has a supported GitHub connection.","tags":["Projects"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Project ID or shortId"},"required":true,"description":"Project ID or shortId","name":"projectId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DynamicPrRunRequest"}}}},"responses":{"202":{"description":"Dynamic PR run queued successfully","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["queued","skipped"],"description":"\"skipped\" means the PR skip judge decided the changes cannot affect this platform; a cancelled audit run records the decision and no test executes."},"runId":{"type":"string","format":"uuid"},"projectId":{"type":"string","format":"uuid"},"platform":{"type":"string","enum":["web","ios","android"]},"skipReason":{"type":"string","description":"Present only when status is \"skipped\"."},"metadata":{"type":"object","properties":{"github":{"type":"object","properties":{"configured":{"type":"boolean"},"checkRunCreated":{"type":"boolean"},"commentTargetResolved":{"type":"boolean"},"status":{"type":"string","enum":["not_configured","check_create_failed","pr_not_found"]}},"required":["configured","checkRunCreated","commentTargetResolved"]},"mobile":{"type":"object","properties":{"source":{"type":"string"},"buildId":{"type":"string"}},"required":["source"]}}}},"required":["status","runId","projectId","platform"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"404":{"description":"Project not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"413":{"description":"Request body too large","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}}},"/v1/projects/{projectId}/discovery-runs":{"post":{"summary":"Trigger a discovery run","description":"Queue a free-roam discovery run: the QA agent gets only a goal, decides what to test itself, and reports every bug it finds. Supports web, iOS, and Android; mobile platforms explore the uploaded app. FAILED means bugs were found.","tags":["Projects"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Project ID or shortId"},"required":true,"description":"Project ID or shortId","name":"projectId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscoveryRunRequest"}}}},"responses":{"202":{"description":"Discovery run queued successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscoveryRunResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"404":{"description":"Project not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"413":{"description":"Request body too large","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}}},"/v1/projects/{projectId}/environments":{"get":{"summary":"List project environments","description":"List all run environments for a project, including built-in Production and PR Preview plus static environments.","tags":["Projects"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Project ID or shortId"},"required":true,"description":"Project ID or shortId","name":"projectId","in":"path"}],"responses":{"200":{"description":"List of project environments","content":{"application/json":{"schema":{"type":"object","properties":{"environments":{"type":"array","items":{"$ref":"#/components/schemas/ProjectEnvironment"}}},"required":["environments"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"404":{"description":"Project not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}},"post":{"summary":"Create a project environment","description":"Create a static project environment with a stable HTTPS URL. Built-in Production and PR Preview environments are managed by TesterArmy.","tags":["Projects"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Project ID or shortId"},"required":true,"description":"Project ID or shortId","name":"projectId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100},"url":{"type":"string","minLength":1,"maxLength":500}},"required":["name","url"],"additionalProperties":false}}}},"responses":{"201":{"description":"Project environment created","content":{"application/json":{"schema":{"type":"object","properties":{"environment":{"$ref":"#/components/schemas/ProjectEnvironment"}},"required":["environment"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"404":{"description":"Project not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"409":{"description":"Environment name conflicts with an existing environment","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}}},"/v1/projects/{projectId}/environments/{environmentId}":{"delete":{"summary":"Delete a project environment","description":"Delete a static project environment. Built-in Production and PR Preview environments are not deletable.","tags":["Projects"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Project ID or shortId"},"required":true,"description":"Project ID or shortId","name":"projectId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Static environment ID"},"required":true,"description":"Static environment ID","name":"environmentId","in":"path"}],"responses":{"200":{"description":"Project environment deleted","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean","enum":[true]},"id":{"type":"string","format":"uuid"}},"required":["deleted","id"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"404":{"description":"Project or environment not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}}},"/v1/projects/{projectId}/credentials":{"get":{"summary":"List project credentials","description":"List credentials for a project. Passwords are not returned.","tags":["Projects"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Project ID or shortId"},"required":true,"description":"Project ID or shortId","name":"projectId","in":"path"}],"responses":{"200":{"description":"List of credentials","content":{"application/json":{"schema":{"type":"object","properties":{"credentials":{"type":"array","items":{"$ref":"#/components/schemas/CredentialSummary"}}},"required":["credentials"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"404":{"description":"Not Found - Resource does not exist or is not accessible","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}},"post":{"summary":"Create a project credential","description":"Create a login or inbox credential for a project. Passwords are not returned.","tags":["Projects"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Project ID or shortId"},"required":true,"description":"Project ID or shortId","name":"projectId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","enum":["login"]},"authMethod":{"type":"string","enum":["password","google","github"]},"label":{"type":"string","minLength":1,"maxLength":50},"description":{"type":"string","maxLength":500,"description":"When to use this account: its type, enabled features/plans, and the environments it exists in. The agent reads this when choosing between credentials."},"username":{"type":"string","minLength":1,"maxLength":255},"password":{"type":"string","minLength":1},"totpSecret":{"type":"string","minLength":1,"maxLength":512,"description":"Authenticator (TOTP/MFA) secret: the base32 setup key or otpauth:// URI from the account's MFA enrollment. The agent generates one-time codes from it during runs. Never returned; responses expose only hasTotpSecret."}},"required":["kind","label","username","password"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","enum":["login"]},"authMethod":{"type":"string","enum":["custom"]},"label":{"type":"string","minLength":1,"maxLength":50},"description":{"type":"string","maxLength":500,"description":"When to use this account: its type, enabled features/plans, and the environments it exists in. The agent reads this when choosing between credentials."},"authInstructions":{"type":"string","minLength":1,"maxLength":4000}},"required":["kind","authMethod","label","authInstructions"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","enum":["inbox"]},"label":{"type":"string","minLength":1,"maxLength":50},"description":{"type":"string","maxLength":500,"description":"When to use this account: its type, enabled features/plans, and the environments it exists in. The agent reads this when choosing between credentials."}},"required":["kind","label"],"additionalProperties":false}]}}}},"responses":{"201":{"description":"Credential created","content":{"application/json":{"schema":{"type":"object","properties":{"credential":{"$ref":"#/components/schemas/CredentialSummary"}},"required":["credential"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}}},"/v1/projects/{projectId}/memories":{"get":{"summary":"List project memories","description":"List manual project memories used as context for dashboard tests and agents.","tags":["Projects"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Project ID or shortId"},"required":true,"description":"Project ID or shortId","name":"projectId","in":"path"}],"responses":{"200":{"description":"List of project memories","content":{"application/json":{"schema":{"type":"object","properties":{"memories":{"type":"array","items":{"$ref":"#/components/schemas/ProjectMemory"}},"count":{"type":"integer"},"maxMemories":{"type":"integer"}},"required":["memories","count","maxMemories"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"404":{"description":"Project not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}},"post":{"summary":"Create a project memory","description":"Create a manual project memory that agents can use as project context.","tags":["Projects"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Project ID or shortId"},"required":true,"description":"Project ID or shortId","name":"projectId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"category":{"type":"string","enum":["site_structure","test_insights","user_preferences"]},"title":{"type":"string","minLength":1,"maxLength":200},"content":{"type":"string","minLength":1},"importance":{"type":"string","enum":["high","medium","low"]}},"required":["category","title","content","importance"]}}}},"responses":{"201":{"description":"Project memory created","content":{"application/json":{"schema":{"type":"object","properties":{"memory":{"$ref":"#/components/schemas/ProjectMemory"},"pruned":{"type":"integer"}},"required":["memory","pruned"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"404":{"description":"Project not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"409":{"description":"Memory limit reached and no lower-priority memories can be pruned","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}}},"/v1/projects/{projectId}/issues":{"get":{"summary":"List project issues","description":"List a project's tracked issues: bugs and warnings surfaced by QA runs, deduplicated across runs with occurrence counts and triage status. Open issues sort first, then by most recently seen.","tags":["Projects"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Project ID or shortId"},"required":true,"description":"Project ID or shortId","name":"projectId","in":"path"},{"schema":{"type":"string","enum":["open","resolved","false_positive"],"description":"Filter to one triage status."},"required":false,"description":"Filter to one triage status.","name":"status","in":"query"},{"schema":{"type":"string","enum":["production","staging","preview","custom"],"description":"Filter to issues seen on one deployment environment."},"required":false,"description":"Filter to issues seen on one deployment environment.","name":"environment","in":"query"},{"schema":{"type":"string","pattern":"^(?:[1-9]|[1-9][0-9]|100)$","description":"Maximum issues to return (1-100, default 50)."},"required":false,"description":"Maximum issues to return (1-100, default 50).","name":"limit","in":"query"}],"responses":{"200":{"description":"List of project issues","content":{"application/json":{"schema":{"type":"object","properties":{"issues":{"type":"array","items":{"$ref":"#/components/schemas/ProjectIssue"}},"count":{"type":"integer"},"openCount":{"type":"integer","description":"Total open issues in the project."}},"required":["issues","count","openCount"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"404":{"description":"Project not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}}},"/v1/projects/{projectId}/issues/{issueId}":{"get":{"summary":"Get a project issue","description":"Get one tracked issue with its full details and recent run occurrences: which runs surfaced it and when.","tags":["Projects"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Project ID or shortId"},"required":true,"description":"Project ID or shortId","name":"projectId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Issue ID"},"required":true,"description":"Issue ID","name":"issueId","in":"path"}],"responses":{"200":{"description":"Issue detail with recent occurrences","content":{"application/json":{"schema":{"type":"object","properties":{"issue":{"$ref":"#/components/schemas/ProjectIssue"},"occurrences":{"type":"array","items":{"$ref":"#/components/schemas/ProjectIssueOccurrence"}}},"required":["issue","occurrences"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"404":{"description":"Project or issue not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}}},"/v1/projects/{projectId}/memories/{memoryId}":{"delete":{"summary":"Delete a project memory","description":"Delete a manual project memory used as agent context.","tags":["Projects"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Project ID or shortId"},"required":true,"description":"Project ID or shortId","name":"projectId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Memory ID"},"required":true,"description":"Memory ID","name":"memoryId","in":"path"}],"responses":{"200":{"description":"Project memory deleted","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean"},"id":{"type":"string","format":"uuid"}},"required":["deleted","id"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"404":{"description":"Project or memory not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}}},"/v1/projects/{projectId}/files":{"get":{"summary":"List project files","description":"List uploaded files for a project.","tags":["Projects"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Project ID"},"required":true,"description":"Project ID","name":"projectId","in":"path"}],"responses":{"200":{"description":"List of files","content":{"application/json":{"schema":{"type":"object","properties":{"files":{"type":"array","items":{"$ref":"#/components/schemas/ProjectFileSummary"}}},"required":["files"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"404":{"description":"Not Found - Resource does not exist or is not accessible","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}},"post":{"summary":"Initiate a project file upload","description":"Validate a project file and create a presigned direct-upload URL. Mobile projects only accept photos and videos (.png, .jpg, .jpeg, .mp4, .mov); runs preload them into the device photo library.","tags":["Projects"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Project ID or shortId"},"required":true,"description":"Project ID or shortId","name":"projectId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"filename":{"type":"string","minLength":1},"fileSize":{"type":"integer","minimum":0,"exclusiveMinimum":true,"maximum":52428800},"mediaType":{"type":"string"}},"required":["filename","fileSize"]}}}},"responses":{"200":{"description":"Presigned project-file upload details","content":{"application/json":{"schema":{"type":"object","properties":{"uploadUrl":{"type":"string","format":"uri"},"storageKey":{"type":"string"},"mimeType":{"type":"string"},"filename":{"type":"string"},"fileSize":{"type":"integer"},"mediaType":{"type":"string"}},"required":["uploadUrl","storageKey","mimeType","filename","fileSize","mediaType"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"404":{"description":"Not Found - Resource does not exist or is not accessible","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}},"put":{"summary":"Confirm a project file upload","description":"Verify uploaded bytes and register the file on the project.","tags":["Projects"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Project ID or shortId"},"required":true,"description":"Project ID or shortId","name":"projectId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"storageKey":{"type":"string","minLength":1},"fileSize":{"type":"integer","minimum":0,"exclusiveMinimum":true,"maximum":52428800},"description":{"type":"string","nullable":true}},"required":["storageKey","fileSize"]}}}},"responses":{"201":{"description":"Project file uploaded successfully","content":{"application/json":{"schema":{"type":"object","properties":{"files":{"type":"array","items":{"$ref":"#/components/schemas/ProjectFileSummary"}}},"required":["files"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"404":{"description":"Not Found - Resource does not exist or is not accessible","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}}},"/v1/projects/{projectId}/mobile":{"get":{"summary":"List project mobile apps","description":"List uploaded mobile apps for a mobile project.","tags":["Projects"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Project ID"},"required":true,"description":"Project ID","name":"projectId","in":"path"}],"responses":{"200":{"description":"List of project mobile apps","content":{"application/json":{"schema":{"type":"object","properties":{"apps":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"platform":{"type":"string","enum":["ios","android"]},"filename":{"type":"string"},"bundleId":{"type":"string","nullable":true},"appVersion":{"type":"string","nullable":true},"buildVersion":{"type":"string","nullable":true},"fileSize":{"type":"number"},"source":{"type":"string","enum":["manual_upload","group_webhook_artifact","api_upload"]},"expiresAt":{"type":"string","nullable":true,"format":"date-time"},"removeAfter":{"type":"integer","nullable":true},"createdAt":{"type":"string","format":"date-time"}},"required":["id","platform","filename","bundleId","appVersion","buildVersion","fileSize","source","expiresAt","removeAfter","createdAt"]}}},"required":["apps"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"404":{"description":"Project not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}},"post":{"summary":"Upload a project mobile app","description":"Upload a mobile app binary to a mobile project. Optionally set removeAfter to delete temporary uploads after a delay.","tags":["Projects"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Project ID"},"required":true,"description":"Project ID","name":"projectId","in":"path"}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"},"removeAfter":{"type":"string","description":"Optional expiration in seconds for temporary uploads, from 60 to 604800. Temporary uploads have a 20 GB storage cap per project."}},"required":["file"]}}}},"responses":{"201":{"description":"Mobile app uploaded successfully","content":{"application/json":{"schema":{"type":"object","properties":{"app":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"platform":{"type":"string","enum":["ios","android"]},"filename":{"type":"string"},"bundleId":{"type":"string","nullable":true},"appVersion":{"type":"string","nullable":true},"buildVersion":{"type":"string","nullable":true},"fileSize":{"type":"number"},"source":{"type":"string","enum":["manual_upload","group_webhook_artifact","api_upload"]},"expiresAt":{"type":"string","nullable":true,"format":"date-time"},"removeAfter":{"type":"integer","nullable":true},"createdAt":{"type":"string","format":"date-time"}},"required":["id","platform","filename","bundleId","appVersion","buildVersion","fileSize","source","expiresAt","removeAfter","createdAt"]}},"required":["app"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"404":{"description":"Project not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}}},"/v1/projects/{projectId}/mobile/{appId}":{"delete":{"summary":"Delete a project mobile app","description":"Delete a previously uploaded mobile app from a mobile project.","tags":["Projects"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Project ID"},"required":true,"description":"Project ID","name":"projectId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Mobile app ID"},"required":true,"description":"Mobile app ID","name":"appId","in":"path"}],"responses":{"200":{"description":"Mobile app deleted","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean","enum":[true]}},"required":["deleted"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"404":{"description":"Project or mobile app not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}}},"/v1/projects/{projectId}/mobile/upload":{"post":{"summary":"Initiate a project mobile app upload","description":"Create a presigned temporary upload for a mobile app binary.","tags":["Projects"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Project ID"},"required":true,"description":"Project ID","name":"projectId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"filename":{"type":"string","minLength":1},"fileSize":{"type":"integer","minimum":0,"exclusiveMinimum":true},"removeAfter":{"type":"integer","minimum":60,"maximum":604800}},"required":["filename","fileSize"]}}}},"responses":{"200":{"description":"Presigned upload details","content":{"application/json":{"schema":{"type":"object","properties":{"uploadUrl":{"type":"string","format":"uri"},"storageKey":{"type":"string"},"filename":{"type":"string"},"fileSize":{"type":"integer"},"removeAfter":{"type":"integer","nullable":true}},"required":["uploadUrl","storageKey","filename","fileSize","removeAfter"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}}},"/v1/projects/{projectId}/mobile/upload/confirm":{"post":{"summary":"Confirm a project mobile app upload","description":"Validate a completed temporary upload and promote it into project storage.","tags":["Projects"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Project ID"},"required":true,"description":"Project ID","name":"projectId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"storageKey":{"type":"string","minLength":1},"filename":{"type":"string","minLength":1},"fileSize":{"type":"integer","minimum":0,"exclusiveMinimum":true},"removeAfter":{"type":"integer","minimum":60,"maximum":604800}},"required":["storageKey","filename","fileSize"]}}}},"responses":{"201":{"description":"Mobile app uploaded successfully","content":{"application/json":{"schema":{"type":"object","properties":{"app":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"platform":{"type":"string","enum":["ios","android"]},"filename":{"type":"string"},"bundleId":{"type":"string","nullable":true},"appVersion":{"type":"string","nullable":true},"buildVersion":{"type":"string","nullable":true},"fileSize":{"type":"number"},"source":{"type":"string","enum":["manual_upload","group_webhook_artifact","api_upload"]},"expiresAt":{"type":"string","nullable":true,"format":"date-time"},"removeAfter":{"type":"integer","nullable":true},"createdAt":{"type":"string","format":"date-time"}},"required":["id","platform","filename","bundleId","appVersion","buildVersion","fileSize","source","expiresAt","removeAfter","createdAt"]}},"required":["app"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}}},"/v1/tests":{"get":{"summary":"List tests","description":"List tests for a project, optionally scoped to a test group. Use `cursor` for pagination; the response includes `nextCursor` when more pages exist.","tags":["Tests"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Project ID"},"required":true,"description":"Project ID","name":"projectId","in":"query"},{"schema":{"type":"string","format":"uuid","description":"Optional test group ID"},"required":false,"description":"Optional test group ID","name":"groupId","in":"query"},{"schema":{"type":"string","pattern":"^(?:[1-9]|[1-9][0-9]|100)$","description":"Max results per page (default 50, max 100)"},"required":false,"description":"Max results per page (default 50, max 100)","name":"limit","in":"query"},{"schema":{"type":"string","description":"Cursor for pagination"},"required":false,"description":"Cursor for pagination","name":"cursor","in":"query"}],"responses":{"200":{"description":"List of tests","content":{"application/json":{"schema":{"type":"object","properties":{"projectUrl":{"type":"string","nullable":true,"format":"uri"},"projectName":{"type":"string"},"tests":{"type":"array","items":{"$ref":"#/components/schemas/TestDefinition"}},"nextCursor":{"type":"string","nullable":true}},"required":["projectUrl","projectName","tests","nextCursor"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"404":{"description":"Not Found - Resource does not exist or is not accessible","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}},"post":{"summary":"Create a test","description":"Create a structured test definition for a project.","tags":["Tests"],"security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":500},"description":{"type":"string"},"steps":{"type":"array","items":{"$ref":"#/components/schemas/TestStep"},"minItems":1,"maxItems":30},"projectId":{"type":"string"},"groupId":{"type":"string","nullable":true,"format":"uuid"},"platform":{"type":"string","enum":["web","mobile"]},"settings":{"$ref":"#/components/schemas/TestSettings"},"enabled":{"type":"boolean"}},"required":["title","steps","projectId"]}}}},"responses":{"201":{"description":"Test created","content":{"application/json":{"schema":{"type":"object","properties":{"test":{"$ref":"#/components/schemas/TestDefinition"}},"required":["test"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"404":{"description":"Not Found - Resource does not exist or is not accessible","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}}},"/v1/tests/{testId}":{"get":{"summary":"Get a test","description":"Get a single structured test definition, including the groups it belongs to.","tags":["Tests"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Test ID"},"required":true,"description":"Test ID","name":"testId","in":"path"}],"responses":{"200":{"description":"Test details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestDetail"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"404":{"description":"Not Found - Resource does not exist or is not accessible","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}},"patch":{"summary":"Update a test","description":"Update a structured test definition. `settings` is merged field by field; every other field replaces its stored value.","tags":["Tests"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Test ID"},"required":true,"description":"Test ID","name":"testId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":500},"description":{"type":"string"},"steps":{"type":"array","items":{"$ref":"#/components/schemas/TestStep"},"minItems":1,"maxItems":30},"settings":{"allOf":[{"$ref":"#/components/schemas/TestSettings"},{"description":"Settings patch; omitted fields keep their stored value."}]},"enabled":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Test updated","content":{"application/json":{"schema":{"type":"object","properties":{"test":{"$ref":"#/components/schemas/TestDefinition"}},"required":["test"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}},"delete":{"summary":"Delete a test","description":"Delete a structured test definition.","tags":["Tests"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Test ID"},"required":true,"description":"Test ID","name":"testId","in":"path"}],"responses":{"200":{"description":"Test deleted","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean","enum":[true]},"id":{"type":"string","format":"uuid"}},"required":["deleted","id"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}}},"/v1/tests/{testId}/runs":{"post":{"summary":"Trigger a test run","description":"Trigger a saved dashboard test remotely using API-key authentication. Returns the queued run ID.","tags":["Tests"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Test ID"},"required":true,"description":"Test ID","name":"testId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","enum":["fast","deep"]},"platform":{"type":"string","enum":["web","ios","android"],"description":"Run platform for the test. Mobile tests default to ios when omitted, so Android runs must set platform: android - including when the mobile app is selected by appId."},"deviceModel":{"type":"string","enum":["iphone","ipad"],"description":"Mobile device variant within the run platform (iOS: iphone | ipad). Omit for the platform default phone-sized device; explicitly requesting the default (e.g. iphone) is equivalent to omitting it."},"appId":{"type":"string","format":"uuid"},"projectEnvironmentId":{"type":"string","format":"uuid"}}}}}},"responses":{"202":{"description":"Test run queued successfully","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["queued"]},"runId":{"type":"string","format":"uuid"},"testId":{"type":"string","format":"uuid"}},"required":["status","runId","testId"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}}},"/v1/groups":{"get":{"summary":"List test groups","description":"List test groups for a project. The default All Tests group is always returned and new tests are added to it at creation time.","tags":["Groups"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Project ID"},"required":true,"description":"Project ID","name":"projectId","in":"query"}],"responses":{"200":{"description":"List of test groups","content":{"application/json":{"schema":{"type":"object","properties":{"groups":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"isDefault":{"type":"boolean"},"testCount":{"type":"integer"},"prepTestId":{"type":"string","nullable":true,"format":"uuid"}},"required":["id","name","isDefault","testCount","prepTestId"]}}},"required":["groups"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"404":{"description":"Not Found - Resource does not exist or is not accessible","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}},"post":{"summary":"Create a test group","description":"Create a test group in a project. Capped at 100 groups per project.","tags":["Groups"],"security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"projectId":{"type":"string","description":"Project ID"},"name":{"type":"string","minLength":1,"maxLength":255},"runMode":{"type":"string","enum":["concurrent","sequential"]},"prepTestId":{"type":"string","nullable":true,"format":"uuid","description":"Web test that runs first and saves its browser session. Any web test in the project qualifies; it does not have to be a member of this group."}},"required":["projectId","name"]}}}},"responses":{"201":{"description":"Group created","content":{"application/json":{"schema":{"type":"object","properties":{"group":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"isDefault":{"type":"boolean"},"runMode":{"type":"string","enum":["concurrent","sequential"]},"prepTestId":{"type":"string","nullable":true,"format":"uuid"},"projectId":{"type":"string","format":"uuid"}},"required":["id","name","isDefault","runMode","prepTestId","projectId"]}},"required":["group"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"404":{"description":"Not Found - Resource does not exist or is not accessible","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}}},"/v1/groups/{groupId}":{"get":{"summary":"Get a test group","description":"Get a single test group by ID.","tags":["Groups"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Test group ID"},"required":true,"description":"Test group ID","name":"groupId","in":"path"}],"responses":{"200":{"description":"Group details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroupDetail"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"404":{"description":"Not Found - Resource does not exist or is not accessible","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}},"patch":{"summary":"Update a test group","description":"Update name, runMode, or prepTestId on a test group.","tags":["Groups"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Test group ID"},"required":true,"description":"Test group ID","name":"groupId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"runMode":{"type":"string","enum":["concurrent","sequential"]},"prepTestId":{"type":"string","nullable":true,"format":"uuid","description":"Web test that runs first and saves its browser session. Any web test in the project qualifies; it does not have to be a member of this group. Pass null to clear."}}}}}},"responses":{"200":{"description":"Group updated","content":{"application/json":{"schema":{"type":"object","properties":{"group":{"$ref":"#/components/schemas/GroupDetail"}},"required":["group"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}},"delete":{"summary":"Delete a test group","description":"Delete a non-default test group. The default group cannot be deleted.","tags":["Groups"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Test group ID"},"required":true,"description":"Test group ID","name":"groupId","in":"path"}],"responses":{"200":{"description":"Group deleted","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean","enum":[true]},"id":{"type":"string","format":"uuid"}},"required":["deleted","id"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}}},"/v1/groups/{groupId}/tests":{"post":{"summary":"Add a test to a group","description":"Add an existing test to a test group. Returns 201 when a new membership row was created, or 200 with `added: false` when the test was already a member (idempotent).","tags":["Groups"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Test group ID"},"required":true,"description":"Test group ID","name":"groupId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"testId":{"type":"string","format":"uuid"}},"required":["testId"]}}}},"responses":{"200":{"description":"Test was already a member; no change","content":{"application/json":{"schema":{"type":"object","properties":{"groupId":{"type":"string","format":"uuid"},"testId":{"type":"string","format":"uuid"},"added":{"type":"boolean","enum":[false]}},"required":["groupId","testId","added"]}}}},"201":{"description":"Test added to group","content":{"application/json":{"schema":{"type":"object","properties":{"groupId":{"type":"string","format":"uuid"},"testId":{"type":"string","format":"uuid"},"added":{"type":"boolean","enum":[true]}},"required":["groupId","testId","added"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"404":{"description":"Not Found - Resource does not exist or is not accessible","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}}},"/v1/groups/{groupId}/tests/{testId}":{"delete":{"summary":"Remove a test from a group","description":"Remove a test from a test group. The group's prepTestId is left alone, because a preparation test does not have to be a member of the group it prepares. `removed` is `true` when a membership row was deleted, `false` when the test was not a member (idempotent).","tags":["Groups"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Test group ID"},"required":true,"description":"Test group ID","name":"groupId","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Test ID"},"required":true,"description":"Test ID","name":"testId","in":"path"}],"responses":{"200":{"description":"Idempotent removal result","content":{"application/json":{"schema":{"type":"object","properties":{"groupId":{"type":"string","format":"uuid"},"testId":{"type":"string","format":"uuid"},"removed":{"type":"boolean"}},"required":["groupId","testId","removed"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}}},"/v1/groups/{groupId}/runs":{"post":{"summary":"Trigger a test group run","description":"Trigger all runnable tests in a group using API-key authentication. Returns the batch ID plus `queuedRunIds` (runs accepted onto the worker) and `cancelledRunIds` (runs the server immediately cancelled, e.g. duplicates or quota cancellations). `status` is `queued` when at least one run is queued and `cancelled` when every run was rejected.","tags":["Groups"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Test group ID"},"required":true,"description":"Test group ID","name":"groupId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"platform":{"type":"string","enum":["web","ios","android"],"description":"Run platform for the batch. Mobile tests default to ios when omitted, so Android runs must set platform: android - including when the mobile app is selected by appId or bundleId."},"deviceModel":{"type":"string","enum":["iphone","ipad"],"description":"Mobile device variant within the run platform (iOS: iphone | ipad). Omit for the platform default phone-sized device; explicitly requesting the default (e.g. iphone) is equivalent to omitting it."},"projectEnvironmentId":{"type":"string","format":"uuid"},"targetUrl":{"type":"string","format":"uri"},"environment":{"type":"string","enum":["production","staging","preview","custom"]},"mobile":{"type":"object","properties":{"appId":{"type":"string","format":"uuid"},"bundleId":{"type":"string","minLength":1},"artifactUrl":{"type":"string","format":"uri"},"artifactFilename":{"type":"string","minLength":1},"buildId":{"type":"string","minLength":1}},"additionalProperties":false},"commitSha":{"type":"string","minLength":1},"prNumber":{"type":"integer","minimum":0,"exclusiveMinimum":true}}}}}},"responses":{"202":{"description":"Group run queued successfully","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["queued","cancelled"]},"groupId":{"type":"string","format":"uuid"},"batchId":{"type":"string","format":"uuid"},"runIds":{"type":"array","items":{"type":"string","format":"uuid"}},"queuedRunIds":{"type":"array","items":{"type":"string","format":"uuid"}},"cancelledRunIds":{"type":"array","items":{"type":"string","format":"uuid"}},"count":{"type":"integer"},"metadata":{"type":"object","properties":{"github":{"type":"object","properties":{"configured":{"type":"boolean"},"checkRunCreated":{"type":"boolean"},"commentTargetResolved":{"type":"boolean"},"status":{"type":"string","enum":["not_configured","check_create_failed","pr_not_found"]}},"required":["configured","checkRunCreated","commentTargetResolved"]}},"required":["github"]}},"required":["status","groupId","batchId","runIds","queuedRunIds","cancelledRunIds","count"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"404":{"description":"Group not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}}},"/v1/webhook/{webhookId}/{secret}":{"post":{"summary":"Trigger a project webhook","description":"Receive a deployment webhook and trigger PR testing when configured.","tags":["Webhooks"],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Webhook ID"},"required":true,"description":"Webhook ID","name":"webhookId","in":"path"},{"schema":{"type":"string","description":"Webhook secret"},"required":true,"description":"Webhook secret","name":"secret","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"nullable":true}}}}},"responses":{"200":{"description":"Webhook accepted","content":{"application/json":{"schema":{"type":"object","properties":{"received":{"type":"boolean"},"ignored":{"type":"boolean"},"reason":{"type":"string"},"runId":{"type":"string","format":"uuid"},"batchId":{"type":"string","format":"uuid","deprecated":true,"description":"First created batch only. Use batchIds, which covers every PR test group."},"batchIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"One batch per selected PR test group started by this delivery."}},"required":["received"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}}},"/v1/groups/webhook/{webhookId}/{secret}":{"post":{"summary":"Trigger a group webhook","description":"Trigger all runnable tests in a group from a signed webhook URL.","tags":["Webhooks"],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Webhook ID"},"required":true,"description":"Webhook ID","name":"webhookId","in":"path"},{"schema":{"type":"string","description":"Webhook secret"},"required":true,"description":"Webhook secret","name":"secret","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"platform":{"type":"string","enum":["web","ios","android"],"description":"Run platform for the batch. Mobile tests default to ios when omitted, so Android runs must set platform: android - including when the mobile app is selected by appId or bundleId."},"deviceModel":{"type":"string","enum":["iphone","ipad"],"description":"Mobile device variant within the run platform (iOS: iphone | ipad). Omit for the platform default phone-sized device; explicitly requesting the default (e.g. iphone) is equivalent to omitting it."},"projectEnvironmentId":{"type":"string","format":"uuid"},"targetUrl":{"type":"string","format":"uri"},"environment":{"type":"string","enum":["production","staging","preview","custom"]},"mobile":{"type":"object","properties":{"appId":{"type":"string","format":"uuid"},"bundleId":{"type":"string","minLength":1},"artifactUrl":{"type":"string","format":"uri"},"artifactFilename":{"type":"string","minLength":1},"buildId":{"type":"string","minLength":1}},"additionalProperties":false},"commitSha":{"type":"string"}}}}}},"responses":{"202":{"description":"Webhook accepted","content":{"application/json":{"schema":{"type":"object","properties":{"received":{"type":"boolean"},"ignored":{"type":"boolean"},"reason":{"type":"string"},"runId":{"type":"string","format":"uuid"},"batchId":{"type":"string","format":"uuid","deprecated":true,"description":"First created batch only. Use batchIds, which covers every PR test group."},"batchIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"One batch per selected PR test group started by this delivery."}},"required":["received"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}}},"/v1/runs":{"get":{"summary":"List test runs","description":"List test runs for the authenticated team with optional project/status filtering and cursor pagination.","tags":["Test Runs"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","pattern":"^(?:[1-9]|[1-9][0-9]|100)$","description":"Max results per page (default 20, max 100)"},"required":false,"description":"Max results per page (default 20, max 100)","name":"limit","in":"query"},{"schema":{"type":"string","enum":["queued","running","completed","failed","cancelled"],"description":"Filter by status"},"required":false,"description":"Filter by status","name":"status","in":"query"},{"schema":{"type":"string","format":"uuid","description":"Filter by project ID"},"required":false,"description":"Filter by project ID","name":"projectId","in":"query"},{"schema":{"type":"string","format":"uuid","description":"Filter by test ID"},"required":false,"description":"Filter by test ID","name":"testId","in":"query"},{"schema":{"type":"string","format":"uuid","description":"Filter by group-run batch ID"},"required":false,"description":"Filter by group-run batch ID","name":"batchId","in":"query"},{"schema":{"type":"string","description":"Cursor for pagination"},"required":false,"description":"Cursor for pagination","name":"cursor","in":"query"}],"responses":{"200":{"description":"List of runs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunListResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}}},"/v1/runs/{id}":{"get":{"summary":"Get test run status","description":"Retrieve the current status and result of a test run. Poll this endpoint to check for completion.","tags":["Test Runs"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Test run ID"},"required":true,"description":"Test run ID","name":"id","in":"path"}],"responses":{"200":{"description":"Run details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"404":{"description":"Run not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}}},"/v1/runs/{id}/messages":{"get":{"summary":"Get run agent transcript","description":"Retrieve the full agent transcript for a run: assistant reasoning, tool calls, and tool outputs in execution order. Use this to understand exactly what the agent did and why a step failed. Credential-bearing tool parts are redacted.","tags":["Test Runs"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Test run ID"},"required":true,"description":"Test run ID","name":"id","in":"path"}],"responses":{"200":{"description":"Agent transcript","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunMessagesResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"404":{"description":"Run not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}}},"/v1/runs/{id}/telemetry":{"get":{"summary":"Get run console and network logs","description":"Retrieve browser console logs and network requests captured during a web run. Use this to debug failures: console errors, failed requests, and 4xx/5xx responses with redacted header and JSON body previews. Telemetry is captured for web runs only and becomes available after the run finishes; mobile runs return 404.","tags":["Test Runs"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Test run ID"},"required":true,"description":"Test run ID","name":"id","in":"path"}],"responses":{"200":{"description":"Console and network telemetry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunTelemetryResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"404":{"description":"Run not found or no telemetry captured for this run","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}}},"/v1/runs/{id}/recording":{"get":{"summary":"Get run screen recording","description":"Stream the screen recording (MP4) captured during a run. Supports HTTP Range requests for seeking and partial downloads. Recordings become available after the run finishes; cancelled runs and runs without a recording return 404.","tags":["Test Runs"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Test run ID"},"required":true,"description":"Test run ID","name":"id","in":"path"}],"responses":{"200":{"description":"Screen recording video stream","content":{"video/mp4":{"schema":{"type":"string","format":"binary"}}}},"206":{"description":"Partial video content for a Range request","content":{"video/mp4":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"404":{"description":"Run not found or no recording available for this run","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"416":{"description":"Requested range not satisfiable"},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}}},"/v1/runs/{id}/recording/download-url":{"get":{"summary":"Get a run recording download URL","description":"Get a short-lived signed URL that downloads the run's screen recording (MP4), plus its file name and size. Use this instead of the streaming endpoint when the client should hand the link off rather than hold the bytes. Recordings become available after the run finishes; cancelled runs and runs without a recording return 404.","tags":["Test Runs"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Test run ID"},"required":true,"description":"Test run ID","name":"id","in":"path"}],"responses":{"200":{"description":"Signed recording download URL","content":{"application/json":{"schema":{"type":"object","properties":{"runId":{"type":"string","format":"uuid"},"fileName":{"type":"string"},"mediaType":{"type":"string"},"sizeBytes":{"type":"number","nullable":true,"description":"Recording size in bytes, when R2 reports it"},"downloadUrl":{"type":"string","format":"uri"},"expiresIn":{"type":"number","description":"Lifetime of the URL in seconds"},"expiresAt":{"type":"string","format":"date-time"}},"required":["runId","fileName","mediaType","sizeBytes","downloadUrl","expiresIn","expiresAt"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"404":{"description":"Run not found or no recording available for this run","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}}},"/v1/runs/{id}/cancel":{"post":{"summary":"Cancel a queued or running run","description":"Cancel a queued or running test run.","tags":["Test Runs"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Test run ID"},"required":true,"description":"Test run ID","name":"id","in":"path"}],"responses":{"200":{"description":"Run cancelled","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["cancelled"]}},"required":["id","status"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"409":{"description":"Conflict - Run is already terminal or cannot be cancelled","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}}},"/v1/batches/{batchId}":{"get":{"summary":"Get batch status","description":"Retrieve the aggregate status of a group-run batch with per-run verdicts. Poll this endpoint to track batch completion, then fetch individual runs (or `GET /v1/runs?batchId=...`) for details.","tags":["Test Runs"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Batch ID"},"required":true,"description":"Batch ID","name":"batchId","in":"path"}],"responses":{"200":{"description":"Batch status summary","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchStatusResponse"}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"404":{"description":"Batch not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}}},"/v1/batches/{batchId}/cancel":{"post":{"summary":"Cancel a queued or running batch","description":"Cancel all queued or running runs in a prior group-run batch. Finished runs are left unchanged, making the endpoint idempotent when the batch has already completed.","tags":["Test Runs"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Batch ID"},"required":true,"description":"Batch ID","name":"batchId","in":"path"}],"responses":{"200":{"description":"Batch cancellation summary","content":{"application/json":{"schema":{"type":"object","properties":{"batchId":{"type":"string","format":"uuid"},"cancelled":{"type":"integer","minimum":0},"alreadyFinished":{"type":"integer","minimum":0},"cancelledRunIds":{"type":"array","items":{"type":"string","format":"uuid"}},"alreadyFinishedRunIds":{"type":"array","items":{"type":"string","format":"uuid"}}},"required":["batchId","cancelled","alreadyFinished","cancelledRunIds","alreadyFinishedRunIds"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"404":{"description":"Batch not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"409":{"description":"Conflict - Some runs could not be cancelled","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"},"batchId":{"type":"string","format":"uuid"},"cancelled":{"type":"integer","minimum":0},"alreadyFinished":{"type":"integer","minimum":0},"cancelledRunIds":{"type":"array","items":{"type":"string","format":"uuid"}},"alreadyFinishedRunIds":{"type":"array","items":{"type":"string","format":"uuid"}},"failedRunIds":{"type":"array","items":{"type":"string","format":"uuid"}}},"required":["error","message","batchId","cancelled","alreadyFinished","cancelledRunIds","alreadyFinishedRunIds","failedRunIds"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}}},"/v1/batches/{batchId}/rerun":{"post":{"summary":"Re-run a batch","description":"Create a new group-run batch from the runnable tests in a prior batch. Deleted, disabled, or malformed tests are skipped and returned as `skippedTestIds`.","tags":["Test Runs"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Source batch ID"},"required":true,"description":"Source batch ID","name":"batchId","in":"path"}],"responses":{"202":{"description":"Batch re-run queued successfully","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["queued","cancelled"]},"groupId":{"type":"string","format":"uuid"},"batchId":{"type":"string","format":"uuid"},"sourceBatchId":{"type":"string","format":"uuid"},"runIds":{"type":"array","items":{"type":"string","format":"uuid"}},"queuedRunIds":{"type":"array","items":{"type":"string","format":"uuid"}},"cancelledRunIds":{"type":"array","items":{"type":"string","format":"uuid"}},"skippedTestIds":{"type":"array","items":{"type":"string","format":"uuid"}},"count":{"type":"integer"}},"required":["status","groupId","batchId","sourceBatchId","runIds","queuedRunIds","cancelledRunIds","skippedTestIds","count"]}}}},"400":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"401":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"404":{"description":"Batch not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"409":{"description":"Conflict - Batch cannot be re-run","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"429":{"description":"Too Many Requests - Usage limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}},"504":{"description":"Gateway Timeout - Test execution exceeded time limit","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error code or type"},"message":{"type":"string","description":"Human-readable error message"}},"required":["error","message"]}}}}}}}}}