Skip to content

Delete several runs at once

POST
/v1/runs/bulk-delete
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.

Media type application/json
object
ids
required

Run ids, one to 200.

Array<string>
>= 1 items <= 200 items
sync

#1423: the one call and its answer (deleted, skipped), as before the job — for a script that reads them.

boolean
Example
{
"ids": [
"6f1c2b3a-0000-4000-8000-0000000000d1"
],
"sync": true
}

With sync: which runs went to the Bin, and which stayed and why

Media type application/json
object
deleted
required

The ids put in the Bin, in the order given.

Array<string>
skipped
required
Array<object>
object
id
required
string
reason
required

running — the run still takes results; not_found — no such run for the caller, or it is already in the Bin.

string
Allowed values: running not_found
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

Media type application/json

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 »; not an error, no button, listed for 24 hours like completed). progress is null while the operation does not know its size — never 0 / 0.

object
id
required
string format: uuid
kind
required

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.

string
>= 1 characters <= 64 characters
state
required
string
Allowed values: in_progress action_needed paused blocked completed failed cancelled
subjectId
required

What it works on — a run id, an import id.

string
nullable
subjectName
required

Its name as people know it — shown after the kind.

string
nullable <= 200 characters
progress
required

How far it got; null while the size is not known yet.

object
done
required
integer
total
required
integer
>= 1
reason
required

Why it stopped — only on action_needed, paused, blocked, failed, cancelled. A cancel reads «Cancelled by ».

string
nullable <= 2000 characters
cursor
required

The producer’s own token for where it resumes; null — a Retry starts from the beginning.

string
nullable <= 2000 characters
attempt
required

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.

integer
>= 1
createdAt
required
string format: date-time
startedAt
required
string format: date-time
nullable
finishedAt
required

Set on completed, failed and cancelled, and only there.

string format: date-time
nullable
runId

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).

string
updatedAt
required
string format: date-time
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

Media type application/json
object
error
required
string
Examples
Example noIds
{
"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

Media type application/json
object
error
required
string
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.

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

Seconds until the window rolls over