Delete several runs at once
const url = 'https://beta-api.plune.ai/v1/runs/bulk-delete';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"ids":["6f1c2b3a-0000-4000-8000-0000000000d1"],"sync":true}'};
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/runs/bulk-delete \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "ids": [ "6f1c2b3a-0000-4000-8000-0000000000d1" ], "sync": true }'#1423: the server deletes the runs as a job. The answer is 202 with the job (kind: runs-delete) — progress counts the runs named, total how many — and the job goes on whether or not anybody waits for it, ten runs at a time on the worker: GET /v1/jobs shows how far it got, and Cancel there (PATCH /v1/jobs/{id}/state, action: cancel) stops it after the piece in hand. A run that still takes results stays, as below, and is counted in the audit entry that closes the job; the job ends completed when the list is gone through, or failed with the reason (the caller may no longer delete here, the database kept failing). A Retry of a failed job cannot go on — the list is not kept — so it ends again at once: delete the runs again, what went is not deleted twice. With sync: true the call is the one it was, below: it answers when every run has been taken, which for runs of a million results can be past the server’s limit for a statement. The same soft delete as DELETE /v1/runs/{id} — the run and what it produced go to the Bin for 30 days — for one to 200 ids in a call (#1100, the Runs list’s «Delete» on a selection). Not all or nothing: each id is its own delete, in the order given, and the answer says which went and which stayed. A run that is still under way (open, or reopened by a rerun) stays — its reporter is still sending results — and is answered running; anything else that was not deleted is not_found: no such run, another project’s, or already in the Bin, never told apart. An id named twice is deleted once. Repeating a call is safe: whatever went is not_found the second time. A reader is refused at the boundary like every write (403). Every run taken leaves the delete entry the single delete leaves. DELETE /v1/runs/{id} itself still takes a run that is under way.
Authorizations
Section titled “Authorizations ”Request Body required
Section titled “Request Body required ”object
Run ids, one to 200.
#1423: the one call and its answer (deleted, skipped), as before the job — for a script that reads them.
Example
{ "ids": [ "6f1c2b3a-0000-4000-8000-0000000000d1" ], "sync": true}Responses
Section titled “ Responses ”With sync: which runs went to the Bin, and which stayed and why
object
The ids put in the Bin, in the order given.
object
running — the run still takes results; not_found — no such run for the caller, or it is already in the Bin.
Example
{ "deleted": [ "6f1c2b3a-0000-4000-8000-0000000000d1" ], "skipped": [ { "id": "3f2b9d3e-9d0c-4d3e-8b55-0a7e3a1c2b10", "reason": "running" } ]}The job that deletes the runs, opened now and queued
One long AI operation. Seven states: in_progress, action_needed (waits for a person — reason says for what), paused (the quota is spent; Resume, or it resumes by itself), blocked (an outside service failed — reason names it; no button), completed, failed (reason is the raw error; a person may Dismiss it), cancelled (a person’s Cancel — reason is «Cancelled by completed). progress is null while the operation does not know its size — never 0 / 0.
object
Which operation: ingest, sync, auto-analysis, and bin-empty — the Bin emptied by the server (#1388) — and runs-delete — runs deleted in the background (#1423) — today; open-ended.
What it works on — a run id, an import id.
Its name as people know it — shown after the kind.
How far it got; null while the size is not known yet.
object
Why it stopped — only on action_needed, paused, blocked, failed, cancelled. A cancel reads «Cancelled by
The producer’s own token for where it resumes; null — a Retry starts from the beginning.
Which try this is: 1, and one more for each Retry. A producer sends it back in its reports (attempt), and a report of an earlier try is 409 stale_attempt.
Set on completed, failed and cancelled, and only there.
Only on a run-export job in GET /v1/jobs and in the answer of GET /v1/runs/{id}/export (202): the run the file is of, so «Export again» works from any browser. A completed export stays in the list 7 days (its file goes after 24 hours).
Example
{ "id": "6f1c2b3a-0000-4000-8000-0000000000a9", "kind": "runs-delete", "state": "in_progress", "subjectId": null, "subjectName": null, "progress": { "done": 0, "total": 150 }, "reason": null, "cursor": "0", "attempt": 1, "createdAt": "2026-09-16T10:02:00.000Z", "startedAt": "2026-09-16T10:02:00.000Z", "finishedAt": null, "updatedAt": "2026-09-16T10:02:00.000Z"}Invalid body — no id, more than 200, an id that is not text, or not JSON
object
Examples
{ "error": "validation failed — ids: Too small: expected array to have >=1 items"}No / invalid token or session
read-only member of the project — a reader cannot delete
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