---
title: "Get Job processing details"
method: GET
path: "/api/v1/jobs/{job_id}/details"
tags: ["jobs"]
---

# Get Job processing details

`GET /api/v1/jobs/{job_id}/details`

## Request

- Base URL: `https://platform-api.transform.unstructured.io` (the document declares no server; this is the origin it was published from)
- URL: `https://platform-api.transform.unstructured.io/api/v1/jobs/{job_id}/details`
- Auth: none declared
- TypeScript: <https://skmtc.dev/unstructured/apis/platform-api/docs/api/v1/jobs/:job_id/details/get.ts> (a function with typed inputs; its response is checked against the schema)

Retrieve processing details for a specific job by its ID.

## Path parameters

- `job_id` string, uuid, required

## Headers

- `unstructured-api-key` string, nullable

## Response `200`

Successful Response

- JobDetails
  - `id` string, uuid, required
  - `processing_status` 'SCHEDULED' | 'IN_PROGRESS' | 'SUCCESS' | 'COMPLETED_WITH_ERRORS' | 'STOPPED' | 'FAILED' | 'REJECTED', required
  - `node_stats` JobNodeDetails[], required
    - `node_id` string, nullable: Id of this step in the workflow DAG. This is the key `progress.slowest_node_id` names -- join on it rather than on `node_name`, which is mutable. A saved workflow's node id is a UUID; a custom DAG's is whatever its author called it. Null on the standalone job shape, whose spec does not guarantee a node id.
    - `node_name` string, nullable
    - `node_type` string, nullable
    - `node_subtype` string, nullable
    - `ready` integer, required
    - `in_progress` integer, required
    - `success` integer, required
    - `failure` integer, required
    - `failure_category` 'AUTH_INVALID_CREDENTIAL' | 'AUTH_PERMISSION_DENIED' | 'AUTH_NETWORK_UNREACHABLE' | 'AUTH_PROVIDER_UNAVAILABLE' | 'PROVIDER_RATE_LIMITED' | 'CONFIG_INVALID' | 'UNKNOWN': Stable, machine-routable category for a per-node check failure. This enum is the contract customers route on. Shared with the existing connection-check path. ``UNKNOWN`` is the forward-compatible default (no category supplied, or an unrecognized value).
    - `failure_reason` string, nullable: Human-readable detail, forwarded from the provider. Free-form and unstable: it changes with third-party error text, so show it to a person and never parse it.
    - `node_phase` 'PENDING_CREATE' | 'IDLE_ZERO' | 'SCHEDULING' | 'UNSCHEDULABLE' | 'STARTING' | 'RUNNING' | 'UNSTARTABLE' | 'CRASH_LOOPING' | 'UNKNOWN': Runtime state of a DAG node's Kubernetes workload. NOT document counts. An unrecognised value reads as UNKNOWN.
    - `node_phase_observed_at` string, date-time, nullable: When the data plane observed the phase. Trails live cluster state.
    - `last_change_at` string, date-time, nullable: When this step last reported new counts. Null when it has not reported at all. Source steps never report, so they are listed here with this field null rather than being left out. Stager steps are not DAG nodes and are never listed. It means this step's counters changed, not that a document finished: a document moving from ready to in progress moves this too.
  - `summary` JobAggregations
    - `total_docs` integer
    - `total_docs_succeeded` integer
    - `total_docs_failed` integer
  - `message` string, nullable
  - `progress` JobProgressInfo: Why this job is not finished yet, as of `as_of`. Advisory: a heuristic read of per-node counters, not a contract, and not the clock that terminates a job.
    - `state` 'not_applicable' | 'starting' | 'waiting_to_start' | 'progressing' | 'no_recent_progress' | 'unknown', required: Why a job is not finished yet. Lives here, not beside the classifier that produces it: models must not import from services, and this enum is part of the response contract.
    - `as_of` string, date-time, required: When this progress read was computed. Every age in this object is measured from here, not from when you received the response.
    - `message` string, required: The measurement stated for a person. One or more sentences -- the step the job is sitting in, a pending stop, cancelling as an option and the other jobs running in this workspace are each appended when they apply. Free-form and unstable: the wording changes between releases, so display it and never parse it.
    - `last_node_change_at` string, date-time, nullable: The most recent time any step reported new counts. Null when no step has reported at all -- read `nodes_observed` to tell that case apart. It means the counters changed, not that a document finished: a document moving from ready to in progress moves this too.
    - `seconds_since_node_change` integer, nullable: Seconds between `last_node_change_at` and `as_of`. Null when no step has reported, and null when that timestamp is in the future -- these are pod clocks, so a negative age is reported as unmeasurable rather than as 0. A step grinding one large document holds its counts constant while perfectly healthy, so a large value is a measurement, not a verdict that the job is broken.
    - `seconds_without_report` integer, nullable: How long this job has gone with no step reporting any work, in seconds. Measured from submission while it is waiting to start, and from when it started running once it is running. Null once `nodes_observed` is above 0 -- read `seconds_since_node_change` from that point on.
    - `nodes_observed` integer: How many steps have reported counts. 0 means none has yet. Source and stager steps never report, so a job wedged fetching its source reports 0 here instead of naming the step it is stuck in.
    - `slowest_node_id` string, nullable: The step with work still outstanding whose counts are oldest -- where the job currently sits. Null when no step has outstanding work. This says where the job is, not that this step is at fault.
    - `slowest_node_name` string, nullable: Display name of `slowest_node_id`, null whenever that is null. Names are mutable -- key on `slowest_node_id`, which every entry in `node_stats` carries as its own `node_id`.
    - `outstanding_docs` integer, nullable: Documents still ready or in progress at `slowest_node_id`, null whenever that is null. This is the number `message` states, carried as an integer so it never has to be parsed back out of the prose.
    - `other_active_jobs` ActiveJob[]: Other `SCHEDULED` or `IN_PROGRESS` jobs in this workspace, oldest first. The list is capped, so read `other_active_jobs_total` for how many there really are. These jobs share the workspace; none of them is asserted to be blocking this one. Empty whenever `state` is `not_applicable`, where the workspace is not measured at all.
      - `job_id` string, uuid, required: Id of the other job. Follow it with GET /jobs/{id}/details to see why that one is not finished.
      - `workflow_id` string, uuid, nullable: Workflow the other job belongs to. Null for an on-demand or playground job, which is submitted without one.
      - `workflow_name` string, nullable: Display name of that workflow, null whenever `workflow_id` is null. Names are mutable -- key on `workflow_id`.
      - `status` 'SCHEDULED' | 'IN_PROGRESS' | 'COMPLETED' | 'STOPPED' | 'FAILED' | 'REJECTED', required
      - `created_at` string, date-time, required: When the other job was submitted. The list is ordered oldest first.
    - `other_active_jobs_total` integer: Uncapped number of other non-terminal jobs in this workspace. It can exceed the length of `other_active_jobs`; quote this number, not the list length. Reads 0 whenever `state` is `not_applicable`, which means not measured rather than none running -- ask `GET /jobs/` if you need the workspace count beside a finished job.
    - `stop_requested_at` string, date-time, nullable: When a stop was requested for this job, null if none was. A job with this set is already cancelling, so do not cancel it again.
  - `queued_behind_job_ids_snapshot` string[], nullable: Job ids that held this workspace's concurrency slots at the instant this run was queued. Taken once and never refreshed, so the jobs named here may have finished long ago. It is not the set of jobs this run is waiting on, and it errs in both directions: runs queued ahead of this one but not yet started sit on the FIFO queue rather than in a slot, so they are absent; and the snapshot is taken at queue time whether or not the jobs it names are what kept this run waiting, since a held slot is not by itself the workspace being full at its `tenant_max_concurrent_jobs` limit. Show it as what held a slot at that moment, never as the cause of a delay or as a complete list of blockers. Null means no snapshot exists -- the run did not go through the queue, or the read failed -- which is not the same as `[]`, meaning the snapshot was taken and nothing held a slot. For what is running now, read `progress.other_active_jobs`, which is a live read.
  - `completion_issue` 'NO_DOCUMENTS_DISCOVERED' | 'NO_DOCUMENTS_SUCCEEDED': Why a COMPLETED job delivered no document. Read for what a run did; the verdict only says whether anything was lost. A run whose source handed back nothing finishes `processing_status: SUCCESS` with an empty destination, and without this there is no statement anywhere that it moved nothing (Pylon 2287, PLU-622). A run that discovered documents and delivered none of them without failing any is FAILED, and carries this for the same reason: nothing else on the row explains it. A run whose documents failed carries none of these; `/failed-files` explains it. So the verdict cannot be used to find these runs, and a caller that wants to know whether a job delivered anything branches on this field. Its own type on its own nullable field, deliberately NOT a `JobProcessingStatus` member: that enum is on the public wire and a closed generated-SDK enum breaks a whole `list_jobs` page on one unrecognised value (DTPL-696, `REJECTED`). Null is "no issue detected", never "checked and fine" -- a caller must not read the absence of a value as a guarantee, and a job FAILED for some other reason (a failed document, a preflight rejection) carries none of these. New members may be added; treat an unrecognised one as "an issue was detected, of a kind this client does not know".

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/unstructured/apis/platform-api.md) - [All operations](https://skmtc.dev/unstructured/apis/platform-api/llms.txt) - [OpenAPI document](https://skmtc.dev/unstructured/apis/platform-api/revisions/16b4542093db?raw)
