Move a job — Resume, Retry, Cancel, Dismiss, or the producer’s report
const url = 'https://beta-api.plune.ai/v1/jobs/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/state';const options = { method: 'PATCH', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"state":"paused","reason":"Today’s AI quota is spent. It resumes by itself in 2 h.","cursor":"failure:41"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request PATCH \ --url https://beta-api.plune.ai/v1/jobs/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/state \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "state": "paused", "reason": "Today’s AI quota is spent. It resumes by itself in 2 h.", "cursor": "failure:41" }'A person: { action: resume } on a paused job (from its cursor — the same job, AC-03), { action: retry } on a failed one (from its cursor if it has one, else from the start; no new job — but not of a sync or an ingest: only running plune sync or plune ingest again retries one, so a browser session’s Retry of it is 403, #2027, #2085), { action: cancel } on a running, paused, action-needed or blocked one (it becomes cancelled, the reason «Cancelled by { action: dismiss } on a failed one (hidden from the list and the count; the second is the same 200, nothing written; audited as job/update, dismissed). The producer, from its API token only (a browser session is refused with 403 reports come from a producer token): { state, reason?, cursor? } — a stopped state says why; the state the job is already in, sent again with its reason and cursor or without them, is answered 200 with the job as it is and writes nothing. Any other move outside the table is 409 illegal_transition with the job’s state. Audited as job/state_change, the state and the reason before and after. A reader is refused with 403 read-only member.
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
object
Required on action_needed, paused, blocked and failed; refused on the other two. cancelled is a person’s, never a report (409).
Examples
The producer: the AI quota is spent
{ "state": "paused", "reason": "Today’s AI quota is spent. It resumes by itself in 2 h.", "cursor": "failure:41"}A person: Resume
{ "action": "resume"}The producer: an outside service is down
{ "state": "blocked", "reason": "Blocked by GitHub API — it has answered 503 since 14:10."}A person: Cancel
{ "action": "cancel"}A person: Retry
{ "action": "retry"}A person: Dismiss a failed job
{ "action": "dismiss"}Responses
Section titled “ Responses ”The job, moved
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": "ingest", "state": "in_progress", "subjectId": "6f1c2b3a-0000-4000-8000-0000000000d1", "subjectName": "nightly-e2e", "progress": { "done": 600, "total": 800 }, "reason": null, "cursor": "result:600", "attempt": 1, "createdAt": "2026-09-16T10:02:00.000Z", "startedAt": "2026-09-16T10:02:00.000Z", "finishedAt": null, "updatedAt": "2026-09-16T10:09:41.000Z"}The body is not JSON, or neither a button nor a report; a stopped state without its reason
object
Example generated
{ "error": "example"}No / invalid token or session
A reader asked, or a browser session sent a report — reports come from the producer’s API token; a job the server runs itself (bin-empty, #1388) takes no report at all; Cancel, Retry and Resume of a TestRail import are the project owner’s (403 project owner only); a browser session’s Retry of a sync or an ingest starts nothing and is refused (403 a job of this kind is retried by running its producer again, not from here, #2027, #2085)
object
Examples
{ "error": "read-only member"}{ "error": "reports come from a producer token"}No such job in this project
object
Example generated
{ "error": "example"}The move is not in the table (illegal_transition; a report of cancelled too), or the report is of an earlier try (stale_attempt)
object
Where the job is now — a producer learns from it that a person cancelled.
Only with stale_attempt: the try the job is on.
Example
{ "error": "job '6f1c2b3a-0000-4000-8000-0000000000a9' is blocked: it cannot move to in_progress this way", "code": "illegal_transition", "state": "blocked"}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