Welcome to the bugAgent API
The bugAgent REST API gives you full programmatic access to bug reports, feature requests, enhancements, projects, API keys, user profiles, and more. Everything available in the dashboard and MCP tools is accessible via the API.
Introduction
The bugAgent API is organized around REST. It accepts JSON-encoded request bodies, returns JSON responses, and uses standard HTTP methods and status codes.
All API requests must include a Content-Type: application/json header for requests with a body. Responses always return Content-Type: application/json.
Secure
All requests over HTTPS. API keys are SHA-256 hashed at rest.
Fast
Sub-100ms responses for most endpoints. Built on edge infrastructure.
Agent-Friendly
Designed for both human and AI agent consumption. Consistent JSON schemas.
Base URL
All API endpoints are relative to the base URL:
https://app.bugagent.com/api For example, to list bug reports:
GET https://app.bugagent.com/api/reports Authentication
The API supports two authentication methods:
API Key (recommended)
Generate an API key from the dashboard settings or via the POST /api/keys endpoint. Include it as a Bearer token:
curl https://app.bugagent.com/api/reports \
-H "Authorization: Bearer ba_live_your_key_here" Session Cookie
If you're authenticated via the dashboard (browser session), API requests from the same origin automatically use your session cookie. This is used by the dashboard frontend.
Connect via MCP
Instead of calling the REST API directly, you can connect to bugAgent through the Model Context Protocol (MCP) server at https://mcp.bugagent.com/mcp. The MCP server exposes 60+ tools (bug reports, projects, automations, explorations, security scans, etc.) to any MCP-compatible client — Claude Desktop, Claude Code, Cursor, VS Code, Claude.ai (web), or the Inspector. Most clients authenticate with the same ba_live_ API key you generated above. For OAuth-aware hosts that require static client_id + client_secret upfront (Claude.ai’s web Connectors form is the most common example), generate platform-agnostic OAuth credentials from Settings → Developers → MCP Connectors. Those credentials work for any MCP host that speaks OAuth 2.0 Authorization Code with PKCE.
Seven ways to connect (macOS + Windows)
1. MCP Inspector (web UI, recommended for first-time testing)
npx @modelcontextprotocol/inspector When the browser opens: Transport Streamable HTTP, URL https://mcp.bugagent.com/mcp, Connection Type Proxy. Open the Authentication tab and add a header with Name Authorization and Value Bearer ba_live_YOUR_KEY. Click Connect.
2. Claude Desktop (Mac + Windows)
Edit ~/Library/Application Support/Claude/claude_desktop_config.json (Mac) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"bugagent": {
"type": "http",
"url": "https://mcp.bugagent.com/mcp",
"headers": {
"Authorization": "Bearer ba_live_YOUR_KEY_HERE"
}
}
}
} Fully quit and relaunch Claude Desktop. Tools hammer icon will show bugAgent.
3. Claude Code (CLI)
claude mcp add --transport http bugagent https://mcp.bugagent.com/mcp \
--header "Authorization: Bearer ba_live_YOUR_KEY_HERE" Restart your session. Verify with claude mcp list.
4. Cursor (Mac + Windows)
Settings → MCP → + Add new MCP server. Select HTTP transport, URL https://mcp.bugagent.com/mcp, header Authorization: Bearer ba_live_YOUR_KEY, Save. Or edit ~/.cursor/mcp.json directly with the same JSON block as Claude Desktop.
5. VS Code with Continue extension (Mac + Windows)
Install the Continue extension, then edit ~/.continue/config.json (Mac) or %USERPROFILE%\.continue\config.json (Windows):
{
"mcpServers": [
{
"name": "bugagent",
"type": "streamable-http",
"url": "https://mcp.bugagent.com/mcp",
"requestOptions": {
"headers": {
"Authorization": "Bearer ba_live_YOUR_KEY_HERE"
}
}
}
]
} 6. OAuth-aware MCP hosts (Claude.ai web shown as the example)
Hosts that require static client_id + client_secret upfront use bugAgent’s OAuth credentials. The credentials are MCP-host-agnostic — any OAuth client supporting Authorization Code + PKCE can use them. The walkthrough below uses the Claude.ai web app as the most common example.
- In bugAgent: Settings → Developers → MCP Connectors → Generate connector. Choose Confidential mode. Paste the redirect URI your MCP host requires — for the Claude.ai web app that’s
https://claude.ai/api/mcp/auth_callback; other hosts will document their own callback URL. Copy theclient_idandclient_secretshown once on the success screen. - In your MCP host’s connector / OAuth settings, paste:
- Server URL:
https://mcp.bugagent.com/mcp - Client ID + Client Secret: from step 1
- Authorization URL:
https://mcp.bugagent.com/authorize - Token URL:
https://mcp.bugagent.com/token
- Server URL:
- Save. The host redirects you to bugAgent to sign in (Google or email/password) and approve consent, then completes the OAuth handshake.
Revoke any time from the same Settings page — takes effect on the next request.
7. curl / Terminal (JSON-RPC 2.0)
MCP Streamable HTTP speaks JSON-RPC 2.0. The Accept: application/json, text/event-stream header is required.
curl -N -s https://mcp.bugagent.com/mcp \
-H "Authorization: Bearer ba_live_YOUR_KEY_HERE" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
# Call a tool
curl -N -s https://mcp.bugagent.com/mcp \
-H "Authorization: Bearer ba_live_YOUR_KEY_HERE" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{
"jsonrpc":"2.0",
"id":2,
"method":"tools/call",
"params":{"name":"list_bug_reports","arguments":{"limit":5}}
}' $headers = @{
"Authorization" = "Bearer ba_live_YOUR_KEY_HERE"
"Content-Type" = "application/json"
"Accept" = "application/json, text/event-stream"
}
$body = '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
Invoke-RestMethod -Uri "https://mcp.bugagent.com/mcp" `
-Method Post -Headers $headers -Body $body Error Handling
The API uses standard HTTP status codes and returns errors as JSON:
{
"error": "Description of what went wrong"
} | Code | Meaning |
|---|---|
200 | Success |
201 | Created |
400 | Bad request — invalid or missing parameters |
401 | Unauthorized — missing or invalid authentication |
403 | Forbidden — insufficient permissions |
404 | Not found — resource doesn't exist or you don't have access |
409 | Conflict — resource already exists |
413 | Payload too large |
422 | Unprocessable — validation failed |
500 | Internal server error |
Available SDKs
Official SDKs are coming soon for popular languages:
Node.js / TypeScript
Coming soon
Python
Coming soon
Rust
Coming soon
Go
Coming soon
In the meantime, you can use any HTTP client to interact with the API, or connect via the MCP server for AI agent workflows.
Contribute
We welcome contributions to our SDKs. If you have any suggestions or improvements, please feel free to open a pull request!
If you have any other languages you would like us to support, please reach out to us at [email protected].
License
All of our SDKs are open source and available under the MIT License. You are free to use, modify, and distribute them in your own projects.
/api/auth/register Public Register a new agent account. Accounts created via this endpoint are automatically flagged as is_agent: true. A unique workspace is created for each new account.
Request Body
email requiredpassword requiredfull_name optionalResponse
{
"userId": "uuid",
"email": "[email protected]"
} /api/auth/login Public Sign in and receive a JWT access token. Use the returned token as a Bearer token for subsequent requests, or generate a long-lived API key instead.
Request Body
email requiredpassword requiredResponse
{
"userId": "uuid",
"email": "[email protected]",
"accessToken": "eyJhbG...",
"refreshToken": "refresh_...",
"expiresAt": 1711234567
} /api/reports Auth Required List bug reports for the authenticated user's account and team. Returns reports in reverse chronological order.
Query Parameters
type optionalui, performance, crash, security, logic, data, network, accessibility, compatibility, functional, ui-ux, data-integrity, feature-request, enhancement, technical-debt, documentation, devops, ux-improvement, integrationseverity optionals1 (Blocker), s2 (Critical), s3 (Major), s4 (Minor). Legacy values still accepted for backward compatibility: critical, high, medium, low.status optionalnew, awaiting-triage, confirmed, in-progress, resolved, retesting, closed, reopened. Note the hyphens in awaiting-triage and in-progress — underscored variants will not match anything on the kanban.resolution optionalfixed, duplicate, works-as-designed, cannot-reproduce, will-not-fix, need-more-info.root_cause optionalregression, missing-requirement, documentation, incomplete-refactor, not-a-bug, requirements-mismatch.search optionalticket_number when the input is a short ID for the active workspace (TEST-24) or a bare positive integer (24) — see TEST-164.limit optionaloffset optionalExample
curl "https://app.bugagent.com/api/reports?type=crash&limit=10" \
-H "Authorization: Bearer ba_live_..." /api/reports Auth Required Create a new report. Supports bugs, feature requests, enhancements, technical debt, and more. If type is omitted, bugAgent auto-classifies based on title and description.
Request Body
title requireddescription optionaltype optionalui, performance, crash, security, logic, data, network, accessibility, compatibility, functional, ui-ux, data-integrity, feature-request, enhancement, technical-debt, documentation, devops, ux-improvement, integration. Auto-classified if omitted.severity optionals1 (Blocker), s2 (Critical), s3 (Major, default), s4 (Minor). Legacy values still accepted: critical, high, medium, low. Auto-classifiers (heuristic + Claude) now emit s1–s4.project optionalenvironment optional{ browser, os, device, url }metadata optionalformat_description optionaltrue, the description is reformatted into a structured bug template using AI before saving. Defaults to false.time_spent_seconds optional0.Response
{
"id": "1fb72a2c-87c7-4adf-90e7-9bd81a8f34b7",
"ticket_number": 545,
"short_id": "WRKID-545",
"title": "Login button unresponsive on iOS",
"type": "ui",
"severity": "high",
"classification": { "type": "ui", "confidence": 0.85 },
"quality_score": 7,
"quality_breakdown": {
"reproduction_steps": 0.9,
"expected_vs_actual": 0.8,
"environment_details": 0.7,
"evidence": 0.6,
"root_cause_analysis": 0.5,
"impact_assessment": 0.8,
"context_and_history": 0.6,
"heuristics_and_oracles": 0.7,
"clarity_and_structure": 0.9,
"actionability": 0.8
},
"created_at": "2026-03-17T12:00:00Z",
...
} /api/reports/format-description Auth Required Reformat a bug report description into a structured bug template using AI. Returns the formatted description text without modifying the report. Use this to preview the AI formatting before saving.
Request Body
description requiredtitle optionalResponse
{ "formatted": "## Summary\nLogin button is unresponsive...\n\n## Steps to Reproduce\n1. Navigate to...\n\n## Expected Behavior\n...\n\n## Actual Behavior\n..." } /api/reports/:id Auth Required Retrieve a single bug report by ID. Returns 404 if the report doesn't exist or you don't have access.
ID formats: :id accepts either the UUID (e.g. 1fb72a2c-87c7-4adf-90e7-9bd81a8f34b7) or the workspace-scoped short ID (e.g. WRKID-545). Short-ID lookups are scoped to your active team — guessing another workspace's short ID returns 404.
Response Fields (includes all standard fields plus)
quality_scorequality_breakdownreproduction_steps, expected_vs_actual, environment_details, evidence, root_cause_analysis, impact_assessment, context_and_history, heuristics_and_oracles, clarity_and_structure, actionability.claude_analysis, claude_pushed_at, claude_statusclaude_status cycles analyzing → done / failed.claude_draft_analysis, claude_challenger_critique, claude_challenger_modelclaude_draft_analysis is the pre-critique Sonnet output, claude_challenger_critique is the OpenAI peer review, claude_challenger_model names the challenger. All three are null when the challenger step was skipped.claude_rebuttal, claude_adjudicator_models1/critical or s2/high). claude_rebuttal is Sonnet's point-by-point response to the critique; claude_adjudicator_model names the model that wrote the final claude_analysis after reading the full transcript. Both null on s3/medium or s4/low bugs (which use the cheaper three-step chain) and when the debate chain couldn't adjudicate (falls through to simple synthesis).likely_fix_area, likely_fix_area_status, likely_fix_area_generated_atdev_notes_stale/api/reports/:id Auth Required Update a bug report. Only fields you include in the body are updated.
ID formats: :id accepts either the UUID or the short ID (e.g. WRKID-545). Same rules apply across all /api/reports/:id verbs.
Request Body
title, description, type, severity, internal_notesinternal_notes are private and not synced to Jira.status optionalnew, awaiting-triage, confirmed, in-progress, resolved, retesting, closed, reopened. The hyphens in awaiting-triage and in-progress are deliberate — underscored variants won't show up on the kanban.resolution optionalnew toward retesting / resolved / closed. Allowed values: fixed (code change shipped), duplicate (reference the canonical ticket in a comment), works-as-designed (intentional behavior), cannot-reproduce, will-not-fix (deliberately deferring), need-more-info.root_cause optionalresolution on close. Common values today: regression, missing-requirement, documentation, incomplete-refactor, not-a-bug, requirements-mismatch. Open-ended — extend the taxonomy when a new pattern shows up in 2+ tickets. Used by analytics and the agent-loop training corpus.assigned_to optionalnull to unassign. When the assignee changes, a database trigger fires the in-app bell notification AND emails the new assignee — same path is used by the MCP update_bug_report tool and any raw SQL UPDATE, so notifications are consistent regardless of entry point. Email respects the per-user opt-out at notification_preferences.email_bug_report_assignment (default on). When status=retesting, the email uses retest-handoff wording.time_spent_seconds optional/api/reports/assign Auth Required Assign a bug report to a team member. A database trigger automatically fires the in-app bell notification AND an email to the new assignee whenever the assignee actually changes (re-saving the same user is silent). Same trigger pipeline is reached by every other update path (PATCH /api/reports/:id, the MCP update_bug_report tool, raw SQL) so notifications are consistent regardless of how the assignment happened.
Request Body
report_id requiredWRKID-545) — The bug report to assign.assigned_to requiredResponse
Returns success: true and notified: true if the bell-icon notification was inserted. The email send is fire-and-forget — the response returns before it completes. The assignee can mute the email channel at /dashboard/settings#notifications (in-app bell is always shown).
/api/reports/upload Auth Required Upload file attachments (screenshots, screen recordings, audio memos, documents) to a bug report. Uses multipart/form-data.
Form Fields
reportId requiredfiles requiredimage/* (png, jpeg, gif, webp, heic, avif, svg), any video/* (mp4, webm, quicktime, mpeg), any audio/* (mp3, wav, m4a, ogg, webm), application/pdf, text/plain, text/csv, text/markdown, application/json./api/reports/flush Auth Required Bulk delete old bug reports. Requires owner or admin team role.
Request Body
months requiredproject_id optionalResponse
{ "deleted": 42 } /api/reports/comments Auth Required Add a comment to a bug report, or toggle an emoji reaction on a comment.
Create Comment
report_id requiredcontent requiredToggle Reaction
action required"react"comment_id requiredemoji required/api/reports/comments Auth Required Edit a comment. Only the author can edit their own comments.
comment_id requiredcontent required/api/reports/comments Auth Required Delete a comment. Only the author can delete their own comments.
comment_id required/api/projects Auth Required List all projects for your team.
/api/projects Auth Required Create a new project. The first project is automatically set as default. Subject to plan limits.
Request Body
name requireddescription optionalis_default optional/api/projects Auth Required Update a project's name, description, or default status.
id requiredname, description, is_default/api/projects Owner / Manager Permanently delete a project and all associated data. Only owners and managers can delete projects. You cannot delete your last project — every workspace must have at least one.
Request Body (JSON)
id requiredWhat Gets Deleted
- All bug reports and their media attachments (storage freed)
- Web automations, runs, and schedules
- Mobile apps, automations, runs, and schedules (binaries purged from storage)
- Test cases, test suites, test runs, and results
- Geo-Snap screenshots
- Notes and time tracking entries
Important Behavior
Errors
403400404/api/keys Auth Required List your active (non-revoked) API keys. Only the key prefix is returned — full keys are shown once at creation.
/api/keys Auth Required Generate a new API key. The full key (starting with ba_live_) is returned only once — store it securely.
Request Body
name requiredscopes optional["reports:read", "reports:write"]Response
{
"key": "ba_live_abc123...",
"id": "uuid",
"name": "CI Pipeline",
"key_prefix": "ba_live_abc123",
"scopes": ["reports:read", "reports:write"],
"created_at": "2026-03-17T12:00:00Z"
} /api/keys/:id Auth Required Revoke an API key. The key is soft-deleted and can no longer be used for authentication.
/api/keys/:id/regenerate Auth Required Revoke the current key and generate a new one with the same name and scopes. Returns the new full key.
/api/profile Auth Required Get the authenticated user's profile.
Response
{
"id": "uuid",
"email": "[email protected]",
"full_name": "Jane Smith",
"avatar_url": null,
"plan": "pro",
"is_agent": false,
"created_at": "2026-03-10T08:00:00Z"
} /api/profile Auth Required Update your profile. Only full_name can be changed via the API (security: no email, role, or plan changes).
full_name/api/profile/password Auth Required Change your password.
password required/api/settings Auth Required Get your profile info and notification preferences.
Response
{
"fullName": "Jane Smith",
"email": "[email protected]",
"isAgent": false,
"plan": "pro",
"notifications": {
"emailUsageWarning": true,
"emailBugReportAssignment": true,
"emailTestCaseAssignment": true
}
} /api/settings Auth Required Update notification preferences.
email_usage_warning optional/api/usage Auth Required Get your current plan usage (reports used, limit, remaining, reset date).
Response
{
"used": 47,
"limit": 5000,
"remaining": 4953,
"plan": "pro",
"period": "monthly",
"resetsAt": "2026-04-01T00:00:00Z"
} /api/stats Auth Required Get report statistics with daily counts, breakdowns by type, severity, and status.
Query Parameters
days optionalResponse
{
"period": "30 days",
"total": 127,
"daily": [
{ "date": "2026-02-16", "count": 3 },
{ "date": "2026-02-17", "count": 5 },
...
],
"byType": { "ui": 42, "crash": 18, "logic": 67, "feature-request": 12, "enhancement": 8 },
"bySeverity": { "high": 23, "medium": 89, "low": 15 },
"byStatus": { "open": 95, "resolved": 32 }
} /api/checkout Auth Required Create a Stripe checkout session to upgrade your plan. Returns a URL to redirect the user to.
Request Body
plan required"pro" or "team"billing optional"monthly" (default) or "annual"Response
{ "url": "https://checkout.stripe.com/..." } /api/billing-portal Auth Required Get a URL to the Stripe billing portal where users can manage subscriptions, payment methods, and invoices.
Response
{ "url": "https://billing.stripe.com/..." } /dashboard/settings/team Manager+ Invite a user to your team. Sends an email invitation with a 5-day expiry. Invited users join the inviting workspace directly — no separate workspace is created.
Form Data
action required"invite"email requiredrole optional"contributor" (default), "manager", or "owner". Managers can only invite contributors and managers./dashboard/settings/team Manager+ Edit a team member's display name inline. Owners and admins can edit any non-owner member. Managers can edit contributors and other managers but not owners or admins.
Form Data
action required"edit_name"member_id requirednew_name required/dashboard/settings/team Manager+ Change a team member's role. Managers can assign contributor or manager roles. Only owners/admins can assign admin. Owner role can only be changed via ownership transfer.
Form Data
action required"change_role"member_id requirednew_role required"contributor", "manager", or "admin"/dashboard/settings/team Owner / Manager Remove a team member from the workspace. Only owners and managers can remove members. Owners cannot be removed. All data created by the removed user (bug reports, automations, test cases, mobile apps, geo snaps, schedules, time tracking) is reassigned to the person performing the removal. Notes are deleted. The user's profile is preserved as a ghost stub for foreign-key integrity and re-invite capability.
Form Data
action required"remove_member"member_id required/api/switch-team Auth Required Switch the active workspace context. Users who belong to multiple workspaces use this to change which workspace's data they see.
Request Body (JSON)
teamId required/api/create-team Auth Required Create a new workspace. Available to all plan tiers (Free, Pro, Team, Enterprise) with a 100-workspace cap per user. New workspaces start on the free plan and can be upgraded via billing. If no name is provided, a unique uplifting name is auto-generated (e.g. "Radiant Foxes"). A Default Project is automatically created so the workspace always has at least one project.
Request Body (JSON)
name optionalResponse
{
"success": true,
"team": {
"id": "uuid",
"name": "Radiant Foxes",
"plan": "pro"
}
} Errors
403409400Skills Overview
bugAgent Skills connect external tools into your QA workflow via OAuth or API keys. Each Skill enriches the context engine with data from services your team already uses — syncing code, pulling analysis, and bridging issue trackers.
Available Skills
| Skill | Connection | Description |
|---|---|---|
| GitHub | OAuth | Sync repositories for Playwright automation scripts. See GitHub endpoints. |
| Jira | OAuth 2.0 | Bi-directional bug sync with comments, attachments, and severity. See Jira endpoints. |
| Claude | API Key | Root cause analysis for bug reports. See Claude endpoints. |
| Slack | Webhook | Notifications for new reports, automation results, and team activity. |
Enabling Skills
Navigate to Settings → Integrations in the dashboard. Each Skill has its own connection flow. Once connected, configure per-project settings such as auto-push for Claude, repository mapping for GitHub, or default project for Jira.
Building Custom Skills
Partners can build custom Skills that interact with bugAgent programmatically. Use the REST API endpoints documented below — reports, automation, projects, and team management — to create integrations that feed data into or out of bugAgent. To propose a new Skill, contact [email protected].
/api/jira/connect Manager+ Start the Jira OAuth 2.0 flow. Redirects to Atlassian's authorization page. The resulting connection is stored against the user's active team, not the individual user.
/api/jira/projects Auth Required Fetch all Jira projects accessible by the team's shared connection. Used to populate the project dropdown when pushing a report to Jira for the first time. Returns the default project key if one is saved.
Response
{
"projects": [
{ "id": "10001", "key": "BUG", "name": "Bug Tracker", "avatar": "https://..." },
{ "id": "10002", "key": "PROJ", "name": "Main Project", "avatar": "https://..." }
],
"defaultProjectKey": "BUG"
} /api/jira/sync Auth Required Sync a bug report to Jira using the team's shared connection. Creates a Jira issue with mapped fields, labels, and uploads any attachments. Severity is mapped to Jira priority (s1/critical→Highest, s2/high→High, s3/medium→Medium, s4/low→Low). Any authenticated team member can sync.
Request Body
reportId requiredprojectKey optionalResponse
{
"success": true,
"jiraKey": "PROJ-1234",
"jiraUrl": "https://your-site.atlassian.net/browse/PROJ-1234"
} /api/jira/force-sync Auth Required Force an immediate bi-directional sync between bugAgent and Jira. Triggered by the sync button next to the AUTO SYNC badge on the report detail page. Syncs description, title, severity/priority, comments, and media attachments.
Request Body
reportId requiredSync Behavior
report.updated_at vs Jira fields.updated — whichever platform was modified more recently determines the value. The other side is updated automatically.jira_comment_id are pushed to Jira. Jira comments not in bugAgent are pulled in. Comments originating from bugAgent (prefixed [bugAgent]) are not re-imported.jira_attachment_id to prevent duplicates across sync cycles.Response
{
"success": true,
"results": [
"Description synced",
"Priority pushed to Jira (high — last updated)",
"2 comment(s) pushed to Jira",
"1 attachment(s) pulled from Jira"
]
} /api/jira/check Auth Required Check if a synced Jira issue has been modified. Compares title, severity, status, and type between bugAgent and Jira. Severity uses last-updated-wins logic and is auto-applied during polling. Comments and attachments are synced bi-directionally via the auto-sync polling and force-sync endpoints.
Query Parameters
reportId requiredResponse
{
"hasChanges": true,
"jiraUpdatedAt": "2026-03-18T15:30:00.000Z",
"changes": {
"title": { "jira": "Updated title in Jira", "bugagent": "Original title" },
"severity": { "jira": "high", "bugagent": "medium" }
}
} /api/jira/merge Auth Required Bi-directional merge between bugAgent and Jira. Updates bugAgent with the chosen values, then pushes them to Jira so both systems are identical. Severity is mapped to Jira priority. For automatic conflict resolution, use /api/jira/force-sync which applies last-updated-wins logic.
Request Body
reportId requiredmerged requiredtitle, severity, status, type. Each value is the chosen winner (from bugAgent or Jira)./api/jira/settings Manager+ Update the team's Jira integration settings or disconnect. Only managers and above can modify these settings.
Request Body
action required"update_settings" or "disconnect"auto_push optionaldefault_project_key optional/api/jira/batch-sync-status Auth Required Batch-sync report statuses with Jira. Used by the Kanban board to push status changes after drag-and-drop reordering. Fetches the latest Jira status for each report and reconciles any differences.
Request Body
report_ids requiredResponse
{
"updates": [
{
"id": "uuid",
"old_status": "new",
"new_status": "in-progress",
"jira_status": "In Progress"
}
],
"synced": 1
} /api/automations Auth Required Create a new automation. Stores the recorded steps, generated Playwright script, and optional schedule. The automation is scoped to the user's active team.
Request Body
name requiredsteps requiredscript optional/generate-script)schedule optional"0 9 * * 1-5")start_url optionalResponse
{
"id": "uuid",
"name": "Login flow smoke test",
"steps": [ ... ],
"script": "import { test } from '@playwright/test'; ...",
"schedule": "0 9 * * 1-5",
"start_url": "https://app.example.com/login",
"status": "active",
"team_id": "uuid",
"created_by": "uuid",
"created_at": "2026-03-21T12:00:00Z",
"updated_at": "2026-03-21T12:00:00Z"
} /api/automations/create Auth Required Create a new automation with a custom Playwright script. Unlike POST /automations which expects recorded FAB steps, this endpoint lets you supply a script directly — ideal for hand-written tests, AI-generated scripts, or scripts imported from an existing test suite.
Supported languages: Node.js/JavaScript/TypeScript and Python. The runner auto-detects the language from the script's imports (from playwright/import playwright → Python; otherwise Node). Python scripts run under pytest if they define a def test_* function, otherwise under python3. Other languages (C#, Java, etc.) aren't supported yet.
Duplicating an Automation
To duplicate an existing automation, fetch its details via GET /api/automations/:id, then call this endpoint with the original's script, target_url, and project_id. Set name to "[Copy] Original Name". The duplicate starts in "draft" status and does not inherit version history or run history from the original.
Request Body
name requiredtarget_url optionalpage.goto(...) call in the script.script optionalstatus optional"active" or "draft". Default: "draft"project_id optionalAuthentication
Requires session authentication (dashboard) or an API key with automations:write scope.
Plan
Pro or Team plan required.
Response
{
"id": "uuid"
} /api/automations Auth Required List all automations for the user's active team. Supports pagination and filtering by status.
Query Parameters
status optionalactive, paused, archivedproject_id optionalcreated_by optionalpage optionallimit optionalResponse
{
"automations": [
{
"id": "uuid",
"name": "Login flow smoke test",
"status": "active",
"project_id": "proj_uuid",
"created_by": "user_uuid",
"schedule": "0 9 * * 1-5",
"last_run_at": "2026-03-21T09:00:00Z",
"last_run_status": "passed",
"run_count": 42,
"created_at": "2026-03-20T12:00:00Z"
}
],
"total": 5,
"page": 1,
"limit": 20
} /api/automations/:id Auth Required Get full details of a single automation, including recorded steps, generated Playwright script, schedule, recent run history, and saved script version history (the stack that version_index on the run endpoints indexes into).
Response
{
"id": "uuid",
"name": "Login flow smoke test",
"steps": [
{ "action": "navigate", "url": "https://app.example.com/login" },
{ "action": "fill", "selector": "#email", "value": "[email protected]" },
{ "action": "fill", "selector": "#password", "value": "********" },
{ "action": "click", "selector": "button[type=submit]" },
{ "action": "assert", "selector": ".dashboard-title", "text": "Welcome" }
],
"script": "import { test, expect } from '@playwright/test'; ...",
"script_versions": [
{ "script": "// older text of the script", "source": "manual_edit", "timestamp": "2026-03-20T13:42:00Z" },
{ "script": "// the state before an AI-optimize ran", "source": "before_optimize", "timestamp": "2026-03-21T07:50:00Z" }
],
"schedule": "0 9 * * 1-5",
"start_url": "https://app.example.com/login",
"status": "active",
"team_id": "uuid",
"created_by": "uuid",
"created_at": "2026-03-20T12:00:00Z",
"updated_at": "2026-03-21T08:00:00Z",
"recent_runs": [
{ "id": "uuid", "status": "passed", "duration_ms": 4200, "started_at": "2026-03-21T09:00:00Z", "script_version_label": "current", "script_version_source": "current" }
]
} Notes
scriptis always the current live version — the one Run Now executes whenversion_indexis omitted.script_versionsis a chronological stack (oldest first) of up to 100 prior states ofscript. An entry is pushed wheneverscriptchanges via PATCH, optimize, or the BrowserStack rewrite. Each entry records{ script, source, timestamp }; validsourcevalues aremanual_edit,before_optimize,bs_compat_rewrite. Callers index into this array withversion_indexonPOST /automations/runsorPOST /v1/automations/runto replay a historical version. Omitversion_indexto runscript(current).- Each entry in
recent_runscarries the version it executed asscript_version_label("current"or"vN") andscript_version_source. The per-run script text itself is on the run detail (script_snapshot) — omitted from list responses to keep them small.
/api/automations/:id Auth Required Update an existing automation. Only provided fields are changed. Use this to rename, update the script, change the schedule, or pause/resume.
Request Body
name optionalsteps optionalscript optionalscript, the previous text is pushed onto script_versions (capped at 100 entries, oldest-evicted) so callers can replay or undo it.version_source optionalscript_versions when script changes. Defaults to "manual_edit". The dashboard uses "bs_compat_rewrite" when accepting the BrowserStack rewrite; the optimize endpoint internally uses "before_optimize". Ignored when script is unchanged.schedule optionalnull to remove schedulestatus optionalactive, paused, or archivedauth_enabled optionalauth_username is optional (leave blank for password-only gates).auth_signin_url optionalpage.goto().auth_username optionalauth_password optionalAUTOMATIONS_AUTH_KEY. Pass an empty string to clear the stored password; omit to leave it unchanged. Never returned in responses.Response
{
"id": "uuid",
"name": "Login flow smoke test (updated)",
"status": "paused",
"schedule": null,
"updated_at": "2026-03-21T14:00:00Z"
} Notes
- GET responses include
auth_has_password: true|falseso clients can render a "password set" indicator without ever seeing the ciphertext. - Pre-auth runs a heuristic login: navigate to
auth_signin_url, fill the password field (and username/email if provided) via role/type selectors, submit, wait fornetworkidle. Supports username+password flows (including two-step email → Next → password) and password-only front-door gates. - When the heuristic selectors don't match the signin page (e.g. non-standard input names, custom-element wrappers), the runner falls back to a Claude-assisted locator plan. The runner captures the signin form HTML, ships it to Claude (with
"USERNAME"/"PASSWORD"placeholders so credentials never hit the model), receives a structured step list (fill / click / wait), and executes it. No additional user configuration required — this happens automatically on every pre-auth miss. - On BrowserStack (including iOS Playwright), pre-auth runs as a
test.beforeEachhook injected into the remote browser's test — a storage-state handoff from a local Chromium would fail because of IP pinning and engine mismatch. The injected prologue uses either the heuristic or the Claude-built plan, whichever the runner's local probe determined would work on this particular signin page.
/api/automations/:id Auth Required Permanently delete an automation and all its associated run history. This action cannot be undone.
Response
{ "deleted": true } /api/automations/generate-script Auth Required Generate a Playwright script from recorded browser steps using AI. The generated script includes assertions, error handling, and is ready to run. Optionally saves the script to an existing automation.
Request Body
steps requiredautomation_id optionalstart_url optionalResponse
{
"script": "import { test, expect } from '@playwright/test';\n\ntest('Login flow smoke test', async ({ page }) => {\n await page.goto('https://app.example.com/login');\n await page.fill('#email', '[email protected]');\n await page.fill('#password', '********');\n await page.click('button[type=submit]');\n await expect(page.locator('.dashboard-title')).toContainText('Welcome');\n});",
"automation_id": "uuid"
} /api/automations/:id/optimize Auth Required Send a Playwright script to Sonnet 4 for AI-powered optimization. Applies a 12-point checklist that automatically fixes selectors, wait strategies, assertions, error handling, auth patterns, mobile compatibility, and strict mode issues. The current script version is saved before optimization so you can undo the change.
URL Parameters
id requiredResponse
{
"script": "// optimized Playwright script...",
"version": 3,
"changes_summary": "Fixed 4 issues: replaced fragile text selectors with data-testid, added explicit waitForLoadState, improved assertions with toBeVisible, added error recovery for auth flow."
} /api/automations/:id/undo Auth Required Revert the automation script to the most recent entry in script_versions. Pops the top of the stack (newest prior version) and promotes it to script. Up to 100 prior versions are retained. Versions are saved before manual edits, AI optimization, and BrowserStack rewrites. To replay (not revert to) a specific historical version without mutating current, pass version_index to POST /automations/runs instead.
URL Parameters
id requiredResponse
{
"script": "// previous version of the script...",
"version": 2,
"versions_remaining": 1
} { "error": "No previous versions available to undo" } /api/automations/:id/rewrite-for-bs Auth Required Rewrite a script-style Python Playwright script (sync_playwright() + browser.new_page() + if __name__ == "__main__":) into pytest-style (def test_<name>(page: Page):), which is what bugAgent Live (BrowserStack) requires for Python runs. Driven by Claude Haiku; behavior is preserved — every page.goto, click, fill, wait, and assertion carries over. The endpoint only performs the rewrite; it doesn't save. The caller sends a subsequent PATCH /api/automations/:id to commit (the dashboard UI does this on Accept, tagged version_source: "bs_compat_rewrite" so the regular Undo flow can roll it back).
Request Body
script requiredResponse
{
"rewritten": "from playwright.sync_api import Page, expect\n\ndef test_navigate_and_wait(page: Page):\n page.goto(\"https://example.com\")\n ..."
} Notes
- The dashboard shows an amber "Not compatible with bugAgent Live" banner on the automation detail page when a Python script lacks a
def test_*(page):function, with a one-click rewrite button that calls this endpoint. - Requires
ANTHROPIC_API_KEYon the Dashboard service. Returns500with a clear error if not configured. - Markdown code fences in Claude's output are stripped defensively before returning — the response is always raw Python source, never wrapped in
```python … ```. - Does not modify stored data. To persist the rewrite, follow up with
PATCH /api/automations/:idincluding"script": <rewritten>and (optionally)"version_source": "bs_compat_rewrite"so the entry shows up in version history with that tag.
/api/automations/runs Auth Required Trigger an on-demand run of an automation. The run is queued and executed asynchronously. Poll GET /api/automations/runs or use the returned run ID to check status.
Request Body
automation_id requiredversion_index optionalscript_versions stack instead of the live script. Default: the current live script runs whenever this field is omitted or null. The history holds up to 100 entries, oldest first — pass 0 for the oldest, script_versions.length - 1 for the newest prior entry. Non-integer, negative, or out-of-range values return 400; we never silently fall back to current so a stale client can't ship the wrong version by accident. The resolved script is snapshotted onto the run record so it stays recoverable after further edits or stack eviction. Call GET /automations/:id first if you need to inspect the available versions.environment optionaldevice optional"desktop"browserstack optionaltrue to run on a real BrowserStack browser instead of the local runner. Requires bs_browser, bs_os, bs_os_version. Node.js scripts support desktop, real Android, and real iPhone; Python scripts support desktop only (real mobile on Python isn't supported by BrowserStack's Playwright product yet). After the run completes the runner fetches BrowserStack's session video and re-hosts it on our own storage — video_url on the resulting run record points at the re-hosted URL so end users can watch the video in the dashboard without needing a BrowserStack login of their own. A Playwright trace .zip is also captured and published at results.trace_url (open in https://trace.playwright.dev/?trace=<url>).bs_browser optional"chrome", "firefox", "safari", "edge"bs_os optional"Windows", "OS X", "android" for a real Android device, or "ios" for a real iPhone.bs_os_version optional"11" on Windows, "Sonoma" on macOS). For bs_os: "android": the real Android device name ("Samsung Galaxy S25 Ultra", "Google Pixel 10", "OnePlus 13R"). For bs_os: "ios": the real iPhone model ("iPhone 17 Pro Max", "iPhone 16 Pro Max", "iPhone 15 Pro Max"). The runner pairs each device with the correct BrowserStack osVersion automatically. Node.js/TypeScript scripts run via the BrowserStack Node SDK (browserstack-node-sdk) — covers desktop, real Android, and real iPhone. Python scripts run via the BrowserStack Python SDK (browserstack-sdk pip, pytest-playwright) — desktop only. Real mobile on Python isn't supported yet: browser_type.connect() can't drive BrowserStack's real-mobile endpoints the way the Node SDK's _android.connect() / webkit.connect() do.Response
{
"run_id": "uuid",
"automation_id": "uuid",
"status": "queued",
"device": "desktop",
"queued_at": "2026-03-21T14:30:00Z"
} Notes
- Self-healing locators (automatic). Every Node Playwright run is wrapped so that when a locator action (
click,fill,press,hover, etc.) times out, the runner captures the page's interactive DOM, asks Claude for a better CSS selector, and retries the same action once with the replacement. The healing happens in the Node test worker on our runner — no secrets leak to the browser. Applies to both local and BrowserStack runs. Healing events are surfaced in the run's stdout as[bugAgent] self-healed locator: "<original>" → "<replacement>". Assertions (expect().toBeVisible()etc.) are not healed — a failed assertion still fails the test. - Pre-auth (if configured on the automation) runs before the test. See PATCH /automations/:id for details.
/api/automations/runs Auth Required List automation runs for the user's active team. Filter by automation ID or status. Returns run results including duration, pass/fail status, and any error output. For Live (BrowserStack) runs, video_url points at our re-hosted copy of the BS session video (Supabase Storage, no BrowserStack login required) and results.trace_url points at the Playwright trace .zip; open the latter in https://trace.playwright.dev/?trace=<url> for a full DOM-timeline replay.
Query Parameters
automation_id optionalstatus optionalqueued, running, passed, failed, cancelledpage optionallimit optionalResponse
{
"runs": [
{
"id": "uuid",
"automation_id": "uuid",
"automation_name": "Login flow smoke test",
"status": "passed",
"duration_ms": 4200,
"started_at": "2026-03-21T09:00:00Z",
"finished_at": "2026-03-21T09:00:04Z",
"error": null,
"video_url": "https://storage.bugagent.com/runs/uuid/bs-session.mp4",
"script_version_label": "current",
"script_version_source": "current",
"script_snapshot": "// full Playwright source the runner executed",
"results": {
"trace_url": "https://storage.bugagent.com/runs/uuid/trace.zip"
}
},
{
"id": "uuid",
"automation_id": "uuid",
"automation_name": "Checkout flow",
"status": "failed",
"duration_ms": 8500,
"started_at": "2026-03-21T09:00:00Z",
"finished_at": "2026-03-21T09:00:08Z",
"error": "Timeout waiting for selector '#confirm-btn'",
"video_url": "https://storage.bugagent.com/runs/uuid/video.webm",
"results": {
"trace_url": "https://storage.bugagent.com/runs/uuid/trace.zip",
"stdout": "...",
"stderr": "..."
}
}
],
"total": 42,
"page": 1,
"limit": 20
} /api/v1/automations/run API Key Trigger an automation run from CI/CD pipelines. Authenticates via API key instead of session token. Designed to be called from GitHub Actions, GitLab CI, or any CI/CD system. Returns immediately with a run ID for polling.
Request Body
automation_id requiredversion_index optionalscript_versions stack (0 = oldest). Default: the current live script runs whenever this field is omitted or null. Non-integer, negative, or out-of-range values return 400. The run record captures the resolved script snapshot plus script_version_label and script_version_source, and any bug report auto-created from a failed run deep-links back to this exact version in the editor via ?version_index=N.environment optionalcallback_url optionaldevice optional"desktop". See POST /automations/runs for the full list of supported device values.Headers
Authorization requiredBearer ba_live_... — API key with automations:run scopeResponse
{
"run_id": "uuid",
"automation_id": "uuid",
"status": "queued",
"device": "desktop",
"poll_url": "/api/v1/automations/runs/uuid",
"queued_at": "2026-03-21T14:30:00Z"
} /api/v1/automations/runs/:id API Key Poll the status of a CI/CD automation run. Returns the current status, duration, and any error output. Use this to wait for completion in CI/CD scripts.
Headers
Authorization requiredBearer ba_live_... — API key with automations:run scopeResponse
{
"id": "uuid",
"automation_id": "uuid",
"automation_name": "Login flow smoke test",
"status": "passed",
"duration_ms": 4200,
"started_at": "2026-03-21T09:00:00Z",
"finished_at": "2026-03-21T09:00:04Z",
"error": null,
"trace_url": "https://bugagent.com/traces/uuid",
"screenshots": [
{ "step": "login-success", "url": "https://storage.bugagent.com/screenshots/uuid.png" }
]
} tests/bugagent/{name}.spec.ts and stay in sync on every edit./api/github/connect Auth Required Initiate the GitHub OAuth flow. Returns a redirect URL that opens the GitHub authorization page. Once the user authorizes, GitHub redirects back to bugAgent with an installation token. Connect from Settings → Integrations in the dashboard.
Request Body
redirect_uri optionalResponse
{
"authorization_url": "https://github.com/login/oauth/authorize?client_id=...",
"state": "random-state-token"
} /api/github/repos Auth Required List all GitHub repositories accessible via the connected GitHub account. Use this to select which repo to map to a bugAgent project.
Response
{
"repos": [
{
"id": 123456,
"full_name": "acme/web-app",
"default_branch": "main",
"private": true
}
]
} /api/github/mapping Auth Required Map a bugAgent project to a GitHub repository. Once mapped, Playwright automation scripts created or updated in that project are automatically pushed to tests/bugagent/{name}.spec.ts in the target repo. Deleting or archiving an automation removes the file from the repo.
Request Body
project_id requiredrepo_full_name requiredowner/repo format (e.g. acme/web-app)branch optionalpath_prefix optionaltests/bugagent.Response
{
"mapping_id": "uuid",
"project_id": "uuid",
"repo_full_name": "acme/web-app",
"branch": "main",
"path_prefix": "tests/bugagent",
"created_at": "2026-03-22T10:00:00Z"
} /api/github/status Auth Required Check the current GitHub connection status and project-to-repo mappings for the authenticated user's workspace. Also returns recent sync history and any SHA conflict errors.
Response
{
"connected": true,
"github_username": "acme-dev",
"mappings": [
{
"project_id": "uuid",
"project_name": "Web App",
"repo_full_name": "acme/web-app",
"branch": "main",
"path_prefix": "tests/bugagent",
"last_sync_at": "2026-03-22T09:45:00Z",
"sync_status": "ok"
}
]
} Notes
- If
sync_statusissha_conflict, the remote file was modified outside bugAgent. UsePOST /api/github/mappingto re-map and force a fresh push, or resolve the conflict in GitHub first. - Scripts are pushed to
{path_prefix}/{automation-name}.spec.tsusing the GitHub Contents API.
/api/github/disconnect Auth Required Disconnect the GitHub integration. Removes the OAuth token and all project-to-repo mappings. Scripts already pushed to GitHub are not deleted.
Response
{
"disconnected": true
} /api/notes Auth Required List notes for the authenticated user's team. Returns notes the user owns or notes with shared visibility. Supports keyword search, project filtering, author filtering, and date range filtering.
Query Parameters
q optionalproject_id optionalauthor_id optionalfrom optionalto optionalpage optionalper_page optionalResponse
{
"notes": [
{
"id": "uuid",
"title": "Checkout flow observations",
"format": "markdown",
"visibility": "shared",
"project_id": "uuid",
"author_id": "uuid",
"author_name": "Jane Smith",
"time_spent_seconds": 1820,
"attachments_count": 2,
"created_at": "2026-03-22T10:00:00Z",
"updated_at": "2026-03-22T10:30:00Z"
}
],
"total": 42,
"page": 1,
"per_page": 20
} /api/notes Auth Required Create a new note. If no title is provided, the first 30 characters of the content are used as the auto-title. Notes auto-save as you type in the dashboard, but this endpoint creates the initial note record.
Request Body
title optionalcontent optionalformat optionalmarkdown (default), plain_text, rich_text, checklist, outlinevisibility optionalprivate (default) or shared. Private notes are only visible to the author. Shared notes are visible to all team membersproject_id optionaltime_spent_seconds optional0Response
{
"id": "uuid",
"title": "Checkout flow observations",
"content": "## Session 1\n- Payment form loads slowly...",
"format": "markdown",
"visibility": "private",
"project_id": "uuid",
"author_id": "uuid",
"time_spent_seconds": 0,
"attachments": [],
"created_at": "2026-03-22T10:00:00Z",
"updated_at": "2026-03-22T10:00:00Z"
} /api/notes/:id Auth Required Get full details of a single note including content and attachments. Returns the note only if the user is the author or the note has shared visibility within the same team.
Response
{
"id": "uuid",
"title": "Checkout flow observations",
"content": "## Session 1\n- Payment form loads slowly on 3G...",
"format": "markdown",
"visibility": "shared",
"project_id": "uuid",
"author_id": "uuid",
"author_name": "Jane Smith",
"time_spent_seconds": 1820,
"attachments": [
{
"id": "uuid",
"filename": "screenshot.png",
"size_bytes": 245000,
"mime_type": "image/png",
"url": "https://storage.bugagent.com/notes/uuid/screenshot.png"
}
],
"created_at": "2026-03-22T10:00:00Z",
"updated_at": "2026-03-22T10:30:00Z"
} /api/notes/:id Auth Required Update an existing note. Only provided fields are changed. Only the note author can update a note. The dashboard uses this endpoint for auto-save (triggered on content changes) and manual save (Save button or Cmd/Ctrl+S).
Request Body
title optionalcontent optionalformat optionalmarkdown, plain_text, rich_text, checklist, outlinevisibility optionalprivate or sharedproject_id optionaltime_spent_seconds optionalResponse
{
"id": "uuid",
"title": "Checkout flow observations (updated)",
"content": "...",
"format": "markdown",
"visibility": "shared",
"time_spent_seconds": 2400,
"updated_at": "2026-03-22T11:00:00Z"
} /api/notes/:id Auth Required Permanently delete a note and all its attachments. Only the note author can delete a note. This action cannot be undone.
Response
{ "deleted": true } /api/notes/upload Auth Required Upload a file attachment to a note. Files are stored in Supabase Storage and linked to the note. Accepts any image, video, audio, PDF, or text/JSON file up to 400 MB per file — the same policy as bug report attachments.
Request Body (multipart/form-data)
note_id requiredfile requiredResponse
{
"id": "uuid",
"note_id": "uuid",
"filename": "walkthrough.mp4",
"size_bytes": 52428800,
"mime_type": "video/mp4",
"url": "https://storage.bugagent.com/notes/uuid/walkthrough.mp4"
} Notes
- Accepted MIME types: any
image/*(png, jpeg, gif, webp, heic, avif, svg), anyvideo/*(mp4, webm, quicktime, mpeg), anyaudio/*(mp3, wav, m4a, ogg, webm),application/pdf,text/plain,text/csv,text/markdown,application/json. - Maximum file size: 400 MB per file. Large screen recordings and audio memos are supported.
- Files are stored in the team's Supabase Storage bucket and served via signed URLs.
/api/time-entries Auth Required List time tracking entries for the authenticated user's team. Supports filtering by time period, project, and category.
Query Parameters
period optionaltoday, week, month, or all (default: all)project_id optionalcategory optionaltesting, bug-triage, automation)sort optionalnewest (default), oldest, most_time, least_timeResponse
{
"entries": [
{
"id": "uuid",
"description": "Regression testing checkout flow",
"category": "testing",
"duration_minutes": 45,
"project_id": "uuid",
"entry_date": "2026-03-22",
"user_id": "uuid",
"created_at": "2026-03-22T10:00:00Z",
"updated_at": "2026-03-22T10:00:00Z"
}
],
"count": 1
} /api/time-entries Auth Required Create a new time tracking entry. Log hours spent on QA tasks with categories for team reporting and analytics.
Request Body
description requiredcategory requiredtesting, bug-triage, automation, review, meeting)duration_minutes requiredproject_id optionalentry_date optionalYYYY-MM-DD format (defaults to today)Response
{
"id": "uuid",
"description": "Regression testing checkout flow",
"category": "testing",
"duration_minutes": 45,
"project_id": "uuid",
"entry_date": "2026-03-22",
"created_at": "2026-03-22T10:00:00Z"
} /api/time-entries/:id Auth Required Update an existing time tracking entry. Only provided fields are changed.
Request Body
description optionalcategory optionalduration_minutes optionalproject_id optionalentry_date optionalYYYY-MM-DD formatResponse
{
"id": "uuid",
"description": "Regression testing checkout flow (updated)",
"category": "testing",
"duration_minutes": 60,
"project_id": "uuid",
"entry_date": "2026-03-22",
"updated_at": "2026-03-22T11:00:00Z"
} /api/time-entries/:id Auth Required Delete a time tracking entry. This action cannot be undone.
Response
{ "deleted": true } Notes
- Time Tracking is a Team plan feature. Free and Pro plan users receive a
403 Forbiddenresponse. - Entries are scoped to the authenticated user's team. All team members can view entries; only the entry creator or team admins can update or delete.
owner_id = auth.uid() — neither the dashboard nor this API ever returns another user's resources. Rows are filtered by team_id (workspace) and optionally project_id. The Chrome extension syncs with these endpoints to mirror local recordings into bugAgent./api/resources Auth Required List the caller's CoPilot resources (recording action logs + generated Playwright scripts) in the requested workspace, optionally narrowed to a project. Returns full resource bodies so a client can mirror them locally without a follow-up request.
Query Parameters
team_id required403.project_id optionalsince optionalupdated_at > since. Use for delta polling.Response
{
"resources": [
{
"id": "uuid",
"owner_id": "uuid",
"team_id": "uuid",
"project_id": "uuid",
"kind": "recording",
"name": "Recording · Apr 22, 3:45pm",
"duration_ms": 42300,
"options": { "actions": true, "playwright": true, "video": false },
"actions": [ { "type": "click", "target": { ... }, "timestamp": 1200 } ],
"playwright": "import { test, expect } from '@playwright/test';\n\ntest('...')",
"stats": { "actionCount": 18, "pageCount": 3 },
"pages": ["https://example.com/login", "https://example.com/dashboard"],
"file_path": null,
"file_size_bytes": null,
"file_mime_type": null,
"client_id": "7",
"created_at": "2026-04-22T19:45:00Z",
"updated_at": "2026-04-22T19:47:22Z"
}
],
"server_time": "2026-04-22T19:50:10Z"
} /api/resources Auth Required Create a new resource for the caller. If client_id is provided and a row with the same (owner_id, client_id) already exists, the existing row is updated instead of a duplicate being inserted — this makes retries idempotent for the Chrome extension's push pipeline.
Request Body
team_id requiredproject_id optionalkind optional"recording". Reserved for future types (video, HAR).name optionalduration_ms optionaloptions optionalactions, playwright, video, playwrightAssertions, playwrightWaits, playwrightLocators).actions optionalplaywright optionalstats optional{ actionCount, pageCount }.pages optionalclient_id optionalResponse
{
"resource": { /* same shape as GET /api/resources */ },
"deduped": true // only present when matched on client_id and updated
} /api/resources/:id Auth Required Fetch a single resource by id. Returns 404 if the resource does not exist or belongs to a different user.
/api/resources/:id Auth Required Update whitelisted fields of a resource. Owner-only. Immutable: owner_id, team_id, created_at, client_id.
Request Body (any subset)
nameplaywrightnull to clear.project_idactionsoptions, stats, pages/api/resources/:id Auth Required Delete a resource. Owner-only. Also removes any associated file in the user-resources storage bucket.
/api/ai/chat Auth Required Send a message to the AI Assistant. The assistant is context-aware — it has access to your workspace's bug data, projects, Jira connection status, custom AI instructions, and uploaded knowledge documents (product specs, testing playbooks, etc.). It can answer questions about your bugs, suggest testing strategies, and guide you through creating bug reports via text or voice.
Request Body
message requiredhistory optional{"role": "user"|"assistant", "content": "..."}. Max 40 entries, 100K total characters.Response
The endpoint content-negotiates the response transport on the Accept header.
{"response": "You have 12 open critical bugs. The most recent is..."} Send Accept: text/event-stream to receive a Server-Sent Events stream of Anthropic content_block_delta events as Claude generates the response. Useful for live token-by-token rendering. The buffered JSON form remains the default for any caller that doesn't request streaming.
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"You "}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"have 12 "}}
... message_stop event ends the stream Notes
- Powered by Claude Sonnet. Responses are professional, concise, and emoji-free.
- The assistant is scoped to your current workspace's data only.
- Context-aware: automatically includes custom AI instructions and uploaded knowledge documents (product specs, testing playbooks, etc.) configured in Settings.
- Supports voice-to-text input via Whisper transcription for long recording sessions (up to 20+ minutes).
- History role values are validated server-side. Only
userandassistantroles are accepted. - Off-topic questions (politics, opinions, etc.) are politely redirected.
/api/ai/create-report Auth Required Create a report via the AI Assistant. Supports all 19 report types including bugs, feature requests, enhancements, technical debt, and more. This endpoint is typically called automatically when the assistant completes a guided report creation flow. It verifies team membership and project ownership before creating the report.
Request Body
title requireddescription requiredtype optionalui, performance, crash, security, logic, data, network, accessibility, compatibility, functional, ui-ux, data-integrity, feature-request, enhancement, technical-debt, documentation, devops, ux-improvement, integration. Auto-classified if omitted.severity optionals1 (Blocker), s2 (Critical), s3 (Major, default), s4 (Minor). Legacy values still accepted: critical, high, medium, low.project_id optionalinternal_notes optionalenvironment optional{"browser": "...", "os": "...", "device": "..."}sync_to_jira optionalfalse.attachments optional{"filename": "...", "mimeType": "image/png", "data": "base64..."}. Max 400 MB per file. Accepted MIME types: any image/*, video/*, audio/*, application/pdf, text/plain, text/csv, text/markdown, or application/json.Response
{
"success": true,
"id": "uuid",
"title": "Login button unresponsive on mobile",
"type": "ui",
"severity": "high",
"attachments_count": 2,
"jira_key": "PROJ-42"
} Security
- Verifies the authenticated user is a member of the current workspace before creating the report.
- Project ID is validated against the workspace. Cross-workspace report creation is blocked.
- Attachment MIME types are restricted to any image, video, audio, PDF, or text/JSON file. Max 400 MB per file.
/api/claude/push Auth Required Generate (or regenerate) the Developer Notes for a bug report. Returns a structured analysis including probable cause, affected areas, suggested fix, verification steps, and risk assessment. Stored on the bug report and auto-regenerates on creation — this endpoint exists for manual regenerate (retry, or after the user edits the description or attachments). Uses the platform Anthropic key, so no per-team Claude connection is required.
Internally runs a multi-step chain that adapts to severity. Medium/low bugs get the three-step chain: Sonnet drafts, a powerful OpenAI model (default gpt-5) critiques the draft as a skeptical peer reviewer, and Sonnet synthesizes the final notes. Critical/high bugs escalate to the five-step debate chain: after the critique, Sonnet writes a point-by-point rebuttal, then a different-model adjudicator (default claude-opus-4-5) reads the full transcript and writes the final notes with independent judgment. Each round is persisted for audit — see the Response + bug_reports column notes below.
Graceful degradation at every step: if OPENAI_API_KEY is missing or the challenger call fails the draft is used as the final answer and critique is null. If the adjudicator call fails the chain falls back to the simple synthesis path. You always get useful notes, never a hard error.
Request Body
report_id requiredResponse
{
"analysis": "## Probable Root Cause\n...",
"pushed_at": "2026-03-22T14:30:00Z"
} Response (additional fields)
draftclaude_draft_analysis.critiquenull when the challenge step was skipped (missing OPENAI_API_KEY, disabled via DEVNOTES_CHALLENGER_ENABLED=false, or an API error — draft is then used as the final answer).rebuttals1/critical or s2/high). null otherwise or when the debate chain couldn't adjudicate.challenger_modelgpt-5). null when the step was skipped.adjudicator_modelclaude-opus-4-5). null when the debate path didn't run or the adjudicator call failed.debatedtrue if the full debate chain (critique → rebuttal → adjudicator) produced the final notes, false otherwise.Notes
- No per-team Claude connection required. The platform
ANTHROPIC_API_KEYandOPENAI_API_KEYare used directly. - Auto-fires on bug creation (via POST /ai/create-report and the failed-automation auto-bug-creation path). You only need this endpoint for manual regenerate.
- Stored on the bug record (see GET /reports/:id) as
claude_analysis(final),claude_draft_analysis(pre-challenger),claude_challenger_critique(peer review),claude_challenger_model,claude_pushed_at, andclaude_status(analyzing/done/failed). - Regenerating clears
dev_notes_stale(the flag that lights up the "Regenerate?" banner in the dashboard when the description or attachments have changed since the last run). - Cost: ~3x a single-shot call (draft + critique + synthesis). Latency: ~10-15s on a fresh report. Auto-fire is fire-and-forget so this doesn't block the UI.
- Available on Pro, Team, and Enterprise plans.
/api/claude/fix-area Auth Required Generate (or regenerate) the Likely Fix Area for a bug report — a narrow Sonnet output that points at the part of the codebase where the fix most likely belongs. Auto-fires on bug creation; this endpoint exists for the in-UI retry button and for external callers that want to regenerate. Uses the platform Anthropic key, so it does not require a per-team Claude connection. When the team has a github_connections row and the project has github_repo mapped, the output is grounded in the top keyword-matched files from that repo; otherwise it falls back to general guidance with a nudge to connect a repo. Writes the result back onto bug_reports asynchronously — the response returns 202 immediately, clients poll GET /reports/:id.
Request Body
report_id requiredResponse
{
"status": "analyzing"
} Resulting fields on bug_reports
likely_fix_arealikely_fix_area_status = "failed".likely_fix_area_statusanalyzing | done | failed. Null when the analysis has never been attempted.likely_fix_area_generated_atlikely_fix_area.Notes
- No
claude_connectionsrow is required. The endpoint usesANTHROPIC_API_KEYon the platform side. - Auto-fires from POST /ai/create-report and from the failed-automation auto-bug-creation path. You only need to call this endpoint for manual retry / regenerate.
- Repo-grounded output requires (a)
github_connections.access_tokenon the team and (b)github_repoon the bug's project. Without either, the output is a general-speculation fallback with a "connect a repo" suggestion in the first bullet. - The Dashboard uses Sonnet 4 (
claude-sonnet-4-20250514). Costs are on the platform, not the caller's team. - Available on Pro, Team, and Enterprise plans (matches the Developer Notes card gating).
/api/sessions/capture Auth Required Submit a session recording captured by the bugAgent SDK. The SDK records the last 60 seconds of user activity — clicks, navigation, errors, and network failures — and sends the data to this endpoint. The AI then analyzes the session to help auto-draft bug reports. Available on Pro, Team, and Enterprise plans.
Request Body
events required{"type": "click"|"navigation"|"error"|"network", "timestamp": "ISO8601", "data": {...}}duration_ms requiredproject_id optionalurl optionalenvironment optional{"browser": "...", "os": "...", "device": "..."}Response
{
"id": "uuid",
"duration_ms": 58200,
"event_count": 34,
"created_at": "2026-03-19T14:30:00Z"
} Notes
- Requires Pro, Team, or Enterprise plan. Free plan users receive a
403error. - Maximum payload size: 5 MB per session capture.
- Sessions are retained for 30 days (Pro/Team) or configurable on Enterprise.
/api/sessions Auth Required List SDK sessions for the current workspace. Supports pagination and filtering.
Query Parameters
project_id optionalreport_id optionallimit optionaloffset optionalResponse
{
"sessions": [
{
"id": "uuid",
"duration_ms": 58200,
"event_count": 34,
"url": "https://app.example.com/checkout",
"report_id": null,
"created_at": "2026-03-19T14:30:00Z"
}
],
"total": 42
} /api/sessions/:id Auth Required Get full detail of a SDK session, including all recorded events. Use this to render the session timeline or feed the events into the AI for analysis.
Response
{
"id": "uuid",
"duration_ms": 58200,
"event_count": 34,
"url": "https://app.example.com/checkout",
"environment": {"browser": "Chrome 120", "os": "macOS 15"},
"report_id": null,
"events": [
{"type": "click", "timestamp": "2026-03-19T14:29:02Z", "data": {"selector": "#checkout-btn"}},
{"type": "error", "timestamp": "2026-03-19T14:29:03Z", "data": {"message": "TypeError: Cannot read property..."}}
],
"created_at": "2026-03-19T14:30:00Z"
} /api/sessions Auth Required Attach a SDK session to an existing bug report. This links the session data to the report so reviewers can see what the user did in the 60 seconds before the bug was filed.
Request Body
session_id requiredreport_id requiredResponse
{
"success": true,
"session_id": "uuid",
"report_id": "uuid"
} Notes
- Both the session and the report must belong to the same workspace.
- A session can only be attached to one report. Re-attaching overwrites the previous link.
/api/team-booster Auth Required Instantly scale your QA team with booster testers. Accounts are provisioned automatically with tester access. Pro and Team plans only. Free plan returns 403. You will not be charged until approval has been given.
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
team_size | integer | Yes | Number of tester accounts to provision (1–10) |
location | string | Yes | Geographic location for testers (e.g. “US”, “EU”, “APAC”) |
duration | string | Yes | Duration of the engagement (e.g. “1 week”, “1 month”) |
product_url | string | No | URL of the product to be tested |
product_types | string[] | No | Types of products (e.g. ["web app", "mobile app"]) |
tech_levels | string[] | No | Technical levels required (e.g. ["junior", "senior"]) |
budget | string | Yes | Budget for the engagement (e.g. “$500”, “$2000/month”) |
Response
{ "success": true, "created": 5 } Error Responses
{ "error": "Team Booster is available on Pro and Team plans only." } /api/admin/changelog Public List all changelog entries, most recent first. Also available as an RSS feed.
Response
{
"entries": [
{
"id": "uuid",
"title": "REST API parity with MCP tools",
"summary": "Added 12 new REST API endpoints...",
"content": "Detailed markdown content...",
"tags": ["api", "new-feature"],
"published_at": "2026-03-17T12:46:28Z"
},
...
]
} /api/test-cases Auth Required List test cases for the authenticated user's team. Supports search, filtering by priority, type, and status, sorting, and pagination.
Query Parameters
search optionalpriority optionalcritical, high, medium, lowtype optionalfunctional, regression, smoke, integration, e2e, performance, security, usability, accessibilitystatus optionalactive, draft, deprecatedsort optionalnewest, oldest, name, priority (default: newest)page optionalper_page optionalResponse
{
"cases": [
{
"id": "uuid",
"name": "Verify checkout with discount code",
"description": "Ensure discount codes apply correctly",
"priority": "high",
"type": "functional",
"status": "active",
"tags": ["checkout", "discounts"],
"estimated_time": 300,
"steps_count": 5,
"project_id": "uuid",
"created_at": "2026-03-25T10:00:00Z",
"updated_at": "2026-03-25T10:00:00Z"
}
],
"total": 42,
"page": 1,
"per_page": 20
} /api/test-cases Auth Required Create a new test case. Two template variants: steps (default) — per-step Action + Expected Result grid (pass steps); text — single free-form description of the steps (pass text_content). Both columns can be sent in the same call; the row stores them independently so a tester switching templates later doesn't lose either side's data.
Request Body
name requireddescription optionalpreconditions optionaltemplate_type optionalsteps (default) or text. Drives which template the dashboard shows on the case detail page. Both fields can be populated regardless; the platform stores both so template flips are non-destructive.steps optional{ "action": "Click login", "expected": "Login form appears" }. Used when template_type is steps.text_content optionaltemplate_type is text.priority optionalcritical, high, medium (default), lowtype optionalfunctional (default), regression, smoke, integration, e2e, performance, security, usability, accessibilitytags optionalestimated_time optionalproject_id optionalResponse
{
"id": "uuid",
"name": "Verify checkout with discount code",
"description": "Ensure discount codes apply correctly",
"preconditions": "User is logged in with items in cart",
"steps": [
{ "order": 1, "action": "Navigate to cart", "expected": "Cart page loads with items" },
{ "order": 2, "action": "Enter code SAVE20", "expected": "20% discount applied" },
{ "order": 3, "action": "Click checkout", "expected": "Order total reflects discount" }
],
"priority": "high",
"type": "functional",
"status": "active",
"tags": ["checkout", "discounts"],
"estimated_time": 300,
"project_id": "uuid",
"created_at": "2026-03-25T10:00:00Z",
"updated_at": "2026-03-25T10:00:00Z"
} /api/test-cases/:id/attachments Auth Required Upload an attachment file to a test case. Multipart/form-data with a single file field per request. Stored in the test-case-attachments Supabase Storage bucket; metadata appended to the case's attachments jsonb column.
Constraints
- Max 10 attachments per case (per-case cap, enforced server-side).
- Max 256 MB per file (per-file cap, enforced both by the API and the storage bucket).
- Allowed MIME types: image (png/jpeg/gif/webp/svg/heic/avif), application/pdf, doc/docx, xls/xlsx/csv, OpenDocument text/spreadsheet, text/plain, text/markdown, video (mp4/webm/quicktime/avi), audio (mp3/wav/ogg/webm/m4a/mp4).
Response
{ "attachment": { "id": "uuid", "filename": "shot.png", "mime_type": "image/png", "size": 12345, "storage_path": "team_id/case_id/file_id_shot.png", "public_url": "https://.../storage/v1/object/public/test-case-attachments/...", "uploaded_at": "...", "uploaded_by": "user_id" }, "attachments_count": 1 } /api/test-cases/:id/attachments/:attachment_id Auth Required Remove an attachment from a test case. Deletes the file from storage AND strips the row out of the attachments jsonb. Storage delete runs first; if it fails (other than "not found"), metadata is left in place so the user can retry.
Response
{ "removed": "attachment_id", "attachments_count": 0 } /api/test-cases/:id Auth Required Get a test case by ID with its full steps and execution history.
Response
{
"id": "uuid",
"name": "Verify checkout with discount code",
"description": "Ensure discount codes apply correctly",
"preconditions": "User is logged in with items in cart",
"steps": [
{ "order": 1, "action": "Navigate to cart", "expected": "Cart page loads with items" },
{ "order": 2, "action": "Enter code SAVE20", "expected": "20% discount applied" }
],
"priority": "high",
"type": "functional",
"status": "active",
"tags": ["checkout", "discounts"],
"estimated_time": 300,
"project_id": "uuid",
"history": [
{ "run_id": "uuid", "run_name": "Sprint 12 Regression", "status": "passed", "executed_at": "2026-03-24T14:00:00Z" }
],
"created_at": "2026-03-25T10:00:00Z",
"updated_at": "2026-03-25T10:00:00Z"
} /api/test-cases/:id Auth Required Update any field of a test case. Only provided fields are changed.
Request Body
name optionaldescription optionalpreconditions optionaltemplate_type optionalsteps or text. Switches the surface shown on the case detail page. Both steps and text_content stay populated through the switch — the platform stores them independently so flips are non-destructive.steps optionaltext_content optionaltemplate_type is text. Multi-line OK; an empty string normalises to null.priority optionalcritical, high, medium, lowtype optionalstatus optionalactive, draft, deprecatedtags optionalurls optionalestimated_time optionalResponse
{ "id": "uuid", "name": "Updated name", ... } /api/test-cases/:id Auth Required Permanently delete a test case. Removes it from all suites.
Response
{ "success": true } /api/test-cases/duplicate Auth Required Duplicate an existing test case including all steps, tags, and metadata. The copy is created with the name prefix "[Copy]".
Request Body
case_id requiredResponse
{ "id": "uuid", "name": "[Copy] Verify checkout with discount code", ... } /api/test-cases/bulk Auth Required Apply one action to up to 500 test cases at once. IDs not in the caller's team are silently skipped (counted in the skipped response field). Used by the bulk toolbar on the Cases tab and the bulk_update_test_cases MCP tool.
Request Body
ids requiredaction requiredset_priority, set_status, set_type, set_folder, add_tags, remove_tags, add_to_suite, pin, unpinparams action-dependentaction:•
set_priority: { priority: "critical"|"high"|"medium"|"low" }•
set_status: { status: "active"|"draft"|"deprecated" }•
set_type: { type: "functional"|...|"exploratory" } (must match the DB CHECK — e2e and other are NOT accepted; use integration or functional)•
set_folder: { folder_id: "uuid" | null } (null unfiles)•
add_tags/remove_tags: { tags: ["..."] }•
add_to_suite: { suite_id: "uuid" }•
pin/unpin: no params
Response
{ "applied": 47, "skipped": 3, "errors": [] } /api/test-cases/:id/links Auth Required List traceability links on a single test case — bug reports the case verifies, covers, or relates to. Established via link_test_case_to_bug (MCP) or the Links tab on the case detail page.
Response
{
"links": [
{
"id": "uuid",
"linked_type": "bug_report",
"linked_id": "uuid",
"relation": "verified_by", // "verified_by" | "covers" | "relates"
"created_at": "..."
}
],
"total": 1
} /api/test-cases/review-candidates Auth Required Informational list of test cases the system flags as archive candidates. Computed by the find_dead_test_cases RPC; the same flags are persisted onto test_cases.review_flag every Monday at 09:00 UTC by pg_cron. Drives the "Archive candidates" section on the Reports tab.
Response
{
"never_run": [ { "id": "uuid", "name": "...", "reason": "no runs in 90+ days since creation" } ],
"always_passes": [ { "id": "uuid", "name": "...", "reason": "5+ runs in last 90d, all passed" } ],
"always_skipped": [ { "id": "uuid", "name": "...", "reason": "3+ runs in last 90d, all skipped" } ],
"total": 12
} /api/test-cases/import/figma/request Auth Required Step 1 of the Figma zip import flow. Validates inputs, (optionally) creates a new folder, inserts a figma_import_jobs row with status uploading, and returns a signed upload URL the client PUTs the zip to directly. Max 100 MB. Uses the platform Anthropic key server-side — no per-team Claude connection is required.
Request Body
{
"project_id": "uuid | null",
"folder_id": "uuid | null", // pick existing
"new_folder_name": "string | null", // or create one
"project_context": "string", // up to 2000 chars
"depth": "quick | thorough",
"file_name": "designs.zip",
"file_size_bytes": 11345678
}Response
{
"job_id": "uuid",
"folder_id": "uuid | null",
"upload": { "path": "...", "token": "...", "signed_url": "https://..." }
}/api/test-cases/import/figma/start Auth Required Step 2 of the Figma zip import flow. Call after the zip has finished uploading to the signed URL from /request. Verifies the object landed in Storage, flips the job to processing, and signals the MCP worker to begin analysis. Returns 202 Accepted immediately — processing runs asynchronously; poll GET /api/test-cases/import/figma/:id for progress.
Request Body
{ "job_id": "uuid" }Response
{ "ok": true, "job_id": "uuid" }/api/test-cases/import/figma/:id Auth Required Poll the status of a Figma import job. Clients call this every 2 s while the modal progress bar is open. Scoped to the caller's team; returns 403 for other teams' jobs.
Response
{
"job": {
"id": "uuid",
"status": "queued | uploading | processing | completed | failed | cancelled",
"progress_phase": "classifying",
"progress_current": 7,
"progress_total": 12,
"progress_message": "Classifying 12 unique frames",
"total_frames": 34,
"unique_frames": 12,
"test_cases_created": 0,
"cost_cents": 0,
"error": null,
"file_name": "designs.zip",
"started_at": "2026-04-20T20:15:00Z",
"completed_at": null,
"created_at": "2026-04-20T20:14:48Z"
}
}/api/test-suites Auth Required List test suites for the authenticated user's team. Returns each suite with its case count and last run status.
Query Parameters
search optionalpage optionalper_page optionalResponse
{
"suites": [
{
"id": "uuid",
"name": "Checkout Regression Suite",
"description": "All checkout-related test cases",
"case_count": 12,
"last_run_status": "passed",
"project_id": "uuid",
"created_at": "2026-03-25T10:00:00Z"
}
],
"total": 8
} /api/test-suites Auth Required Create a new test suite to group related test cases.
Request Body
name requireddescription optionalproject_id optionalResponse
{
"id": "uuid",
"name": "Checkout Regression Suite",
"description": "All checkout-related test cases",
"case_count": 0,
"project_id": "uuid",
"project_slug": "checkout-team",
"created_at": "2026-03-25T10:00:00Z"
} /api/test-suites/:id Auth Required Get a test suite by ID with its full list of cases in order.
Query Parameters
include_descendants optional1 to also return metadata for every descendant sub-suite plus deduped case counts. When enabled, the response includes descendant_suites[], descendant_case_count (cases in sub-suites that aren’t already in this suite), and total_case_count. Useful for run-creation previews.Response
{
"id": "uuid",
"name": "Checkout Regression Suite",
"description": "All checkout-related test cases",
"cases": [
{ "id": "uuid", "name": "Verify checkout with discount code", "priority": "high", "type": "functional", "order": 1 }
],
"project_id": "uuid",
"created_at": "2026-03-25T10:00:00Z"
} /api/test-suites/:id Auth Required Update a test suite's name or description.
Request Body
name optionaldescription optionalResponse
{ "id": "uuid", "name": "Updated Suite Name", ... } /api/test-suites/:id Auth Required Delete a test suite. Test cases within the suite are not deleted.
Response
{ "success": true } /api/test-suites/:id/cases Auth Required Add one or more test cases to a suite.
Request Body
case_ids requiredResponse
{ "added": 3, "case_count": 15 } /api/test-suites/:id/cases Auth Required Remove a test case from a suite.
Request Body
case_id requiredResponse
{ "success": true, "case_count": 14 } /api/test-suites/:id/reorder Auth Required Reorder the test cases within a suite. Provide the full ordered list of case IDs.
Request Body
ordered_case_ids requiredResponse
{ "success": true } /api/test-suites/reorder Auth Required Reorder sibling test suites under a shared parent (or root-level suites). Used by the drag-and-drop reorder in the Suites tab tree. All suites in the request must belong to the same parent — cross-parent reorders are rejected with HTTP 400.
Request Body
parent_suite_id requirednull for root-level suites.ordered_suite_ids requiredsort_order is rewritten as the array index for each.Response
{ "success": true, "count": 5 } /api/test-case-folders Auth Required List folders for the authenticated team. Folders organize test cases hierarchically (one folder per case via folder_id) and are distinct from suites, which are many-to-many test plan groupings. Returns the full set (capped at 500) since folder trees are usually small and the entire tree is needed to render correctly.
Query Parameters
project optionalparent optionalroot — Direct children of the given folder, or top-level folders when set to rootResponse
{
"test_case_folders": [
{
"id": "uuid",
"name": "Smoke Tests",
"description": "",
"parent_folder_id": null,
"depth": 0,
"sort_order": 0,
"project_id": "uuid",
"case_count": 12,
"created_at": "2026-04-19T...",
"updated_at": "2026-04-19T..."
}
],
"total": 1
} /api/test-case-folders Auth Required Create a new folder. Pass parent_folder_id to nest it; folders can nest up to 3 levels deep.
Request Body
name requireddescription optionalparent_folder_id optionalproject_id optional/api/test-case-folders/reorder Auth Required Reorder sibling folders under a shared parent (or root-level folders). Used by the drag-and-drop reorder in the Cases-tab folder sidebar. Mirrors /api/test-suites/reorder — same validation, same shape, against the folder table instead.
Request Body
parent_folder_id requirednull for root-level folders.ordered_folder_ids requiredsort_order is rewritten as the array index for each.Response
{ "success": true, "count": 5 } /api/test-runs Auth Required List test runs for the authenticated user's team. Returns each run with suite name, assignee, and pass/fail summary.
Query Parameters
search optionalstatus optionalin_progress, completedsuite_id optionalpage optionalper_page optionalResponse
{
"runs": [
{
"id": "uuid",
"name": "Sprint 12 Regression",
"suite_id": "uuid",
"suite_name": "Checkout Regression Suite",
"status": "in_progress",
"assigned_to": "uuid",
"assignee_name": "Jane Smith",
"summary": { "total": 12, "passed": 8, "failed": 2, "blocked": 1, "skipped": 0, "untested": 1 },
"created_at": "2026-03-25T10:00:00Z"
}
],
"total": 5
} /api/test-runs Auth Required Create a new test run from a test suite. Snapshots all cases at creation time. If the suite has sub-suites, every descendant sub-suite's cases are included too — running a parent suite executes its whole subtree. Each case is added exactly once (parent suite wins if a case is linked to both a parent and a sub-suite) and each row in the resulting test_run_results records which sub-suite it came from.
If any cases have a per-case assignee, an in-app bell notification AND a digest email are sent to each assignee. Emails respect the per-user opt-out at notification_preferences.email_test_case_assignment (default on); the in-app bell is always shown.
Request Body
suite_id requiredname requiredassigned_to optionalResponse
{
"id": "uuid",
"name": "Sprint 12 Regression",
"suite_id": "uuid",
"status": "in_progress",
"assigned_to": "uuid",
"results": [
{ "case_id": "uuid", "case_name": "Verify checkout with discount code", "status": "untested" }
],
"created_at": "2026-03-25T10:00:00Z"
} /api/test-runs/:id Auth Required Get a test run by ID with all case results. Each entry in results[] includes suite_id and case_suite_name identifying the sub-suite the case was pulled from at run-creation time — useful for grouping results by origin on a run-detail page.
Response
{
"id": "uuid",
"name": "Sprint 12 Regression",
"suite_id": "uuid",
"suite_name": "Checkout Regression Suite",
"status": "in_progress",
"assigned_to": "uuid",
"assignee_name": "Jane Smith",
"results": [
{
"case_id": "uuid",
"case_name": "Verify checkout with discount code",
"status": "passed",
"actual_result": "Discount applied correctly",
"notes": "",
"executed_at": "2026-03-25T11:00:00Z"
}
],
"summary": { "total": 12, "passed": 8, "failed": 2, "blocked": 1, "skipped": 0, "untested": 1 },
"created_at": "2026-03-25T10:00:00Z"
} /api/test-runs/:id Auth Required Update a test run's name, assignee, or status.
Request Body
name optionaldescription optionalassigned_to optionalstatus optionalarchived on a run that is already archived short-circuits to a no-op 200 { id, status: "archived", already_archived: true } so retries are idempotent. The dashboard UI hides the Archive Run button on archived runs so this path is only reachable from MCP / scripts / direct API callers.Response
{ "id": "uuid", "name": "Updated Run Name", ... } /api/test-runs/:id/results Auth Required Save the execution result for a specific test case in a run. Mark each case as passed, failed, blocked, or skipped.
Request Body
case_id requiredstatus requiredpassed, failed, blocked, skippedactual_result optionalnotes optionaltest_run_results.notes and surfaced inline on the run carousel; never synced to Jira.Response
{ "success": true, "status": "failed", "case_id": "uuid", "notes": "..." } /api/test-runs/:id/results Auth Required Reassign a single test case inside an active run. Updates test_run_results.assigned_to for the matching case_id. When the new assignee is a real user and differs from the previous one, the recipient gets a bell-icon message and an email notification. Re-saving the same assignee or unassigning (null) is silent.
Request Body
case_id requiredassigned_to requirednull to unassignResponse
{ "success": true, "case_id": "uuid", "assigned_to": "uuid-or-null" } /api/test-runs/:id/results/attachments Auth Required Attach screenshots, screen recordings, or other evidence files to a single test case during run execution. Files are stored in the team's bug-attachments bucket and the metadata is appended to test_run_results.attachments (jsonb). The result row must already exist (the case has been marked passed/failed/blocked/skipped) — the endpoint returns 409 if it doesn't.
Request
Multipart form data:
case_id requiredfiles requiredResponse
{
"success": true,
"attachments": [
{
"id": "uuid",
"storage_path": "team-id/test-runs/run-id/case-id/uuid_screenshot.png",
"filename": "screenshot.png",
"url": "https://....supabase.co/storage/v1/.../screenshot.png",
"type": "image",
"mimeType": "image/png",
"size": 86552,
"uploaded_at": "2026-05-09T14:00:00Z",
"uploaded_by": "user-uuid"
}
],
"added": [ /* just the new attachments from this request */ ]
} /api/test-runs/:id/results/attachments Auth Required Remove a single attachment from a test case result. Deletes both the file in storage and the metadata entry. Returns the updated attachments list.
Request Body
case_id requiredattachment_id requiredid returned from the POST)Response
{ "success": true, "attachments": [ /* remaining attachments */ ] } /api/test-runs/:id/complete Auth Required Mark a test run as completed. Calculates and stores the final pass rate.
Response
{
"id": "uuid",
"status": "completed",
"summary": { "total": 12, "passed": 10, "failed": 2, "blocked": 0, "skipped": 0, "untested": 0 },
"pass_rate": 83.3,
"completed_at": "2026-03-25T15:00:00Z"
} /api/test-runs/:id/rerun-failed Auth Required Create a new test run containing only the failed cases from a completed run. Useful for re-testing after fixes.
Response
{
"id": "uuid",
"name": "Re-run: Sprint 12 Regression (failed)",
"suite_id": "uuid",
"status": "in_progress",
"results": [
{ "case_id": "uuid", "case_name": "Apply expired discount code", "status": "untested" }
],
"created_at": "2026-03-25T16:00:00Z"
} /api/test-reports Auth Required Get completed test run reports with pass rate and date range filtering. Returns aggregated test execution data.
Query Parameters
from optionalto optionalsuite_id optionalResponse
{
"reports": [
{
"run_id": "uuid",
"run_name": "Sprint 12 Regression",
"suite_name": "Checkout Regression Suite",
"status": "completed",
"pass_rate": 83.3,
"summary": { "total": 12, "passed": 10, "failed": 2, "blocked": 0, "skipped": 0 },
"completed_at": "2026-03-25T15:00:00Z"
}
],
"total": 15,
"average_pass_rate": 87.5
} /api/test-reports/overview Auth Required Aggregated quality KPIs + a weekly pass-rate trend for the Reports tab. Returns the current-period totals AND the prior equivalent-length period so the UI can render delta arrows.
Query Parameters
from optionalto optionalproject optionalsuite optionalget_suite_descendants)Response
{
"range": { "from": "...", "to": "...", "previous_from": "...", "previous_to": "..." },
"kpis": {
"pass_rate": { "current": 82, "previous": 78, "delta": 4 },
"runs_completed": { "current": 12, "previous": 8, "delta": 4 },
"avg_run_duration_seconds": { "current": 1840, "previous": 2100, "delta": -260 },
"cases_executed": { "current": 245, "previous": 198, "delta": 47 }
},
"trend": {
"buckets": ["2026-04-06", "2026-04-13", "2026-04-20"],
"pass_rate": [78, 80, 82],
"runs": [3, 4, 5],
"cases_executed": [50, 65, 70]
},
"capped": false
} /api/test-reports/failures Auth Required Failure analysis for the Reports tab — four parallel "what to fix this week?" lists.
flaky_cases— cases that flip between pass/fail in the period (sorted by flip count)failing_cases— pass rate < 50% with at least 3 runs (noise filter)failing_suites— same logic at suite level viatest_run_results.suite_idregressed_cases— most-recent execution failed but the period contained an earlier pass
Query Parameters
from optionalto optionalproject optionalsuite optionalResponse
{
"flaky_cases": [
{ "id": "uuid", "name": "Login redirects to dashboard",
"suite_name": "Auth", "flips": 4,
"pass_count": 3, "fail_count": 5, "total_runs": 8 }
],
"failing_cases": [
{ "id": "uuid", "name": "Coupon stacks past expiry",
"suite_name": "Billing/Checkout", "fail_rate": 67,
"fail_count": 4, "total_runs": 6, "last_failed_at": "..." }
],
"failing_suites": [
{ "id": "uuid", "name": "Billing", "fail_rate": 32,
"fail_count": 11, "total_runs": 34 }
],
"regressed_cases": [
{ "id": "uuid", "name": "...", "suite_name": "...",
"last_failed_at": "...",
"pass_count": 2, "fail_count": 1, "total_runs": 3 }
]
} /api/test-reports/suite-health Auth Required One row per suite that had activity in the period, with the metrics needed to spot "where's the rot?" at a glance: pass rate (current + previous), trend ▲▼→, runs completed, cases executed, last run, and open bug count. Suites are sorted worst-pass-rate first so the most-broken suite is at the top. Idle suites (no runs in the current period) are excluded.
Query Parameters
from optionalto optionalproject optionalsuite optionalget_suite_descendants)Response
{
"suites": [
{
"id": "uuid",
"name": "Billing",
"depth": 0,
"parent_suite_id": null,
"pass_rate": 71,
"pass_rate_previous": 84,
"trend": "down", // up | down | flat | new
"runs_completed": 8,
"cases_executed": 96,
"fail_count": 28,
"last_run_at": "2026-04-20T...",
"open_bugs": 4
}
]
} Notes
- Suite attribution uses
test_run_results.suite_id(added in migration 106), which records the originating sub-suite per result — exact, not a lossy join throughtest_suite_cases. - Trend compares the current pass rate to the same metric over the prior equivalent-length window.
up/downrequire a ±3% change; smaller deltas areflat.newmeans the suite had no runs in the prior window. - Open bugs are
bug_reportslinked from any result in the period whose status is notclosedorresolved.
/api/test-reports/coverage Auth Required Catalog hygiene report. Answers "what have I NOT been testing?" via three coordinated views: workspace-level KPIs, a staleness distribution across six time buckets, and a per-suite coverage rollup. Idle suites and deprecated cases are excluded.
Query Parameters
from optionalto optionalproject optionalsuite optionaltest_suite_cases to the suite + descendants (via get_suite_descendants)Response
{
"range": { "from": "...", "to": "..." },
"kpis": {
"total_active_cases": 250,
"covered_cases": 195, // ≥1 execution in [from,to]
"coverage_pct": 78,
"untouched_in_period": 55,
"never_run": 12 // no execution EVER, not just in period
},
"buckets": [
{ "label": "Never run", "key": "never", "count": 12 },
{ "label": "Last 7 days", "key": "lt7", "count": 120 },
{ "label": "8–30 days ago", "key": "lt30", "count": 75 },
{ "label": "31–90 days ago", "key": "lt90", "count": 27 },
{ "label": "91–180 days ago", "key": "lt180", "count": 10 },
{ "label": "Older than 180 days", "key": "gt180", "count": 6 }
],
"suite_coverage": [
{
"id": "uuid",
"name": "Billing/Checkout",
"depth": 1,
"total_cases": 18,
"covered_cases": 4,
"coverage_pct": 22,
"stale_count": 14,
"last_activity_at": "..."
}
]
} Definitions
- Active =
test_cases.status = 'active'. Drafts (work in progress) and deprecated (intentionally retired) cases are excluded. - Covered in period = at least one
test_run_resultsrow withexecuted_atin[from, to]and status notuntested. - Never run = no
test_run_resultsrow in the entire history (catalog hygiene metric, not period-scoped). - Bucket order: rows are evaluated in array order, first match wins — so the
neverbucket is checked before any numeric range. - suite_coverage uses cases linked to the suite via
test_suite_cases(the test-plan relationship), nottest_cases.folder_id(the organizational hierarchy). A case can appear under multiple suites; it counts once per suite. Sorted bycoverage_pctascending; capped at 25 entries.
/api/test-reports/tester-productivity Auth Required Per-tester rollup useful for capacity planning, bottleneck detection, and bug-finding effectiveness. Sorted by cases_executed descending. A user shows up if either they appear as test_run_results.tester_id in the period or they were assigned a run created in the period (so a tester with zero executions but assigned work still surfaces — that's the bottleneck signal).
Query Parameters
from optionalto optionalproject optionalsuite optionalget_suite_descendants)Response
{
"range": { "from": "...", "to": "..." },
"totals": {
"active_testers": 5, // testers with ≥1 execution
"cases_executed": 450,
"bugs_filed": 12 // distinct bugs linked from results
},
"testers": [
{
"id": "uuid",
"name": "Jason H.",
"email": "jason@...",
"cases_executed": 145,
"passed": 120, "failed": 18, "blocked": 4, "skipped": 3,
"pass_rate": 83, // INFORMATIONAL — see notes
"avg_duration_seconds": 240,
"runs_assigned": 8,
"runs_assigned_completed": 6,
"bugs_filed": 4,
"last_active_at": "..."
}
]
} Definitions & caveats
- cases_executed =
test_run_resultswith thistester_id, executed in[from, to], status notuntested. - avg_duration_seconds excludes any per-case duration above 24h to defend against forgotten timers skewing the average. Result rows with no recorded duration are omitted from the average entirely (not counted as zero).
- runs_assigned =
test_runswithassigned_to = this userANDcreated_atin the period.runs_assigned_completed= those whose status iscompleted. - bugs_filed counts only bug reports linked from results this tester executed (
test_run_results.bug_report_id). Standalone bug reports filed outside test runs (Bugs tab, MCP, browser extension) are NOT counted — this metric is about testing output, not bug filing in general. - pass_rate per tester is informational only. It mostly reflects which cases that tester was assigned. Treat it as a secondary signal, not a quality leaderboard.
- Capped at 50 testers; results with no
tester_idattribution are excluded.
/api/test-reports/export.pdf Auth Required One-click PDF export of the QA Reports dashboard, suitable for stakeholder distribution. Renders a 3-page brand-styled report covering the most important sections: at-a-glance KPIs & trend, what-to-fix (failing / flaky / regressed cases), and per-suite + per-tester rollups.
Query Parameters
from optionalto optionalproject optionalsuite optionalResponse
A PDF binary with Content-Type: application/pdf and a Content-Disposition: attachment header. The filename includes the date range so saved files stay self-describing: bugagent-qa-report-2026-03-21_2026-04-20.pdf.
Page contents
- Page 1 — At a glance: 4 KPI tiles (pass rate / runs / avg duration / cases executed) with deltas vs the prior equivalent-length window, a pass-rate trend line chart, and a coverage summary (KPIs + staleness distribution bar).
- Page 2 — What to fix: top 5 failing cases (≥50% fail rate), top 5 flaky cases (most pass↔fail flips), top 5 recently regressed cases.
- Page 3 — By suite + by tester: top 12 suites by health (worst pass rate first), top 10 testers by cases run.
/api/geo-snap Auth Required List saved Geo-Snap screenshots. Filter by country, search by URL, and paginate results.
Query Parameters
search optionalcountry optionalUS, DE, JP)sort optionalnewest (default), oldestpage optionalper_page optionalResponse
{
"snaps": [
{
"id": "uuid",
"url": "https://example.com",
"country": "US",
"screenshot_url": "https://storage.bugagent.com/geo-snaps/uuid-us.png",
"status": "completed",
"created_at": "2026-03-25T10:00:00Z"
}
],
"total": 15,
"page": 1,
"per_page": 20
} /api/geo-snap Auth Required Capture screenshots of a URL from one or more countries. Free plan: 1 country per request, 10 saved screenshots. Pro/Team: up to 5 countries per request, unlimited saved screenshots.
Request Body
url requiredcountries required["US", "DE", "JP"]). Free: max 1, Pro/Team: max 5Response
{
"snaps": [
{
"id": "uuid",
"url": "https://example.com",
"country": "US",
"screenshot_url": "https://storage.bugagent.com/geo-snaps/uuid-us.png",
"status": "completed",
"created_at": "2026-03-25T10:00:00Z"
},
{
"id": "uuid",
"url": "https://example.com",
"country": "DE",
"screenshot_url": "https://storage.bugagent.com/geo-snaps/uuid-de.png",
"status": "completed",
"created_at": "2026-03-25T10:00:00Z"
}
]
} /api/geo-snap/:id Auth Required Delete a saved Geo-Snap screenshot by ID.
Path Parameters
id requiredResponse
{ "deleted": true } /api/mobile/apps Auth Required List uploaded mobile apps. Filter by platform, search by name, and paginate results.
Query Parameters
search optionalplatform optionalandroid or iossort optionalnewest (default), oldest, namepage optionalper_page optionalResponse
{
"apps": [
{
"id": "uuid",
"name": "MyApp",
"platform": "android",
"package_name": "com.example.myapp",
"version": "2.1.0",
"file_url": "https://storage.bugagent.com/apps/uuid.apk",
"file_size": 48500000,
"automation_count": 3,
"created_at": "2026-03-20T10:00:00Z"
}
],
"total": 1
} /api/mobile/apps Auth Required Upload an APK (Android) or IPA (iOS) app binary. Uses multipart/form-data. Max file size: 500 MB.
Request Body (multipart/form-data)
file requiredname requiredplatform requiredandroid or iosversion optional2.1.0)package_name optionalcom.example.myapp)Response
{
"id": "uuid",
"name": "MyApp",
"platform": "android",
"package_name": "com.example.myapp",
"version": "2.1.0",
"file_url": "https://storage.bugagent.com/apps/uuid.apk",
"file_size": 48500000,
"created_at": "2026-03-20T10:00:00Z"
} /api/mobile/apps/:id Auth Required Get full details for a mobile app, including automation count.
Path Parameters
id requiredResponse
{
"id": "uuid",
"name": "MyApp",
"platform": "android",
"package_name": "com.example.myapp",
"version": "2.1.0",
"file_url": "https://storage.bugagent.com/apps/uuid.apk",
"file_size": 48500000,
"automation_count": 3,
"created_at": "2026-03-20T10:00:00Z",
"updated_at": "2026-03-20T10:00:00Z"
} /api/mobile/apps/:id Auth Required Update an uploaded mobile app's metadata.
Path Parameters
id requiredRequest Body
name optionalversion optionalpackage_name optionalsimulator_file_url optionalnull to remove.simulator_storage_path optionalResponse
{
"id": "uuid",
"name": "MyApp",
"platform": "android",
"package_name": "com.example.myapp",
"version": "2.1.0",
"file_url": "https://storage.bugagent.com/apps/uuid.apk",
"file_size": 48500000,
"automation_count": 3,
"created_at": "2026-03-20T10:00:00Z",
"updated_at": "2026-03-20T10:00:00Z"
} /api/mobile/apps/:id Auth Required Replace an app's binary with a new version. Deletes the old file from storage, clears cached platform URLs (forcing re-upload on next run), and updates the team's storage quota. All linked automations and schedules will automatically use the new version. For iOS apps, the simulator build is also removed — re-upload it to continue recording.
Path Parameters
id requiredRequest Body
storage_path requiredfile_size optionalversion optionalResponse
{ "id": "uuid", "name": "My App", "platform": "android", "version": "2.0.0", "file_size": 15728640, "updated_at": "2026-03-29T..." } /api/mobile/apps/:id Auth Required Delete an uploaded mobile app and its storage file. Automations referencing this app will be orphaned.
Path Parameters
id requiredResponse
{ "success": true } /api/mobile/automations Auth Required List mobile automation scripts. Filter by app, script type, and status.
Query Parameters
search optionalapp_id optionalscript_type optionalmaestro (YAML), appium (Python), or appium_js (JavaScript)status optionaldraft, active, pausedsort optionalnewest (default), oldest, nameResponse
{
"automations": [
{
"id": "uuid",
"name": "Login Flow Test",
"app_id": "uuid",
"script_type": "maestro",
"status": "active",
"target_devices": [
"Pixel 7",
"Samsung Galaxy S23"
],
"created_at": "2026-03-21T09:00:00Z"
}
],
"total": 1
} /api/mobile/automations Auth Required Create a mobile automation script. Use Appium for complex cross-platform interactions or Maestro YAML for simple flows.
Request Body
name requiredapp_id requiredscript_type requiredmaestro (YAML), appium (Appium Python), or appium_js (Appium JS)script requiredtarget_devices optional["Pixel 7", "Samsung Galaxy S23"])Response
{
"id": "uuid",
"name": "Login Flow Test",
"app_id": "uuid",
"script_type": "maestro",
"script": "appId: com.example.myapp\n---\n- launchApp\n- tapOn: \"Login\"\n- inputText: \"[email protected]\"",
"status": "draft",
"target_devices": [
"Pixel 7",
"Samsung Galaxy S23"
],
"created_at": "2026-03-21T09:00:00Z"
} /api/mobile/automations/:id Auth Required Get full details for a mobile automation, including app info and recent runs.
Path Parameters
id requiredResponse
{
"id": "uuid",
"name": "Login Flow Test",
"app_id": "uuid",
"app_name": "MyApp",
"script_type": "maestro",
"script": "appId: com.example.myapp\n---\n- launchApp\n- tapOn: \"Login\"",
"status": "active",
"target_devices": [
"Pixel 7",
"Samsung Galaxy S23"
],
"recent_runs": [
{
"id": "uuid",
"status": "passed",
"device": "Pixel 7",
"duration_ms": 45000,
"created_at": "2026-03-22T08:00:00Z"
}
],
"created_at": "2026-03-21T09:00:00Z"
} /api/mobile/automations/:id Auth Required Update a mobile automation script or its metadata.
Path Parameters
id requiredRequest Body
name optionalscript optionalstatus optionaldraft, active, or pausedtarget_devices optionalResponse
{
"id": "uuid",
"name": "Login Flow Test",
"app_id": "uuid",
"app_name": "MyApp",
"script_type": "maestro",
"script": "appId: com.example.myapp\n---\n- launchApp\n- tapOn: \"Login\"",
"status": "active",
"target_devices": [
"Pixel 7",
"Samsung Galaxy S23"
],
"recent_runs": [
{
"id": "uuid",
"status": "passed",
"device": "Pixel 7",
"duration_ms": 45000,
"created_at": "2026-03-22T08:00:00Z"
}
],
"created_at": "2026-03-21T09:00:00Z"
} /api/mobile/automations/:id Auth Required Delete a mobile automation. Fails if the automation has active schedules — delete schedules first.
Path Parameters
id requiredResponse
{ "success": true } /api/mobile/runs Auth Required List mobile test runs. Filter by automation and status.
Query Parameters
automation_id optionalstatus optionalqueued, running, passed, failed, erroredsort optionalnewest (default), oldestResponse
{
"runs": [
{
"id": "uuid",
"automation_id": "uuid",
"status": "passed",
"device": "Pixel 7",
"os_version": "14",
"duration_ms": 45000,
"created_at": "2026-03-22T08:00:00Z"
}
],
"total": 1
} /api/mobile/runs Auth Required Trigger a mobile test run. Appium scripts are routed to BrowserStack; Maestro scripts are routed to Maestro Cloud.
Request Body
automation_id requireddevice requiredPixel 7, iPhone 15 Pro)os_version optional14 for Android 14, 17.2 for iOS)Response
{
"id": "uuid",
"automation_id": "uuid",
"status": "queued",
"device": "Pixel 7",
"os_version": "14",
"provider": "browserstack",
"created_at": "2026-03-22T08:00:00Z"
} /api/mobile/runs/:id Auth Required Get full results for a mobile test run, including video recording, Appium logs, device logs, network logs, and duration.
Path Parameters
id requiredResponse
{
"id": "uuid",
"automation_id": "uuid",
"status": "passed",
"device": "Pixel 7",
"os_version": "14",
"provider": "browserstack",
"duration_ms": 45000,
"video_url": "https://storage.bugagent.com/runs/uuid/video.mp4",
"screenshots": [
"https://storage.bugagent.com/runs/uuid/screen_001.png"
],
"logs": "https://storage.bugagent.com/runs/uuid/device.log",
"performance": {
"cpu_avg": 23.5,
"memory_peak_mb": 256,
"battery_drain": 2.1,
"fps_avg": 58.3
},
"created_at": "2026-03-22T08:00:00Z",
"completed_at": "2026-03-22T08:00:45Z"
} /api/mobile/runs/:id Auth Required Archive a completed mobile test run. Archived runs are hidden from the default listing but can be viewed with the status=archived filter.
Request Body
status required"archived"/api/mobile/devices Auth Required List available BrowserStack real devices for mobile testing. Optionally filter by platform.
Query Parameters
platform"android" or "ios". Omit to get both./api/automations/schedules Auth Required List all web automation schedules for the team. Returns cron expression, timezone, device, notification settings, and next run time.
/api/automations/schedules Auth Required Create a web automation schedule. Requires automation_id and cron_expression. Optional: timezone, device (desktop, iphone-15, galaxy-s23, etc. — Virtual mode viewport emulation), notify_on_fail (none/email/slack/both), notify_email, slack_channel_id. Supports BrowserStack Live via browserstack: true + bs_browser, bs_os, bs_os_version — same matrix as POST /automations/runs: Node scripts get desktop + real Android + real iPhone; Python scripts get desktop only. See the Live-browser device list on that endpoint for device names.
/api/mobile/schedules Auth Required List scheduled mobile test runs with cron expression, timezone, and notification settings.
Response
{
"schedules": [
{
"id": "uuid",
"automation_id": "uuid",
"automation_name": "Login Flow Test",
"cron_expression": "0 9 * * 1-5",
"timezone": "America/New_York",
"devices": [
"Pixel 7",
"iPhone 15 Pro"
],
"notify_on_fail": "slack",
"enabled": true,
"next_run_at": "2026-03-23T09:00:00Z"
}
],
"total": 1
} /api/mobile/schedules Auth Required Create a scheduled mobile test run. Runs are dispatched to the configured devices on the cron schedule.
Request Body
automation_id requiredcron_expression required0 9 * * 1-5 for weekdays at 9am)timezone optionalUTC)devices requirednotify_on_fail optionalnone (default), email, slack, bothResponse
{
"id": "uuid",
"automation_id": "uuid",
"cron_expression": "0 9 * * 1-5",
"timezone": "America/New_York",
"devices": [
"Pixel 7",
"iPhone 15 Pro"
],
"notify_on_fail": "slack",
"enabled": true,
"next_run_at": "2026-03-23T09:00:00Z",
"created_at": "2026-03-22T10:00:00Z"
} /api/mobile/schedules/:id Auth Required Update a mobile test schedule.
Path Parameters
id requiredRequest Body
cron_expression optionaltimezone optionaldevices optionalnotify_on_fail optionalenabled optionalResponse
{
"id": "uuid",
"automation_id": "uuid",
"cron_expression": "0 9 * * 1-5",
"timezone": "America/New_York",
"devices": [
"Pixel 7",
"iPhone 15 Pro"
],
"notify_on_fail": "slack",
"enabled": true,
"next_run_at": "2026-03-23T09:00:00Z",
"created_at": "2026-03-22T10:00:00Z"
} /api/mobile/schedules/:id Auth Required Delete a mobile test schedule.
Path Parameters
id requiredResponse
{ "success": true } /api/performance/tests Auth Required List all performance test configurations for the current team.
Response
{ "tests": [{ "id": "uuid", "name": "Homepage Perf", "url": "https://example.com", "device": "desktop", "virtual_users": 10, "duration": 30, "perf_threshold": 50, "auto_create_bug": true, "created_at": "..." }] } /api/performance/tests Auth Required Create a new performance test configuration. Combines page quality audits with distributed load testing. Supports mobile app profiling on real Android/iOS devices via BrowserStack. Pro/Team/Enterprise plans only.
Body Parameters
name requiredurl requireddevice optionaldesktop (default), mobile, tabletvirtual_users optionalduration optionalperf_threshold optionalauto_create_bug optionalapp_id optionalPOST /mobile/apps). Required for mobile performance testsmobile_devices optional["Pixel 7", "iPhone 15 Pro"]). Each device creates one run and consumes 1 monthly creditmobile_thresholds optionalcpu_max (%), memory_peak (MB), fps_min, battery_drain_max (%), launch_time_max (ms). Exceeding any threshold triggers a bug reportResponse
{ "test": { "id": "uuid", "name": "Homepage Perf", "url": "https://example.com", ... } } /api/performance/tests/:id Auth Required Get a single performance test configuration by ID.
Path Parameters
id required/api/performance/tests/:id Auth Required Update a performance test configuration. Only include fields you want to change.
Path Parameters
id requiredBody Parameters
name optionalurl optionaldevice optionalvirtual_users optionalperf_threshold optionalauto_create_bug optional/api/performance/tests/:id Auth Required Delete a performance test configuration and all its associated runs.
Path Parameters
id requiredResponse
{ "success": true } /api/performance/run Auth Required Trigger a performance test run (page audit + load test). The run executes asynchronously; poll GET /performance/runs/:id for results. Auto-creates a bug report when the performance score drops below the configured threshold.
Body Parameters
test_id requiredResponse
{ "run": { "id": "uuid", "status": "running", "test_id": "uuid", "created_at": "..." } } /api/performance/runs/:id Auth Required Get full results for a performance test run. Includes Lighthouse scores (Performance, Accessibility, Best Practices, SEO), Core Web Vitals (LCP, FID, CLS, FCP, TTFB, INP, TBT, SI), and load test metrics (VUs, total requests, RPS, p50/p90/p95/p99 latencies).
Path Parameters
id required/api/performance/runs/:id/csv Auth Required Download a CSV report for a performance run. Includes Lighthouse scores, Core Web Vitals, load test summary with latency percentiles, and test metadata.
Path Parameters
id requiredResponse
Returns text/csv with Content-Disposition: attachment; filename="performance-report-{id}.csv"
/api/performance/runs/:id/archive Auth Required Archive a completed performance test run. Archived runs are hidden from the default listing but can be viewed with the status=archived filter on GET /performance/runs.
Path Parameters
id requiredResponse
{ "success": true, "status": "archived" } /api/performance/runs/:id/archive Auth Required Unarchive a previously archived performance test run, restoring it to the default listing.
Path Parameters
id requiredResponse
{ "success": true, "status": "completed" } /api/performance/usage Auth Required Check monthly performance test usage against plan limits. Limits: Free=0, Pro=1/mo, Team=2/mo, Enterprise=10/mo, Admin=unlimited.
Response
{ "used": 1, "limit": 2, "remaining": 1, "plan": "team", "period_start": "2026-03-01", "period_end": "2026-03-31" } /api/security/scans Auth Required Create a security scan configuration. Requires Pro, Team, or Enterprise plan.
Request Body
name requiredscan_type requiredweb or mobiletarget_url web onlyapp_id mobile onlyscan_depth optionalquick (default, ~30s), regular (~5min), deep (up to 30min)auth_config optional{ login_url, username, password } for authenticated web scanningauto_create_bug optionalmin_severity_for_bug optionalcritical, high (default), medium, low/api/security/run Auth Required Trigger a security scan. Web scans require a verified domain. Mobile scans require an uploaded app with a valid file URL. Counts against monthly quota.
Request Body
scan_id requiredscan_depth optionalResponse
{ "id": "run-uuid", "status": "queued" } /api/security/runs/{id} Auth Required Get scan run status and results. Poll this endpoint while status is queued or running.
Response (completed)
{
"id": "run-uuid",
"status": "completed",
"security_score": 72,
"total_findings": 15,
"critical_count": 0,
"high_count": 2,
"medium_count": 5,
"low_count": 4,
"info_count": 4,
"authenticated": true,
"duration_seconds": 185
} /api/security/domains Auth Required List verified domains for the team. Use POST to add a domain and receive a DNS TXT verification token.
/api/security/schedules Auth Required List scheduled security scans for the team. Filter by scan_id query param to get schedules for a specific scan config. Each schedule has one and only one parent scan config.
Query Parameters
scan_id optional/api/security/schedules Auth Required Create a scheduled security scan. One schedule per scan config. When the schedule fires, the scan uses the scan_depth configured on the scan itself. Every run counts against your monthly security scan cap (Pro 2/mo, Team 5/mo, Enterprise 20/mo). Security+ and admin users bypass the cap.
Request Body
scan_id requiredcron_expression required0 9 * * 1-5 for weekdays at 9am)timezone optionalUTC)notify_on_fail optionalnone (default), email, slack, bothnotify_email optionalslack_channel_id optionalResponse
{
"id": "schedule-uuid",
"scan_id": "scan-uuid",
"cron_expression": "0 9 * * 1-5",
"timezone": "America/New_York",
"enabled": true,
"next_run_at": "2026-04-06T13:00:00.000Z"
} /api/security/schedules/:id Auth Required Update a security scan schedule. Updating cron_expression, timezone, or re-enabling automatically recomputes next_run_at.
Request Body
cron_expression optionaltimezone optionalenabled optionalnotify_on_fail optionalnotify_email optionalslack_channel_id optional/api/security/schedules/:id Auth Required Delete a security scan schedule. Does not affect the parent scan config or any completed runs.
/api/code-review/prs?repo=owner/repo Auth Required List open pull requests for a GitHub repository. Returns PR number, title, author, head branch, and existing review status if previously reviewed. Requires a GitHub integration configured in Settings.
repostring (query)GitHub repo in owner/repo format/api/code-review/review Auth Required Trigger an AI code review on a pull request. Fetches the PR diff from GitHub and sends it to Claude for analysis. Returns the review ID with quality score and findings. Team/Enterprise only.
repostringGitHub repo in owner/repo formatpr_numberintegerPull request number/api/code-review/reviews Auth Required List past code reviews for the team. Returns review ID, repo, PR number/title, quality score, severity counts, and timestamps. Ordered by most recent.
/api/code-review/reviews/:id Auth Required Get a single code review with all findings. Each finding includes severity (critical/high/medium/low), category (bug/security/performance/style/logic/maintainability), title, description, suggestion, file path, line numbers, and code snippet.
/api/code-review/settings Auth Required Get code review settings for the team. Returns custom instructions, auto-review toggle, post-comments toggle, auto-bug creation config, and enabled status.
/api/code-review/settings Auth Required Update code review settings. All fields optional — only provided fields are updated.
custom_instructionsstring?Custom review instructions sent to Claudeauto_reviewboolean?Auto-review PRs on open (Phase 2)post_commentsboolean?Post inline comments to GitHub PR (Phase 3)auto_create_bugboolean?Auto-create bug reports for critical findingsmin_severity_for_bugstring?Minimum severity for auto-bug: critical, high, medium, low/api/code-review/usage Auth Required Check code review usage. Returns reviews used and plan info. Unlimited reviews on Pro, Team, and Enterprise plans.
/api/code-review/analytics Auth Required Get code review analytics for the team. Returns trends (daily review counts + avg scores), finding category and source breakdowns, severity distribution, velocity metrics (reviews/week, avg time, avg findings), top repos, top PR authors, and recent quality score sparkline data. Query param: days (7, 30, or 90, default 30).
/api/github/webhooks Auth Required List all GitHub webhooks registered for the team. Returns webhook ID, repo, active status, and creation date.
/api/github/webhooks Auth Required Register a GitHub webhook on a repository for auto-review. Requires repo (e.g. owner/name). Creates a webhook on GitHub that sends pull_request events to bugAgent. The webhook secret is auto-generated and stored securely.
/api/github/webhooks Auth Required Remove a GitHub webhook from a repository. Requires repo. Deletes the webhook from both GitHub and the bugAgent database.
/api/github/webhook Public (Webhook) GitHub webhook receiver endpoint. Handles pull_request events. Verifies HMAC-SHA256 signature, checks auto-review settings, and triggers a Claude-powered code review. Only processes opened and synchronize actions. Deduplicates by commit SHA.
/api/explorations Auth Required List all Exploratory AI configs for the team. Returns name, target URL, status, agent count, selected strategies, last run info, and run count.
/api/explorations Auth Required Create a new exploration config. Requires name and target_url. Optional: exploration_context (JSONB with focus_areas, instructions, auth_config, exclude_paths, max_depth, test_data), project_id, auto_create_bug, min_severity_for_bug, agent_count (1–10, clamped to plan limit; Pro: max 3, Team: max 10), agent_strategies (array of strategy IDs: happy_path, edge_case, security, accessibility, error_path, performance, mobile, data_integrity, navigation, custom).
/api/explorations/run Auth Required Trigger an exploration run. Requires exploration_id. Dispatches to the runner for 5-phase execution (Recon, Plan, Execute, Analyze, Report). When agent_count > 1, multiple agents run Plan/Execute/Analyze in parallel after a shared Recon phase. Returns the run ID. Poll GET /api/explorations/runs/:id for status and per-agent progress via agent_progress.
/api/explorations/runs/:id Auth Required Get exploration run details including phase data (recon, plan, execute, analyze), findings with agent attribution (agent_index, agent_strategy), per-agent progress (agent_progress), and linked bug reports. Use for polling during execution or viewing results.
/api/explorations/usage Auth Required Check monthly Exploratory AI usage. Pro: 3/mo, Team: 50/mo, Enterprise: 50/mo.
/api/explorations/trends Auth Required Get exploration history and trends. Returns run history, finding trends by type and severity over time, screenshot comparisons between consecutive runs, and delta vs previous run. Query params: exploration_id (optional filter), days (7/30/90, default 30).
/api/explorations/schedules Auth Required Manage exploration schedules. GET lists schedules. POST creates a new one (requires exploration_id and cron_expression). PATCH updates schedule (enable/disable, change cron). DELETE removes a schedule. Supports notifications via email or Slack on failure.
Compliance Center
Automated SOC2, ISO 27001, and GDPR compliance evidence collection, config drift monitoring, access reviews, and security event tracking. Team and Enterprise plans only.
GET /api/compliance/connections
List connected compliance services for the team.
POST /api/compliance/connections
Connect or update a compliance service. Service must be one of: cloudflare, github, sentry, supabase, railway. Credentials are service-specific (e.g., api_token + zone_id for Cloudflare).
POST /api/compliance/collect
Trigger compliance evidence collection from all connected services. Returns run ID immediately; collection runs in background. Response includes id (run UUID), status ("running"), and usage (used/limit for current month).
GET /api/compliance/runs/:id
Get evidence collection run details including per-service evidence, findings, and metrics.
GET /api/compliance/drift
List config baselines and unresolved drift events.
POST /api/compliance/drift
Trigger a config drift check across all connected services. Compares current settings against baselines. Returns checks_performed, drift_detected count, and drift_events array with service, config_key, expected/actual values, and severity.
POST /api/compliance/drift/:id/resolve
Mark a config drift event as resolved.
POST /api/compliance/access-review
Generate a quarterly access review report. Optional body: quarter (e.g., "2026-Q2", defaults to current). Returns team members with roles/MFA/login status, API keys with usage/inactive days, summary stats, and actionable recommendations.
GET /api/compliance/events
Query the cross-service security event timeline.
Query params: source (cloudflare, sentry, github), severity (critical, high, medium, low, info), limit (max 100), offset
POST /api/compliance/backups
Trigger backup verification across connected services. Returns the verification rows just inserted into backup_verifications.
Supabase backup check: when the team's compliance_connections.credentials includes a management_token (a Supabase Personal Access Token from supabase.com/dashboard/account/tokens), the endpoint calls Supabase's Management API for the project's actual backup list and records whether the latest is younger than 24 hours. Without a management_token the row is recorded with status: "unknown" and a note explaining how to enable real verification.
Daily auto-run: a pg_cron job fires the verification at 04:00 UTC for every team that has the Management API token configured, so the evidence trail in backup_verifications stays continuous without anyone clicking the button.
GET /api/compliance/backups
List all backup verification rows for the team, newest first. Returns array of { id, team_id, service, backup_type, status, last_backup_at, metadata, verified_at }.
Suggestions & Recommendations
Use API keys over JWTs
API keys don't expire and are simpler for server-to-server or agent integrations. JWTs from /auth/login expire and require refresh logic.
Set a project on every report
Use the project field when creating reports to keep your bug data organized. If omitted, reports go to the team's default project.
Poll /usage before bulk operations
Check GET /usage before submitting many reports to avoid hitting plan limits mid-batch.
Use the MCP server for AI agents
If you're building an AI agent integration, the MCP server provides a more natural interface than raw REST calls. Both offer the same features.
Rotate API keys periodically
Use POST /keys/:id/regenerate to rotate keys without downtime — the new key keeps the same name and scopes.
Subscribe to the changelog
Stay up to date with API changes via the changelog page or RSS feed.