Skip to content

Launch a manual or mixed run again: its failures, or a copy

POST
/v1/runs/{id}/relaunch
curl --request POST \
--url https://beta-api.plune.ai/v1/runs/example/relaunch \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "cases": "all", "title": "Release 4.12 regression · copy" }'

A new manual run made from this one (#1232) — «Re-run N failed» and «Launch a copy» on the run page. cases: failed takes the cases whose latest result here failed or broke, the whole run whatever a filter shows, each assigned to whoever marked it, else to the run’s own assignee. cases: all takes every case the run expected or holds a result of, assigned as the run was. statuses (#1768) clones the run with a filter instead: any combination of passed, failed, broken, blocked, skipped and muted, the cases whose latest result here is counted under one of them; the new run is called «… · clone». Give exactly one of cases and statuses. Cases in the Bin since are left out; no result comes along, so the new run starts unmarked. It is called title when the body names one, else after the source — «… · re-run» or «… · copy» — and keeps its environment, labels and custom field values (#1764, copied as they stand, so a field made required since does not stop it), not its description. Only a manual or a mixed run: an automated run is re-run where its tests live (plune run grep <id> --failed names its failures), so it is refused with 409, an eval run too. A new run spends the daily quota like every other way to create one (see POST /v1/runs). The source run’s history gets an event naming the run it became. A reader is refused (403).

id
required
string
Media type application/json
One of:

Which cases of the run the new manual run takes (#1232, #1768), and what it is called. Exactly one of cases and statuses.

object
cases
required

failed — «Re-run N failed»: what failed or broke, each to whoever marked it. all — «Launch a copy»: every case, assigned as the run was.

string
Allowed values: failed all
statuses

A clone with a filter (#1768): any non-empty combination of the statuses a run counts. The new run takes the cases whose latest result here is counted under one of them (a muted failure is muted, not failed), each to whoever marked it, else to the run’s own assignee. No result comes along.

Array<string>
>= 1 items unique items
Allowed values: passed failed broken blocked skipped muted
title

Trimmed. Defaults to the source’s title with «· re-run» or «· copy».

string
>= 1 characters <= 200 characters
Example
{
"cases": "all",
"title": "Release 4.12 regression · copy"
}

The new run — open it to walk its cases

Media type application/json
object
run
required
object
id
string
projectId
string
kind
string
Allowed values: automated manual mixed eval
externalKey
string
nullable
statusEvent

The value rerun is reached only by joining a terminated run again — it is never requested. scheduled (#1233): saved and not launched yet — launch, or a reporter joining by its key, starts it.

string
Allowed values: launched finished terminated rerun scheduled
configuration

What the run expects to happen. Without it, a crashed shard is indistinguishable from a green run.

object
expected
required
Array<object>
<= 10000 items
object
testCaseId
string
externalKey
object
key
additional properties
any
matrix

Deprecated: not read; configurations are run fields (ADR 0070). Taken and stored as sent.

object
key
additional properties
Array<string>
full

The caller states that expected is everything its source has — the whole suite, not one file or a --grep. When such a run finishes with an empty notRun, every active case that this source (the source of the run’s results) reported before and did not report in this run moves to detached, with the run named as the reason. Manual cases, other sources, in_review and deprecated cases are never touched; a later result on a detached case brings it back to active by itself. Set it only for the run that covers the whole suite (PLUNE_FULL_RUN=1 in the CLI).

boolean
assignees

Who is to run which case (B8-team T4): testCaseId → userId. Filled at launch by assignment: prefer-assignee from each expected case’s assigneeId at that moment — a snapshot, so a case that changes hands later does not rewrite a run under way. Cases nobody holds are absent. May also be sent as is.

object
key
additional properties
string
meta
object
sha

The commit the run was made from — run.sha in GET /v1/runs/{id}/summary.

string
branch

The branch it was made on — run.branch in GET /v1/runs/{id}/summary.

string
ciUrl

The CI run that produced the report — the reporter reads the runner’s own config.metadata.ci.buildHref. Sanitized before it is stored (a credential in a query parameter becomes a marker); set by the shard that opens the run and never changed by one that joins it. The run page links it from GET /v1/runs/{id}/summary.

string format: uri
/^[Hh][Tt][Tt][Pp][Ss]?:///
runner

The tool that reported the run — playwright, or the report format plune run import read — not the machine of the CI; run.runner in GET /v1/runs/{id}/summary.

string
planId

The plan the run was launched from (D33), when it was — what GET /v1/runs?planId= filters by.

string
planSelected

How many cases the plan’s collections selected when the run was launched (#1274); a count taken then, so it does not follow the plan afterwards.

integer
planQuery

The plan’s collections (filter query strings) as they stood when the run was launched (#1274); a copy, so the run still says what it selected by after the plan is edited or deleted.

Array<string>
<= 20 items
title

What to call this run in a list. The first shard to declare one wins; a shard that arrives later fills a field left empty rather than overwriting.

string
>= 1 characters <= 200 characters
environment

Where it ran — staging, prod, a preview. Filterable on GET /v1/runs, so two CI matrices read as two histories.

string
>= 1 characters <= 64 characters
labels

How the run is marked — smoke, nightly, a team name. An empty array is how every mark is removed.

Array<string>
<= 32 items
description

What the run is for, in a person’s words (#1232) — plain text; null when nobody wrote one.

string
nullable >= 1 characters <= 2000 characters
custom

Values of the project’s custom fields (#1764), field id → value. Absent while the run has none. Not configuration, which is the execution plan and is no field.

object
combinations

The combinations of configuration values the run was launched with (#1251), in the order of the groups and of their values: Chrome · Windows, Chrome · macOS, Firefox · Windows, Firefox · macOS. Computed by the server from custom when the run is created and frozen; the values of a group cannot change afterwards. Absent for a run launched with none. The one addition: a batch from CI that names a combination the list lacks (configuration of POST /v1/runs/{id}/results) appends it at the end — a number, once given, never changes.

Array<object>
>= 1 items <= 25 items

One combination of configuration values (#1251, ADR 0070 §2): a value of each chosen group, the groups in their order. Names are frozen at launch: a rename later changes no past run.

object
values
required
Array<object>
object
fieldId
required

The group (a field with role: configuration); null with optionId for a value CI named that is not in the list.

string
nullable
optionId
required

The value (an option of the group); null for a value CI named that is not in Settings → Configurations — «not in the list», kept as it was sent.

string
nullable
group
required

The name of the group at launch.

string
label
required

The label of the value at launch.

string
startedAt
string format: date-time
finishedAt
string format: date-time
nullable
terminateReason
string
nullable
summary

What a run amounted to, frozen at finish. Distinct from RunSummary, which is the list-item shape.

object
counts
required

One entry per status that occurred, and muted when a muted case failed or broke; an absent key means zero. A failed or broken result of a muted case is counted as muted, not as a failure; a finished run never changes (#1247).

object
key
additional properties
integer
byPriority

counts again, by the priority each result’s case had when the run finished (#1379): { "critical": { "passed": 4, "failed": 1 } }. It is what Analytics counts a finished run under by priority, so a case’s priority changed later moves none of it. Absent from a summary frozen before it was kept.

object
key
additional properties
object
key
additional properties
integer
notRun
required

Expected and never reported — what keeps a dead shard from looking green.

Array<string>
awaitingRetest

Cases a retest reset that wait for a new result (#1767): in no count, not in notRun, not in total. Only on a live summary: a run cannot finish while any wait, so a frozen one never has it.

Array<string>
total
required
integer
byCombination

Only for a run with configurations (#1251, ADR 0070 §4): the counts again per combination, in the order of the run’s combinations. notRun and awaitingRetest are by the pair (case, combination): a combination nobody reported has empty counts, total 0 and every expected case in notRun — none of it is counted as skipped. The run’s own notRun is then the cases with a result in no combination, its awaitingRetest the cases waiting in any one.

Array<object>
object
counts
required

One entry per status that occurred in this combination; an absent key means zero.

object
key
additional properties
integer
total
required
integer
notRun
required

Expected cases with no current result in this combination.

Array<string>
awaitingRetest

Cases a retest reset that wait for a new result in this combination; absent for none.

Array<string>
caseCounts

Only for a run with configurations (#1251): the cases that have a result, by where each stands — the worst of its combinations (failed, broken, blocked, muted, passed, skipped): «4 of 120 cases failed». A case in the Bin is not counted (as in /cases?status= and the re-run).

object
key
additional properties
integer
createdBy

Who launched it (B8-team T3): the userId of the session, or of the owner of the token that started or synced it — the first shard to create the run; a joiner is not recorded. null for a run from before names were kept. Resolve it to a name through GET /v1/members.

string
nullable
Example
{
"run": {
"id": "6f1c2b3a-0000-4000-8000-0000000000d1",
"projectId": "u-shop::default",
"kind": "manual",
"externalKey": null,
"statusEvent": "launched",
"configuration": {
"expected": [
{
"testCaseId": "6f1c2b3a-0000-4000-8000-0000000000c1"
}
],
"assignees": {
"6f1c2b3a-0000-4000-8000-0000000000c1": "6f1c2b3a-0000-4000-8000-0000000000a2"
}
},
"meta": null,
"startedAt": "2026-09-16T09:12:04.151Z",
"finishedAt": null,
"terminateReason": null,
"summary": null,
"title": "Release 4.12 regression · copy",
"environment": "staging",
"labels": [
"release"
],
"description": null,
"createdBy": "u-shop"
}
}

Invalid body — exactly one of cases (failed or all) and statuses (a non-empty list of distinct statuses), a title 1–200 characters

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

No / invalid token or session

A reader of the project — it may read the run, not launch it again

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

No such run in your projects

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

An automated or eval run, or nothing to launch: no case failed or broke, no case stands in the statuses asked for, or the run holds no case

Media type application/json
object
error
required
string
Example
{
"error": "nothing failed or broke in run '6f1c2b3a-0000-4000-8000-0000000000d1' — nothing to re-run"
}

Two refusals share this status, and what to do about them is opposite. Rate-limited — the per-route throttle, or the per-minute request limit of the plan an API token counts by (#1442, #2092): Retry-After carries the seconds until the window rolls over, and waiting that long is the way out. Quota reached — a ceiling on what the project holds (runs in the last 24 hours, test cases, items waiting in the review queue): { error, quota }. A retry straight away frees nothing, so do not loop on it; the message says what makes room — deleting cases, working the queue down, an operator raising the limit — and the run quota, a rolling 24 hours, frees its oldest runs as they age out. Tell the two apart by the body: a 429 whose body has a quota object is a quota, one without it is a throttle. quota carries kind, limit, used, remaining and resetsAt: the figures behind the sentence, and for the run quota the instant its oldest run ages out (#1258). Retry-After is sent on a quota only where there is such an instant (the run quota: the whole seconds, at least 1, until resetsAt); the case, review-queue and project quotas free only by an action, have resetsAt: null, and send no Retry-After. GET /v1/quotas reads the same figures without a refusal.

Media type application/json
One of:
object
error
required
string
Example
{
"quota": {
"kind": "runsPerDay"
}
}
Retry-After
integer

Seconds until the window rolls over on a throttle; on a quota, until quota.resetsAt — sent only for the run quota, which has one