BearQ API

Base URL: https://api.bearq.smartbear.com

Note

Early access. Endpoints, request shapes, and response shapes may change without notice. Expect occasional breaking changes until the API is marked stable.

Introduction

The BearQ Public API lets you create tasks, query information about them, and drive BearQ's agents remotely. It is designed around a simple model: submit work to an agent, receive task IDs, then either poll for completion or open a real-time SSE stream and wait for the terminal event. To learn more, see the SmartBear MCP BearQ documents.

What you can do

  • Kick off QA work programmatically. Create a task and assign it to a QA Lead, Tester, or Explorer agent via POST /tasks.

  • Query task progress. Poll GET /tasks/{taskId}/status to learn when a task finishes, or open GET /tasks/{taskId}/stream to be notified the moment it does — no polling required.

  • Follow a task in real time. Stream live metadata and activity log entries via GET /tasks/{taskId}/stream. Works for both running and already-terminal tasks.

  • Inspect task details. Retrieve full metadata and the complete activity log via GET /tasks/{taskId}.

  • Cancel work in flight. Send DELETE /tasks/{taskId} to stop a pending or running task.

Primary use cases

  • CI/CD pipelines. Trigger a Tester task on every build, stream each task ID over SSE, and block the pipeline on the done event's testRunStatus.

  • IDE integrations. Let a developer kick off an Explorer task scoped to a functional area before pushing changes.

  • Agent-to-agent via MCP. BearQ exposes the same capabilities through an MCP server, so any agent that speaks MCP can drive BearQ directly.

  • Open-ended automation. Use the QA Lead agent with a natural-language instruction as a general-purpose escape hatch for work that doesn't fit a structured flow.

CI/CD example

Store BEARQ_API_KEY as a secret in your CI runner. The script below runs a full test suite, streams all tasks in parallel over SSE, and exits non-zero if any test run fails.

