Skip to content

The results of a run, newest first

GET
/v1/runs/{id}/results
curl --request GET \
--url 'https://beta-api.plune.ai/v1/runs/example/results?limit=100&defects=1&status=failed%2Cbroken&muted=true&q=coupon&subStatus=Product%20bug&combination=1' \
--header 'Authorization: Bearer <token>'

The result list of the run page (api.ts → listRunResults), a page at a time: the results the run holds, with their status, outcome, execution and error text, whatever the state of the case they point at — a result is evidence of the run and stays listed when its case is later deleted. Paged (#1380): without limit the answer is the newest 100 results, and next while more remain — the before of the call for the page after it. limit asks for another size, up to 1000; past that it is a 400. A page also stops early, with next, once its error text and failure details pass 64 Mi characters (#814). A caller that wants the whole run follows next until it is absent — the length of one answer is never the size of the run, which GET /v1/runs/{id}/summary counts. Newest first throughout. Each result carries its failure in this same answer, so the page opens the detail without another request, and every errorContext is sanitized on the way out — one stored before the rules existed included. The run report (#1232) narrows the list here, on the server: status, q and defects each narrow what the others left, and every result carries its case’s suitePath, which its Suites view groups by.

id
required
string
limit
integer
default: 100 >= 1 <= 1000

At most this many results in the answer: 100 when absent, 1000 at the most (#1380).

before
string

The next of a previous answer: continue after it.

defects
string
Allowed values: 1

1: only the results that carry at least one defect link (#1064). Anything else is the whole run.

status
string
Example
failed,broken

Only the results with one of these statuses (#1232): a comma-separated list, or the key repeated. None named is every status; a word that is not a status is a 400.

muted
string
Allowed values: true false
Example
true

Reads status the way the run’s counters do (#1247): a muted failure — the failed or broken result of a case that was muted when it was written (muted: true) — is counted as muted, not under its status. true: the muted failures, beside the statuses named, or alone when none is; false: the statuses named without them, or every result but them. Without it, status is the result’s own and finds a muted failure too. Anything but true or false is a 400.

q
string
Example
coupon

Only the results whose case’s name holds this text (#1232) — any part of it, in any case; % and _ are letters here. Trimmed; blank is no filter.

subStatus
string
Example
Product bug

Only the results marked with one of these sub-statuses (#1231), by the name a result keeps — the key repeated for several, never a comma (a name may hold one). A name the settings no longer offer still finds the results marked with it. Narrows status as the other filters do.

combination
integer
<= 24
Example
1

Only the results of this combination of the run’s combinations (#1251), by its number. Anything but a number from 0 to 24 is a 400; a number the run has no combination for finds nothing.

Results of the run

Media type application/json
object
results
required
Array<object>

One stored result, as every reader returns it — a run’s results, a test’s history, a corrected mark.

object
resultKey

The key the reporter sent (a person’s mark: manual:<caseId>). A result a retest replaced (#1767) keeps it with #retest:<id> appended, in its history.

string
combination

The number of the result’s combination in its run’s combinations (#1251, ADR 0070). Absent for a result of a run without configurations.

integer
status

What happened, as it happened — a muted case’s failure is still failed here, and ?status=failed finds it.

string
Allowed values: passed failed broken blocked skipped
muted

Whether the case was muted when this result counted (#1247): stamped from the case when the result is written (a reporter, plune sync, a Cairn ingest), and following the case while the run is open. A failed or broken result of a muted case is counted as muted, not as a failure; a finished run never changes (#1247).

boolean
subStatus

The sub-status a person marked it with (#1231) — the NAME as it stood then: renaming or removing it under Settings → Statuses changes what is offered next, never this. A built-in is its English name (Product bug); the dashboard shows it in its own language. null for none — every reporter’s result, which never carries one.

string
nullable <= 40 characters
errorContext

Returned sanitized — no colour codes, no credentials — whether it was stored before the rules existed or after.

string
nullable
errorContextMeta

What the platform removed before storing — written whenever something was, even without text; null when nothing ever was.

object
redacted
required

Values replaced by a marker, in the text and in every string of failure, each once. The headline counts only when there is no text — otherwise it repeats a line of it.

integer
truncated
required

Whether the TEXT was cut to 256 KB. A shortened field of failure carries its own ….

boolean
omittedByReporter

Characters the REPORTER cut before sending, as it declared in errorContextOmitted; absent when it said nothing. Not the platform’s cut (truncated).

integer
>= 1
failure

What the reporter said about the failed attempt, or null.

object
headline
string
<= 300 characters
steps
Array<string>
<= 20 items
stepsOmitted

How many steps between the outer and the inner ones were left out. Absent when none were.

integer
>= 1
location
object
file
required

From the repository root in posix form, the way a case’s specRef names it. A path of the machine is refused: absolute, with a drive or a scheme, from a home (~), or climbing out with ...

string
>= 1 characters /^(?![A-Za-z][A-Za-z0-9+.-]*:)(?![\\/~])(?!(?:.*[\\/])?\.\.(?:[\\/]|$)).+$/
line
required
integer
>= 1
column
integer
>= 1
file
string
<= 1000 characters
artifacts
Array
<= 50 items
object
name
required

As the runner named it — screenshot, trace, error-context.

string
>= 1 characters
contentType
string
>= 1 characters
name
string
<= 200 characters
contentType
string
<= 100 characters
artifactsOmitted

How many artifacts past the listed ones there are — all reachable through ciUrl.

integer
>= 1
ciUrl
string format: uri
/^[Hh][Tt][Tt][Pp][Ss]?:///
defects

The defect links on this result (#1064), oldest first - present on a run’s results list, and only when there is one. A result carries them only if it failed or broke.

Array<object>

A defect (#1064): the address of a ticket somebody already filed, kept beside a case or a failed result. https only, at most 2000 characters; the label is plain text, at most 200, and is shown as text, never as markup. The author is a userId; the dashboard names them from GET /v1/members. No type: Bugs (#1065) will read the same links as external tickets.

object
id
required
string format: uuid
url
required
string
<= 2000 characters /^[Hh][Tt][Tt][Pp][Ss]:///
label
required
string
nullable <= 200 characters
authorId
required
string
createdAt
required
string format: date-time
suitePath

Where the result’s case sits in the tree (#1232) — the suites from the root down to its own; a suite filed from a spec stands for the folders above it by its file (["e2e/cart.spec.ts", "Coupons"]). Empty for a case at the root. On a run’s results list, always.

Array<string>
title

The title of the result’s case (#1705), so a page can name its rows without reading the project’s case list. On a run’s results list; kept after the case is deleted, like the rest of the evidence.

string
files

Files uploaded to this result — screenshots, text (JSON, plain text, logs) and, for a project with a bucket, any file — oldest first (ADR 0040, ADR 0041) — present on a run’s results list, and only when there is one. Only finished files: one still waiting for complete is not listed. For storage: db the bytes are GET /v1/files/{id}.

Array<object>

A file of a result, everything but its bytes (ADR 0040, ADR 0041). Only a finished file is ever shown: one that was announced with uploads and not yet completed is in no list.

object
id
required
string
name
required

The last segment of the name it was uploaded with, cleaned of credentials as a text is.

string
contentType
required

In the database (storage: db): image/png, image/jpeg, image/webp, application/json or text/plain — a log is text/plain. In the bucket (storage: bucket): the media type it was announced with, lower case and without parameters, any type.

string
size
required

Bytes as kept: in the database a picture at most 2 MiB and a text at most 512 KiB, counted after its credentials are cleaned, so it can differ from what was sent; in the bucket the size that was announced and found there.

integer
storage
required

db: Plune keeps the bytes, GET /v1/files/{id} returns them. bucket: they are in the project’s own bucket, and GET /v1/files/{id} answers 409 in_bucket (the way to read them is GET /v1/files/{id}/link).

string
Allowed values: db bucket
key
additional properties
any
next

Present only when more results remain: pass it as before.

string
Example
{
"results": [
{
"id": "6f1c2b3a-0000-4000-8000-0000000000e2",
"runId": "6f1c2b3a-0000-4000-8000-0000000000d1",
"testCaseId": "6f1c2b3a-0000-4000-8000-0000000000c1",
"resultKey": "e2e/checkout.spec.ts::Checkout — coupon applied::chromium",
"signature": "2c624232cdd221771294dfbb310aca000a0df6ac8b66b696d90ef06fdefb64a3",
"status": "failed",
"rawStatus": "failed",
"source": "playwright",
"expectedStatus": "passed",
"outcome": "unexpected",
"execution": {
"startedAt": "2026-09-16T09:12:05.400Z",
"finishedAt": "2026-09-16T09:12:09.021Z",
"durationMs": 3621,
"retry": 1,
"worker": "chromium-1"
},
"durationMs": 3621,
"caseVersion": 1,
"muted": false,
"errorContext": "Error: expect(locator).toHaveText(\"−10 %\")\n Expected: \"−10 %\"\n Received: \"0 %\"\n at e2e/checkout.spec.ts:41:31",
"errorContextMeta": {
"redacted": 0,
"truncated": false
},
"assertions": [],
"steps": null,
"failure": {
"headline": "Error: expect(locator).toHaveText(\"−10 %\")",
"steps": [
"Pay",
"Apply the coupon"
],
"location": {
"file": "e2e/checkout.spec.ts",
"line": 41,
"column": 31
},
"artifacts": [
{
"name": "screenshot",
"contentType": "image/png"
},
{
"name": "error-context",
"contentType": "text/markdown"
},
{
"name": "trace",
"contentType": "application/zip"
}
],
"ciUrl": "https://github.com/plune-ai/plune/actions/runs/35003177826"
},
"executedBy": null,
"subStatus": null,
"createdAt": "2026-09-16T09:12:04.151Z",
"defects": [
{
"id": "6f1c2b3a-0000-4000-8000-0000000000a8",
"url": "https://tracker.example.com/browse/PLN-482",
"label": "Coupon is not applied on an empty cart",
"authorId": "6f1c2b3a-0000-4000-8000-0000000000a2",
"createdAt": "2026-09-16T10:30:00.000Z"
}
],
"suitePath": [
"e2e/checkout.spec.ts"
]
},
{
"id": "6f1c2b3a-0000-4000-8000-0000000000e1",
"runId": "6f1c2b3a-0000-4000-8000-0000000000d1",
"testCaseId": "6f1c2b3a-0000-4000-8000-0000000000c1",
"resultKey": "e2e/checkout.spec.ts::Checkout — empty cart::chromium",
"signature": "7f974c61f8f10065cd8ae6993cc069e4f85b1db1ed008b965885fb6f945a28c9",
"status": "passed",
"rawStatus": "passed",
"source": "playwright",
"expectedStatus": "passed",
"outcome": "expected",
"execution": {
"startedAt": "2026-09-16T09:12:04.000Z",
"finishedAt": "2026-09-16T09:12:05.310Z",
"durationMs": 1310,
"retry": 0,
"worker": "chromium-1"
},
"durationMs": 1310,
"caseVersion": 1,
"muted": false,
"errorContext": null,
"errorContextMeta": null,
"assertions": [],
"steps": null,
"failure": null,
"executedBy": null,
"subStatus": null,
"createdAt": "2026-09-16T09:12:04.151Z",
"suitePath": [
"e2e/checkout.spec.ts"
]
}
]
}

limit is not an integer from 1 to 1000, before is not a next of this list, or status names a word that is not a status

Media type application/json
object
error
required
string
Example
{
"error": "`limit` must be an integer from 1 to 1000"
}

No / invalid token or session

Not found or not yours

Media type application/json
object
error
required
string
Example generated
{
"error": "example"
}