Skip to content

PQL queries API

PQL (Probara Query Language) reads the organization’s test data: cases, suites, runs, run cases, results, defects, milestones, plans and shared steps. A query names an entity, filters it, and can group and aggregate it. This page covers the endpoints, what they answer, and their limits.

Every entity, field, operator, function and error code of the language is in the PQL language reference.

Queries are available on the Pro and Enterprise plans, the same plans as dashboards. On any other plan every endpoint on this page returns 403 forbidden. dashboardsEnabled on GET /api/v1/orgs/current shows the plan’s setting.

Method and pathWhat it does
POST /api/v1/queryRuns one query and answers one page of rows or groups.
GET /api/v1/query/schemaAnswers the schema a query is checked against.

Every member can run queries, viewers included. To keep a query and reuse it, see Saved queries.

POST /api/v1/query takes a JSON body:

{ "query": "FROM results WHERE status = failed", "offset": 0 }
  • query is required: 1 to 4,000 characters.
  • offset is optional. It overrides the query’s own OFFSET for paging, from 0 to 10,000.

Results cover only the projects the caller can open, and archived projects are never included. scope.hiddenProjectCount counts the organization’s other projects that the caller cannot open, so a result is never shown as complete when projects are hidden.

A query without an aggregate answers rows. Each row is one record, with a link to it and its values, one per column:

  • mode is rows, and columns names each column with its key, label and type.
  • total counts the matching rows exactly up to 10,000. Past that, total is 10,000 and totalCapped is true.
  • limit is the page size: the query’s LIMIT, 50 by default and 500 at most.
  • offset, scope and timeZone echo the page, the project counts and the zone the query read dates in.
  • timeZoneFallback is true only when the caller’s stored time zone could not be read, so the default zone answered.

A query with a SELECT of aggregates, or a GROUP BY, answers aggregate groups:

  • mode is aggregate. Each column has a role: group for a grouping key, measure for a value computed per group.
  • Each row has values and no link.
  • Groups are capped at 1,000. total counts them up to that cap, and truncated is true when there are more.
  • passRate() is the percentage of executed rows that passed: a number from 0 to 100, rounded to one decimal, or null when nothing executed. A result counts as executed unless its status is untested. For runs, executed means passed, failed, blocked or skipped. passRate() applies to results and runs only.

in query("name") and not in query("name") filter the entity’s display id by the rows of another saved query. Names are matched without regard to case.

  • The name resolves among the saved queries the caller can see. A query the caller cannot see is unknown, and its name never appears in a hint.
  • The referenced query must be a rows query over the same entity. Its WHERE applies under the caller’s own project access. Its ORDER BY, LIMIT and OFFSET are ignored.
  • A referenced query may reference another, up to three references deep from the query that runs. A cycle is refused.
  • The referenced text is checked against the current fields each time the query runs, so a reference always reads the current text of the saved query. A reference that no longer validates answers pql_invalid with referenced_query_invalid.
  • The refusals appear in details.errors: unknown_value (no visible query has the name), query_entity_mismatch, query_not_rows, query_depth_exceeded, query_cycle and referenced_query_invalid.

GET /api/v1/query/schema answers what a query is checked against, for the caller:

  • customFields: the custom fields that apply to the caller’s projects, with their options.
  • members and groups: the active members and the user groups.
  • savedQueries: the names of the saved queries the caller can see, sorted by name. The schema answers at most 500 of them, and savedQueriesTruncated is true when there are more. A reference to any visible name still resolves.
  • hints: the value lists for suites, milestones, plans, environments, projects and tags. Each is truncated at 500 names, with truncated set when there are more.

Every error answers { "error": { "code", "message" } }, with a details object when there is more to say.

StatusCodeWhen
403forbiddenThe organization’s plan does not include dashboards, so queries are off.
422validation_failedThe body is not JSON, the query is empty or longer than 4,000 characters, or offset is outside 0 to 10,000.
422pql_invalidThe query does not parse or does not validate. details.errors lists every error.
422pql_unsupportedThe query uses a construct a later release adds. details.construct names it.

Each entry in details.errors has a stable code, a localized message, a span (offset, line, column and length) that points at the offending text, the expected tokens or fields, and an optional hint, such as a name the query may have meant.

POST /api/v1/query/export takes the query text alone, and answers the rows of the query as CSV:

{ "query": "SELECT title, created FROM cases ORDER BY title" }
  • The export has the same checks, scope and access as a run, and refuses what a run refuses with the same codes and statuses.
  • A rows query writes its rows in their order, up to 10,000. The X-Pql-Export-Truncated header is true when more rows matched.
  • An aggregate query writes up to 1,000 groups, with its grouping keys and measures as columns.
  • The query’s own OFFSET and LIMIT do not apply to an export.
  • The body is UTF-8 with a byte order mark and CRLF record ends. The first record holds the column labels.
  • Values are machine values: a time is its ISO-8601 UTC instant, a duration is milliseconds, a person, an option or a reference is its name, and the tags of a row are joined with ; .
  • A text a spreadsheet would read as a formula, one that starts with =, +, -, @, a tab or a carriage return, is written with a leading quote.
  • Content-Disposition names the file query-YYYY-MM-DD.csv. X-Pql-Time-Zone-Fallback is true when the stored time zone could not be read.

The saved query export is documented with the saved queries API.

LimitValue
Query text4,000 characters
OFFSET10,000 at most
LIMIT (page size)50 by default, 500 at most
Rows totalCounted exactly up to 10,000, then totalCapped
Groups1,000 at most, then truncated