Skip to content

Report how far a job got

PATCH
/v1/jobs/{id}/progress
curl --request PATCH \
--url https://beta-api.plune.ai/v1/jobs/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/progress \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "done": 600, "total": 800, "cursor": "result:600" }'

The producer, every N records — N is its own setting (AC-06; the server’s own jobs take JOB_PROGRESS_EVERY, 500 by default). done of total, or both null while it is still counting. A report keeps a running job running and brings a waiting one back: an action_needed, paused or blocked job returns to in_progress and its reason is cleared. A finished job takes none — completed is the end, a failed one waits for a person’s Retry: 409 job_finished with its state. Not audited (machine intake, like results). Only from an API token — the producer’s: a browser session is refused with 403 reports come from a producer token, a reader with 403 read-only member. subjectId names what the job works on once the producer knows it (#1279) — only while the job names nothing: another value is 409 subject_set.

id
required
string format: uuid
X-Plune-Project
string

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.

Media type application/json
object
done
required

At most total. Null with total: still counting.

integer
nullable <= 2147483647
total
required
integer
nullable >= 1 <= 2147483647
cursor

Where to resume from. Absent keeps the stored one.

string
nullable <= 2000 characters
attempt

Job.attempt as the producer knows it. A report of another try than the job is on is 409 stale_attempt; absent, it is taken as the current try’s — the check is opt-in, a producer that omits it is not protected (only the server’s own bin-empty steps always send it).

integer
>= 1
subjectId

#1279: what the job works on, learnt after it was opened — a sync names its run once the upload gave it an id, and the run’s page then shows the job (GET /v1/jobs?runId=). Taken only while the job has none; the same value again changes nothing, another is 409 subject_set. Absent keeps it.

string
>= 1 characters <= 200 characters
Examples

600 of 800, and where to resume

{
"done": 600,
"total": 800,
"cursor": "result:600"
}

The job, as it is now

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": "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 not a report: one number without the other, done past total, a total of 0

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

Media type application/json
object
error
required
string
Examples
{
"error": "read-only member"
}

No such job in this project

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

The job is completed, failed or cancelled, the report is of an earlier try (stale_attempt), or it names another subject than the job has (subject_set)

Media type application/json
object
error
required
string
code
required
string
Allowed values: illegal_transition job_finished stale_attempt subject_set
state
required

Where the job is now — a producer learns from it that a person cancelled.

string
Allowed values: in_progress action_needed paused blocked completed failed cancelled
attempt

Only with stale_attempt: the try the job is on.

integer
>= 1
Example
{
"error": "job '6f1c2b3a-0000-4000-8000-0000000000a9' is failed: a finished job takes no progress",
"code": "job_finished",
"state": "failed"
}

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