IDS=$(curl -sf -X POST "$BEARQ_BASE_URL/tasks" \
  -H "Authorization: Bearer $BEARQ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"agent":"tester","mode":"run"}' | jq -r '.taskIds[]')

run_task() {
  curl -sN -H "Authorization: Bearer $BEARQ_API_KEY" \
    "$BEARQ_BASE_URL/tasks/$1/stream" \
  | awk -v id="$1" '
    /^event: done$/ { getline; sub(/^data: /, ""); print id, $0; exit }
  ' \
  | jq -e --arg id "$1" '.testRunStatus == "passed"' >/dev/null
}

PIDS=()
for ID in $IDS; do run_task "$ID" & PIDS+=($!); done

FAILED=0
for PID in "${PIDS[@]}"; do wait "$PID" || FAILED=1; done
exit $FAILED

Authentication

All endpoints except /health require an API key passed as a Bearer token in the Authorization header. Each key is scoped to a single workspace; all requests act on that workspace's data.

Authorization: Bearer <your-api-key>

Warning

Treat the API key as a secret. Anyone who holds it can act on your workspace.

How to get an API key

  • You must be a workspace admin. Non-admins cannot view the key.

  • Sign in to BearQ at https://bearq.smartbear.com and open Settings.

  • Scroll to the Workspace Settings panel and copy the value from the API Key field.

Errors

All error responses use the application/problem+json format. Use the type URI — not title or detail — to branch in error-handling code, as it is stable across releases.

Error response shape

{
  "type": "https://problems-registry.smartbear.com/unauthorized",
  "title": "Unauthorized",
  "status": 401,
  "detail": "Invalid API key",
  "code": "401-01"
}

Status codes

Code

Name

When it occurs

400

Bad Request

Malformed request or validation failure — for example, a path parameter cannot be parsed, a required field is missing, or a field has the wrong type.

401

Unauthorized

The Authorization header was missing, malformed, or did not match a known API key.

404

Not Found

The requested resource (for example, task ID) does not exist.

Endpoints

POST /tasks — createTask

Creates one or more tasks and assigns them to a BearQ agent. The agent field discriminates between three variants. A single request may produce multiple tasks — for example, a Tester request scoped to a functional area creates one task per test case in that area.

On success, poll GET /tasks/{taskId}/status for each returned ID, or open GET /tasks/{taskId}/stream to be notified of completion without polling.

Agents

Agent

Best for

qa-lead

Natural-language instructions; chaining multiple capabilities; functionality not yet exposed through other endpoints.

tester

Running or refining specific test cases or all tests in a functional area. Ideal for CI/CD pipelines.

explorer

Exploring the application to expand BearQ's understanding and identify new functional areas. Optionally scoped to one area.

Request body

Content-Type: application/json. The agent field is required and selects which variant's fields apply.

Field

Type

Agent

Req?

Description

agent

string

all

Yes

Discriminator. One of qa-lead, tester, explorer.

instruction

string

qa-lead

Yes

Natural-language description of the work. May be multi-sentence or multi-paragraph.

mode

"run" | "refine"

tester

Yes

run executes regression tests; refine improves draft tests. Each mode only operates on its matching test type — mismatched IDs return 400.

testCaseIds

integer[]

tester

No

Specific test case IDs. Mutually exclusive with functionalAreas. Omit both to target every test case of the mode's matching type in the workspace.

functionalAreas

(int|string)[]

tester

No

Areas by ID or name. Creates one task per matching test case. Mutually exclusive with testCaseIds. Omit both to target every test case of the mode's matching type in the workspace.

functionalArea

int | string

explorer

No

Scope the exploration to a single area by ID or name. Omit for full-application exploration.

Request examples

QA Lead — add test cases

{ "agent": "qa-lead", "instruction": "Add important new test cases for our product page." }

Tester — run all regression tests in an area

{
  "agent": "tester",
  "mode": "run",
  "functionalAreas": ["Checkout"]
}

Tester — refine specific test cases by ID

{
  "agent": "tester",
  "mode": "refine",
  "testCaseIds": [4821, 4822, 4823]
}

Tester — run every regression test case in the workspace (omit both selectors)

{ "agent": "tester", "mode": "run" }

Explorer — scope to a single area

{ "agent": "explorer", "functionalArea": "Checkout" }

Responses

Status

Description

200

Task(s) created

400

Bad request or validation failure

401

Invalid or missing API key

404

A referenced resource was not found

200 response body

{ "taskIds": [9183, 9184, 9185] }

GET /tasks/{taskId} — getTaskDetails

Returns full metadata for a task along with its complete activity log. Use this for detailed inspection — for example, displaying progress in a UI or surfacing activity messages to a developer.

For lightweight polling, prefer GET /tasks/{taskId}/status. To follow a task in real time, use GET /tasks/{taskId}/stream.

Path parameters

Parameter

Type

Required

Description

taskId

integer >= 1

Yes

ID of the task. Example: 9183.

Responses

Status

Description

200

Task found — returns TaskDetailsResponse

400

Bad request — for example, taskId cannot be parsed as a positive integer

401

Invalid or missing API key

404

Task not found

200 response body

{
  "taskId": 9183,
  "taskStatus": "completed",
  "metadata": {
    "type": "tester",
    "name": "Checkout",
    "parentTaskId": null,
    "subtaskIds": [],
    "userId": 412,
    "createdAt": "2026-05-15T18:04:21.123Z",
    "completedAt": "2026-05-15T18:07:55.901Z",
    "duration": "PT3M34.778S",
    "acus": 0.14,
    "testCaseId": 4821,
    "testRunStatus": "passed"
  },
  "activityLog": [
    {
      "messageType": "status-message",
      "timestampAt": "2026-05-15T18:04:21.200Z",
      "description": "Started"
    },
    {
      "messageType": "action-message",
      "timestampAt": "2026-05-15T18:04:22.501Z",
      "description": "Navigated to /cart"
    },
    {
      "messageType": "action-message",
      "timestampAt": "2026-05-15T18:04:24.118Z",
      "description": "Applied coupon SAVE10"
    }
  ]
}

DELETE /tasks/{taskId} — deleteTask

Cancels a task that is pending or running. Tasks that have already reached a terminal state (completed, failed, or canceled) are unaffected — the request still returns 200.

Calling this on an already-terminal or already-deleted task returns 200 with an empty object body.

Path parameters

Parameter

Type

Required

Description

taskId

integer >= 1

Yes

ID of the task. Example: 9183.

Responses

Status

Description

200

Canceled, already terminal, or already deleted. Body is {}.

400

Bad request — for example, taskId cannot be parsed as a positive integer

401

Invalid or missing API key

404

Task not found

GET /tasks/{taskId}/status — getTaskStatus

Returns only the task's current lifecycle status. This is the lightweight endpoint for polling. To avoid polling entirely, open GET /tasks/{taskId}/stream and wait for the done event.

Recommended CI/CD pattern: Create tasks with POST /tasks, then either poll this endpoint for each taskId until the status is terminal (completed, failed, or canceled), or stream each task via SSE for a push-based alternative.

Path parameters

Parameter

Type

Required

Description

taskId

integer >= 1

Yes

ID of the task. Example: 9183.

Responses

Status

Description

200

Task found — returns current status.

400

Bad request — for example, taskId cannot be parsed as a positive integer

401

Invalid or missing API key

404

Task not found

200 response body

{ "status": "running" }

GET /tasks/{taskId}/stream — streamTask

Streams a task's metadata and activity log as Server-Sent Events (SSE). Two primary patterns:

  • Wait for the task to finish without polling. Open the stream and read frames until the terminal done event arrives. Useful in CI/CD pipelines that just need the final outcome.

  • Follow a task in real time. Read each frame as it arrives to surface live progress in a UI or feed activity to an agent.

The stream works for both running and already-terminal tasks. If the task is already terminal when the stream opens, all events are flushed immediately, and the stream closes.

For one-shot reads, prefer GET /tasks/{taskId}. For lightweight polling, prefer GET /tasks/{taskId}/status.

Event sequence

Each event is delivered as a standard SSE frame: event: <name>\ndata: <json>\n\n. Events arrive in this order:

S. No.

Event

Occurs

Payload

1

metadata

Exactly once, first.

taskId, taskStatus, and metadata — same shape as GET /tasks/{taskId} without activityLog.

2

activityLogEntries

Zero or more frames.

Non-empty array of activity log entries. First frame carries the backlog (if any); subsequent frames carry new entries as they are emitted.

3

done

Exactly once, last (normal close).

{ status, result, testCaseId?, testRunStatus? }. testCaseId and testRunStatus are always present on Tester tasks, absent otherwise.

4

timeout

Instead of done if stream times out.

{ reason: "max_stream_lifetime_exceeded", message }. Re-fetch GET /tasks/{taskId}/status to get the final status.

Path parameters

Parameter

Type

Required

Description

taskId

integer >= 1

Yes

ID of the task. Example: 9183.

Responses

Status

Description

200

Stream opened. Frames delivered as text/event-stream until done or timeout event.

400

Bad request — for example, taskId cannot be parsed as a positive integer

401

Invalid or missing API key

404

Task not found

Example stream

event: metadata
data: {"taskId":9183,"taskStatus":"running","metadata":{"type":"tester",
  "name":"Checkout","parentTaskId":null,
  "subtaskIds":[],"userId":412,"createdAt":"2026-05-15T18:04:21.123Z",
  "completedAt":null,"duration":null,
  "testCaseId":4821,"testRunStatus":"running"}}

event: activityLogEntries
data: [{"messageType":"action-message","timestampAt":"2026-05-15T18:04:22.501Z",
  "description":"Navigated to /cart"}]

event: activityLogEntries
data: [{"messageType":"action-message","timestampAt":"2026-05-15T18:04:24.118Z",
  "description":"Applied coupon SAVE10"}]

event: done
data: {"status":"completed","result":"All assertions passed.",
  "testCaseId":4821,"testRunStatus":"passed"}

GET /health — getHealth (unauthenticated)

Liveness probe used by infrastructure to verify the public API is running. Returns the plain-text string OK with status 200. This endpoint does not require authentication and is not intended for application use.

Status

Description

200

Service is running. Body: OK (text/plain).

Reference

Task lifecycle

A task moves through these lifecycle states. Once it reaches a terminal state, it will not change again.

Task_status.png

Status

Terminal

Description

pending

No

Created and queued

running

No

Currently being worked on by an agent

completed

Yes

Finished successfully

failed

Yes

Did not complete due to an error

canceled

Yes

Stopped before completion — by DELETE /tasks/{taskId} or by BearQ internally.

Note

For Tester tasks, taskStatus: completed (lifecycle) and testRunStatus: failed (outcome) can both be true at the same time — the agent finished its work, but the test it ran did not pass. These two fields are distinct.

TaskMetadata

Returned inside TaskDetailsResponse and in the metadata SSE event payload.

Field

Type

Description

type

AgentType

Which agent owns the task: qa-lead, tester, or explorer.

name

string

Human-readable task name derived from its type and payload.

parentTaskId

integer | null

ID of the task that spawned this one, or null if created directly via the API.

subtaskIds

integer[]

IDs of tasks this task spawned, in creation order.

userId

integer | null

ID of the user who created the task, or null if created by an automated agent.

createdAt

string (datetime)

ISO 8601 timestamp when the task was created.

completedAt

string | null

ISO 8601 timestamp when the task reached a terminal status, or null if still in progress.

duration

string | null

ISO 8601 duration between task start and finish (for example, PT3M34.778S), or null if not finished.

acus

number (optional)

Agent compute units consumed. Populated only once the task reaches a terminal status.

testCaseId

integer (optional)

ID of the test case being operated on. Always present on Tester tasks, absent otherwise.

testRunStatus

TestRunStatus (optional)

Outcome of the test run. Always present on Tester tasks, absent otherwise.

TestRunStatus

Outcome enum for Tester tasks only. Distinct from the task's lifecycle TaskStatus.

Values

Description

running

The test is currently running or has not yet started executing.

passed

The test completed and all assertions passed.

failed

The test completed but one or more assertions did not pass.

refined

The test was successfully improved (refine mode).

error

An unexpected error prevented the test from running to completion.

canceled

The test was canceled before it could finish.

ActivityLog entry types

Each entry in activityLog (and in activityLogEntries SSE frames) has a messageType field. The following types are unstable and may change without notice:

messageType

Description

user-message

An input message (task instruction, chat input).

agent-message

A message from the agent (response, summary, result).

step-message

A completed test step, with its objective, outcome, and the actions taken.

action-message

A single browser or tool action taken by the agent.

subtasks-message

A spawned subtask (for example, QA Lead analysis, refinement attempt, exploration).

reasoning-message

Step or action execution reasoning.

Problem (error schema)

Field

Type

Description

type

string (URI)

Stable URI identifying the problem class. Use this for error-handling logic — it does not change between releases.

title

string

Short, human-readable summary of the problem class.

status

integer

HTTP status code, repeated for convenience.

detail

string

Human-readable explanation specific to this occurrence of the problem.

code

string

Stable machine-readable code. Examples: 400-00, 401-01, 404-01.

Support

Open a ticket at support.smartbear.com/open-ticket or visit support.smartbear.com.

Publication date: