> ## Documentation Index
> Fetch the complete documentation index at: https://docs.api.rask.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Jobs and long-polling

> How long-running work behaves in the Rask API v3: job statuses, waiting with wait_seconds, Retry-After, overdue jobs, retention and cancellation.

Long work in this API is a job. A call that starts one answers `202` with the `Job` and `Location: /v3/jobs/{job_id}`. ([createProjectCopies](https://docs.api.rask.ai/operations/createProjectCopies.md) starts several, so it answers with a list and no
`Location`; each job has `links.self`.)

## Status

A job moves one way and never back:

```text theme={null}
queued -> running -> succeeded | failed | canceled
```

| Status | Then |
| - | - |
| `succeeded` | Read `result` |
| `failed` | Read `error`. See [Handle errors](https://docs.api.rask.ai/v3/recipes/spend-balance-errors.md#handle-errors) |
| `canceled` | It was canceled, or its project was deleted (`error.code` is `project_deleted`) |

Because status never moves back, [resuming a failed run](https://docs.api.rask.ai/v3/recipes/localization-run.md#5-resume-a-failed-run) makes a new job, and a failed job needs a new `Idempotency-Key` to start again.

## Waiting

```typescript TypeScript theme={null}
const { data: job } = await rask.jobs.getJob({ path: { job_id: jobId }, query: { wait_seconds: 20 } });
```

```python Python theme={null}
job = client.jobs.get_job(job_id, wait_seconds=20)
```

```go Go theme={null}
job, err := client.Jobs.GetJob(ctx, jobID, &api.GetJobParams{WaitSeconds: rask.Ptr(int32(20))})
if err != nil {
	return err
}
```

```java Java theme={null}
Job job = rask.jobs().getJob(jobId, GetJobParams.builder().waitSeconds(20).build()).data();
```

```php PHP theme={null}
$job = $rask->jobs->getJob($jobId, ['wait_seconds' => 20]);
```

```bash cURL theme={null}
curl "https://api.rask.ai/v3/jobs/$JOB_ID?wait_seconds=20" \
  -H "Authorization: Bearer $RASK_API_KEY"
```

`wait_seconds`, 20 at most, holds the request until the job changes or ends, or until the wait is over. Loop on it until a terminal status, and do not ask faster than the `Retry-After` header of the answer, which holds the poll hint of the job's type.

With `If-None-Match` set to the `ETag` of the last answer, an unchanged job answers 304. A terminal job ignores it and always answers 200, because a refund or fresh links can change the body after the job ended.

By default a key may hold 10 waits at once, and a payer 50; a trial allows fewer. These counts are approximate, like the [request limits](https://docs.api.rask.ai/v3/concepts/capabilities.md#rate-limits). Beyond them a wait answers 429 [`too_many_waiters`](https://docs.api.rask.ai/errors/too_many_waiters): wait `Retry-After`, or ask again without `wait_seconds`.

## How long a job takes

`estimated_finish_at` estimates the end from the queue position and the type's typical duration, and turns null once the job runs past that estimate. An on-screen job that has started shows its run's own estimate instead. `queue_position` says where the job stands in its queue (1 is next). Only a lip-sync or on-screen job that waits in a queue has one, and a `localization` run shows its running stage's; otherwise it is null. `x-rask-operation.typical_duration_seconds` in the contract holds a p50 and a p95 per
starting operation. They are typical durations, not guarantees or deadlines.

| Job `type` | Started by | Poll hint | Typical (p50 / p95) |
| - | - | - | - |
| `media_import` | [completeUpload](https://docs.api.rask.ai/operations/completeUpload.md) | 3 s | 30 s / 5 min |
| `media_import` | [importMedia](https://docs.api.rask.ai/operations/importMedia.md) | 3 s | 1 min / 10 min |
| `project_processing` | [createProject](https://docs.api.rask.ai/operations/createProject.md), [createProjectCopies](https://docs.api.rask.ai/operations/createProjectCopies.md), [importTranscript](https://docs.api.rask.ai/operations/importTranscript.md) | 10 s | 5 min / 30 min |
| `translation` | [retranslateSegments](https://docs.api.rask.ai/operations/retranslateSegments.md), edits that retranslate | 5 s | 30 s / 5 min |
| `segment_generation` | [generateSegments](https://docs.api.rask.ai/operations/generateSegments.md) | 5 s | 30 s / 5 min |
| `dub` | [createDub](https://docs.api.rask.ai/operations/createDub.md), auto-dub | 10 s | 5 min / 30 min |
| `lipsync` | [createLipsync](https://docs.api.rask.ai/operations/createLipsync.md) | 30 s | 30 min / 1 h 30 min |
| `onscreen` | [createOnscreen](https://docs.api.rask.ai/operations/createOnscreen.md), auto-start | 15 s | 1 h / 2 h 15 min |
| `localization` | [createLocalization](https://docs.api.rask.ai/operations/createLocalization.md), [resumeJob](https://docs.api.rask.ai/operations/resumeJob.md), a `createProject` block | 15 s | 1 h 35 min / 4 h 15 min |
| `voice_clone` | [createVoiceClone](https://docs.api.rask.ai/operations/createVoiceClone.md) | 10 s | 1 min / 10 min |
| `export` | [createExport](https://docs.api.rask.ai/operations/createExport.md) | 15 s | 5 min / 30 min |
| `file_restore` | [createFileRestore](https://docs.api.rask.ai/operations/createFileRestore.md) | 300 s | 4 h / 12 h |

For long jobs, keep the id and check back later rather than hold a wait for hours. The wait of an [SDK](https://docs.api.rask.ai/v3/sdks.md) gives up after 4 hours unless you pass a longer timeout, and the job keeps running. A `localization` run can take longer than that (p95 4 h 15 min), and a `file_restore` often does (p50 4 h, p95 12 h), so give their waits a longer timeout, or save the id and check back. `overdue` turns true when a job runs well past its type's typical duration: Rask is alerted, and the job may still finish. Keep waiting or check back later, and do not start the same work again.

## What a job holds

| Field | Meaning |
| - | - |
| `type`, `status`, `stage`, `progress` | What runs and how far. `progress` is 0 to 100, or null when the type has no honest progress |
| `params` | An echo of the start request |
| `details` | Live state. On-screen jobs only today |
| `stages` | The stages of a `localization` job |
| `cost` | What the job costs: [Read the cost of a job](https://docs.api.rask.ai/v3/recipes/spend-balance-errors.md#read-the-cost-of-a-job) |
| `result` | Set when it succeeded; a failed `segment_generation` job may also list the clips it voiced. Its links are minted at read time, so read it again for fresh ones |
| `error` | Set when it failed, and on a job canceled because its project was deleted |
| `parent_job_id` | The job that started this one: the `project_processing` job of an auto-dub or of a `createProject` localization block, the dub before an on-screen auto-start, the `localization` job of a stage, the failed run a resumed run continues |
| `channel` | `api`, `mcp` or `system` for automatic follow-up work |
| `links` | `self`, `project`, `outputs`, `media` |

## Which work has a job

Jobs exist for work started through v3, and for automatic follow-up work on projects created through v3. Work started in the web app or API v2 has no job: read `processing_state` on the project, or the [lip-sync](https://docs.api.rask.ai/operations/getLipsyncState.md) and
[on-screen](https://docs.api.rask.ai/operations/getOnscreenState.md) state, where such a result shows with `job_id: null`.

A finished job can be read and listed for 90 days after it ends. After that it answers 404 [`job_not_found`](https://docs.api.rask.ai/errors/job_not_found).

## Canceling

[cancelJob](https://docs.api.rask.ai/operations/cancelJob.md) works on two kinds of job: a `media_import` that has not ended, and an `onscreen` job that is queued and not charging (its minutes come back). Everything else answers 409 [`job_not_cancelable`](https://docs.api.rask.ai/errors/job_not_cancelable), including a
`localization` run and an `onscreen` job that is one of its stages. A job that has already ended answers 409 [`job_already_finished`](https://docs.api.rask.ai/errors/job_already_finished).

Deleting a project ends its active jobs as `canceled`, and discards their work: only on-screen runs are refunded. A project with active spending work answers 409 [`project_busy`](https://docs.api.rask.ai/errors/project_busy) unless you send `force=true`.

## Listing

[listJobs](https://docs.api.rask.ai/operations/listJobs.md) lists jobs newest first and filters by `project_id`, `media_id`, `type`, `status`, `channel` and `created_after`; `type` and `status` take comma-separated lists. A job another key started is read and listed only with the scope that reads what it works on: see [Scopes](https://docs.api.rask.ai/authentication.md#scopes). A project's own `active_jobs` lists its jobs that have not ended.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.