# Jobs

> Check, wait for, list and diagnose Nodaro jobs from an AI assistant, with the job envelope, statuses, held jobs, retryable failures and fallback models.

Source: https://nodaro.ai/docs/mcp/tools/jobs

The **job tools** let an assistant follow the work Nodaro does for it. Almost every generation tool starts a job and returns its id at once; `get_job` and `wait_for_job` report when it finishes and where the result is, `list_jobs` lists your recent jobs, and `diagnose_run` explains a failure. All four need the `jobs:read` permission and cost no credits.

## Job statuses

| Status | Meaning |
| --- | --- |
| `pending`, `queued`, `processing` | The job is waiting or running. Keep checking. |
| `pending_review` | The result exists, but the deployment holds it for a person to review. Keep checking, and never run the job again. |
| `completed` | The job is done. `outputUrl` and `outputData` hold the result. |
| `failed` | The job failed. Read `retryable` and `guidance`. |
| `cancelled` | The job was cancelled. |

A held job ends as `completed` when the reviewer approves it, or as `failed` with a policy reason when the reviewer rejects it. A client that follows the job through the MCP `tasks` API sees a held job as `input_required`: the decision belongs to the reviewer, so do not ask the user for new parameters.

## The job envelope

`get_job` and `wait_for_job` return the same structured result, the job envelope. `get_asset` returns it too, without `input`.

| Field | What it holds |
| --- | --- |
| `jobId`, `jobType` | The job id and what kind of job it is |
| `status`, `progress` | The status above, and the progress while it runs |
| `assetKind` | `image`, `video`, `audio`, or null for a text or data result |
| `outputUrl` | The finished image, video or audio |
| `outputData` | Structured output, such as a transcript, an alignment or an analysis |
| `input` | What the model was actually sent (see below), or null |
| `errorMessage` | The error of a failed job |
| `credits` | The credits of the job |
| `createdAt`, `startedAt`, `completedAt` | Timestamps |
| `retryable`, `guidance`, `suggestedProvider` | On a failed, cancelled or held job: whether the same request can succeed, a sentence on what to do, and a fallback model when one exists |

`input` is a safe subset of the request, enough to check what the model received. Nothing outside this list is included:

- `prompt`, the prompt as rendered, after pickers, subjects and references were folded in, and `userPrompt`, your own words.
- `negativePrompt`, and the `direction` and `subject` picker ids.
- `provider`, `model`, `duration`, `resolution` and `aspectRatio`.
- `imageUrl`, `endFrameUrl`, and the reference image, video and audio URLs.
- The job `type`.

## `get_job`

Returns one of your jobs by id, as the job envelope. Use it to check a job every 5 to 10 seconds until it finishes.

**Permission:** `jobs:read`. **Credits:** free.

| Parameter | Type | Notes |
| --- | --- | --- |
| `job_id` | string | **Required.** The id a generation tool returned. |

**Returns:** the job envelope.

## `wait_for_job`

Blocks until one of your jobs finishes, then returns the job envelope. Use it instead of a tight loop of `get_job` calls.

**Permission:** `jobs:read`. **Credits:** free.

| Parameter | Type | Notes |
| --- | --- | --- |
| `job_id` | string | **Required.** The job to wait for. |
| `timeout_s` | integer | Seconds to wait, from 1 to 120. Default `60`. |

**Returns:** the job envelope. When the job is still running at the deadline, the status is `timeout`. That is not an error: call `wait_for_job` again, or poll `get_job`. A held job answers `pending_review` at once. For a long video render, polling `get_job` every 5 to 10 seconds is better than repeated waits.

## `list_jobs`

Lists your recent jobs as structured data: status, type, output URL, error, credits and timestamps. Use it for questions such as "how many generations failed yesterday". When the user wants to see the results, use [`browse_gallery`](https://nodaro.ai/docs/mcp/tools/gallery-and-assets#browse_gallery), which shows a grid.

**Permission:** `jobs:read`. **Credits:** free.

| Parameter | Type | Notes |
| --- | --- | --- |
| `kinds` | array | Media kinds to include: any of `image`, `video`, `audio`. Default `["image", "video"]`, so audio is left out unless you ask for it. |
| `status` | string | One of `pending`, `queued`, `processing`, `pending_review`, `completed`, `failed`, `cancelled`. |
| `scope` | string | `mine` (default) for your own jobs, or `public` for recent public results of other users. |
| `limit` | integer | From 1 to 200. Default `50`. |
| `cursor` | string | The `next_cursor` of the previous page. |

**Returns:** a page of jobs and a `next_cursor` for the next page.

## `diagnose_run`

Explains why a workflow run or a single job failed. Pass either id: the tool tries a workflow run first and falls back to a job.

**Permission:** `jobs:read`. **Credits:** free.

| Parameter | Type | Notes |
| --- | --- | --- |
| `id` | string | **Required.** A workflow run id or a job id. |

**Returns:** for a workflow run, every node with its job id, type and status (`nodes`). This is the only tool that maps the nodes of a run to their job ids. Each failed node also carries its error message, its model, the credits actually charged (`creditsActual`), a failure class and a hint on how to fix it.

| Failure class | Meaning |
| --- | --- |
| `content_policy` | A safety filter blocked the prompt or the result |
| `validation` | The settings or the input were not accepted |
| `rate_limited` | The request hit a rate limit |
| `timeout` | The run took too long |
| `post_processing` | The model delivered, but a step after it failed |
| `provider_error` | The model's service returned an error |
| `unknown` | The error matches none of the classes above |

The class is a best guess from the error text, so treat it as guidance. Reserved credits are refunded automatically for every class except `post_processing`, because in that case the model already delivered its work.

## When a job fails

1. **Read `retryable`.** `false` means the same request will fail again unchanged. That happens after a content policy block, or when the model refused the combination of settings and input media.
2. **Follow `suggestedProvider`.** When a safety filter blocked the result and the catalog has a fallback model, the job names it. Run the same prompt and references on that model instead of guessing another one.
3. **Change the request when the model refused it.** An error that says the model rejected these settings means the duration, aspect ratio, resolution or a reference file does not fit that model. Change them, or pick a model whose capability sheet in [`list_models`](https://nodaro.ai/docs/mcp/tools/models-and-credits#list_models) allows the combination.
4. **Retry the rest.** A temporary error from the model's service stays `retryable`, even when its wording sounds like a validation problem.

More fixes are in [Troubleshooting](https://nodaro.ai/docs/mcp/troubleshooting).

## Frequently asked questions

### How often should an assistant poll a Nodaro job?

Every 5 to 10 seconds with get_job, or with wait_for_job, which blocks for up to 120 seconds. An image usually finishes within a minute and a video within 2 to 10 minutes.

### What does pending_review mean?

The deployment reviews results before release, and a person is checking this one. It is not a failure. Keep checking the job and never run it again, because a duplicate would be held too.

### What should the assistant do when a job fails?

Read retryable and guidance on the job. When retryable is false, change the settings or the input before trying again. When suggestedProvider is present, run the same prompt and references on that model.

### Do the job tools cost credits?

No. They read the status of work that already exists. Only the tools that start jobs spend credits.
