Add evidence from another failed result
const url = 'https://beta-api.plune.ai/v1/bugs/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/evidence';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"resultId":"6f1c2b3a-0000-4000-8000-0000000000e2","fileIds":["6f1c2b3a-0000-4000-8000-0000000000e3"]}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://beta-api.plune.ai/v1/bugs/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/evidence \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "resultId": "6f1c2b3a-0000-4000-8000-0000000000e2", "fileIds": [ "6f1c2b3a-0000-4000-8000-0000000000e3" ] }'An owner’s or a member’s (a reader gets 403): the failure happened again. The result must be failed or broken (422 result_not_failed) and of the project, in a run out of the Bin (404 otherwise, the same as one nobody made). Its case is linked if it is not yet; its snapshot is taken, cleaned and with the failure text cut at 16384 bytes; the pictures named are copied into the bug - in Plune’s storage a new row of the same bytes, in the project’s bucket a new object under a key of the bug’s, made by the bucket itself. A copy is the bug’s: the eviction of the budget never takes it, and it goes when the bug goes. What is over the limits or the budget (the bug’s copies take at most half of it) is named in notCopied - the call is never refused for room. At most 10 pieces of evidence a bug (409 evidence_limit). Audited on the bug: bug/event with the result, the names and sizes of the copies and of what was not copied - never the snapshot - and bug/event for a case it linked. The answer is the card.
Authorizations
Section titled “Authorizations ”Parameters
Section titled “ Parameters ”Path Parameters
Section titled “Path Parameters ”Header Parameters
Section titled “Header Parameters ”Which of your projects to act in — an id from GET /v1/projects. Absent, your default project. A project you are not a member of answers 404, the same as one that does not exist. Ignored under a bearer token, which is bound to the project it was minted in.
Request Body required
Section titled “Request Body required ”object
A failed or broken result of the project (422 result_not_failed for another status; 404 for one of another project, or in a run in the Bin).
Pictures of that result to copy into the bug - at most 10 a call and 30 a bug; what is over, or does not fit, is named in notCopied and never refuses the call.
Example
{ "resultId": "6f1c2b3a-0000-4000-8000-0000000000e2", "fileIds": [ "6f1c2b3a-0000-4000-8000-0000000000e3" ]}Responses
Section titled “ Responses ”The bug with the new evidence
object
The bug’s name for people (BUG-12): the project’s own number, handed out in order, never reused and never changed.
Whose truth the row is. plune is a bug of the project’s own; jira (a mirror of a Jira ticket, #1069) is not written by this version.
The author’s user id, to be named from GET /v1/members; null when the account is gone.
The live cases linked to the bug.
«Passed X of N» (#1067, ADR 0057 §4). A linked case counts its green runs in a row while the bug is open: passed adds one, failed or broken resets, blocked, skipped and a muted result neither add nor reset; a run is one verdict, as the run itself counts the case - its latest result in each combination (a retry that passed is a pass), then the worst of the combinations; green counts once every combination of the run has a result, red at once (a failure in any combination); only a run newer than the one last counted and made after the case was linked counts, and with an environment in the rule only a run on it.
object
The smallest streak among the live linked cases; 0 with none.
N of the project rule (bugs.close.n of the settings).
The bug is open, has a live case, and every live case has N in a row - and nobody put it off for this series (POST /v1/bugs/{id}/wait, #2163). Under the rule after_n the bug then closes itself, unless flaky.
A live linked case is flaky: the streak is weak proof, and the rule after_n only tells, it does not close.
Closed by its streak (the rule after_n), not by a person (#1067). A person’s close or reopen sets it back to false.
Open again because a linked case failed after its streak closed it - the list’s badge of a regression (#2163). A person’s move clears it.
Markdown, at most 16384 bytes; shown by the safe component. null - none.
Why the last move of state was made: manual, the words the person gave, or Plune’s own (#1067): automatically after N green runs in a row, regression after auto-close. null - never moved.
The live cases linked to the bug, by title.
object
Green runs of the case in a row, counted while the bug is open; from 0 again after a reopen (#1067).
User ids of the people who are told about the bug: the author, and whoever pressed «watch».
Whether the caller is one of them. The one field of the card that depends on who asks.
The failed results the bug was made from or added to, oldest first (#1066, ADR 0057 §6).
object
The result, while it is there and its run is out of the Bin - a link that opens; null otherwise. The snapshot keeps the id.
Its run, on the same terms.
present; deleted_by_cleanup - the plan’s cleanup of old history removed it (#1049); deleted - any other road (the Bin, a deleted case). Kept when the result goes: it cannot be read back after.
The result as it was when the evidence was taken, cleaned of credentials as every reader cleans it: result (status, raw status, source, sub-status, outcome, expected status, muted, case version, duration, params, when), errorContext (at most 16384 bytes; a longer one is cut and ends with …[truncated N bytes], and errorContextTruncated is true), failure (headline, steps, place, CI link - not the artifacts), steps (a person’s marks), case (id, title, keys, flaky and muted then), run (id, title, environment, started), takenBy, takenAt.
object
The pictures named that were not copied, and why. The evidence is written all the same.
object
null when the id named no picture of the result.
limit - over 10 a call or 30 a bug; budget - the bug’s copies in Plune’s storage would take more than half of the file budget; storage - the project’s bucket did not make the copy; missing - not a picture of that result (gone, a text, or never one).
The bug’s copies of the pictures of its evidence, oldest first. Read by GET /v1/files/{id} (one in the project’s bucket by GET /v1/files/{id}/link), by anyone who reads the bug; never deleted alone (DELETE /v1/files/{id} is a 409 evidence_file), they go with the bug.
object
db: the bytes are GET /v1/files/{id}; bucket: a new object in the project’s bucket, under a key of the bug’s.
What the streak last did, while it is the last move of the state; null after a person’s move, or when the streak never moved it (#2163).
object
The run of the move; null once it is in the Bin or gone.
object
The environment of that run, as it was then.
The case that failed - a regression’s; null on a close, or once the case is in the Bin or gone.
object
Example
{ "id": "6f1c2b3a-0000-4000-8000-0000000000f6", "key": "BUG-12", "number": 12, "source": "plune", "title": "The cart loses an item after a coupon is applied", "state": "open", "createdBy": "6f1c2b3a-0000-4000-8000-0000000000a2", "caseCount": 1, "commentCount": 2, "createdAt": "2026-09-16T09:12:04.151Z", "updatedAt": "2026-09-16T09:12:04.151Z", "streak": { "passed": 2, "n": 3, "canBeClosed": false, "flaky": false }, "autoClosed": false, "reopenedByRegression": false, "projectId": "u-shop::default", "description": "Add two items, apply the coupon `SPRING`, remove one: **both** are gone.", "stateReason": null, "closedAt": null, "closedBy": null, "cases": [ { "id": "6f1c2b3a-0000-4000-8000-0000000000c1", "title": "Cart keeps its items", "greenStreak": 2, "isFlaky": false } ], "watchers": [ "6f1c2b3a-0000-4000-8000-0000000000a2" ], "watching": true, "evidence": [ { "id": "7b3e1d2c-0000-4000-8000-00000000e066", "resultId": "6f1c2b3a-0000-4000-8000-0000000000e2", "runId": "6f1c2b3a-0000-4000-8000-0000000000d1", "resultState": "present", "snapshot": { "result": { "id": "6f1c2b3a-0000-4000-8000-0000000000e2", "status": "failed", "rawStatus": "failed", "source": "playwright", "subStatus": null, "outcome": "unexpected", "expectedStatus": "passed", "muted": false, "caseVersion": 3, "durationMs": 4120, "params": null, "createdAt": "2026-09-16T09:12:04.151Z" }, "errorContext": "Error: expect(received).toHaveCount(expected)\nExpected: 2\nReceived: 0", "errorContextTruncated": false, "failure": { "headline": "Expected 2 items in the cart, got 0", "steps": [ "open the cart", "apply SPRING", "remove one" ], "ciUrl": "https://ci.example.com/runs/77" }, "steps": null, "case": { "id": "6f1c2b3a-0000-4000-8000-0000000000c1", "title": "Cart keeps its items", "keys": [], "isFlaky": false, "isMuted": false }, "run": { "id": "6f1c2b3a-0000-4000-8000-0000000000d1", "title": "Nightly", "environment": "staging", "startedAt": "2026-09-16T09:12:04.151Z" }, "takenBy": "6f1c2b3a-0000-4000-8000-0000000000a2", "takenAt": "2026-09-16T09:12:04.151Z" }, "notCopied": [ { "fileId": "7b3e1d2c-0000-4000-8000-00000000e067", "name": "after-coupon.png", "reason": "budget" } ], "createdBy": "6f1c2b3a-0000-4000-8000-0000000000a2", "createdAt": "2026-09-16T09:12:04.151Z" } ], "files": [ { "id": "7b3e1d2c-0000-4000-8000-00000000e068", "name": "cart.png", "contentType": "image/png", "size": 48213, "storage": "db", "createdAt": "2026-09-16T09:12:04.151Z" } ], "streakMove": null}Invalid body
object
Example generated
{ "error": "example"}No / invalid token or session
You are in the project as a reader
No such bug in this project, or no such result
object
Example generated
{ "error": "example"}The bug holds 10 pieces of evidence already (code: evidence_limit)
object
Example generated
{ "error": "example"}The result did not fail (code: result_not_failed)
object
Example generated
{ "error": "example"}Rate-limited: the per-route throttle, or the per-minute request limit of the plan an API token counts by (#1442; the body names the plan, #2092). Retry-After carries the seconds until the window rolls over.
object
Example generated
{ "error": "example"}Headers
Section titled “Headers ”Seconds until the window rolls over