# Jobs and progress

Poll status, receive SSE updates, or request cancellation.

## Get a job

`GET /jobs/:id` requires the owning account. No body.

```json
{
    "job": {
        "id": "job_example",
        "type": "download",
        "status": "processing",
        "phase": "downloading",
        "progress": 35,
        "result": null,
        "error": null
    }
}
```

This is a shortened response. `progress` is a percentage from 0 to 100. Phase and progress are best-effort execution information; do not use them instead of `status` to decide whether a job is done.

```mermaid
stateDiagram-v2
    accTitle: Job status transitions
    accDescr: Queued work starts processing; completion, failure and cancellation stop normal polling.
    [*] --> queued
    queued --> processing
    queued --> cancelled
    processing --> completed
    processing --> failed
    processing --> cancelled
    completed --> [*]
    failed --> [*]
    cancelled --> [*]
    note right of processing
      Phase and progress describe work.
      Use status to decide when to stop.
    end note
```

| Status       | What your client should do                          |
| ------------ | --------------------------------------------------- |
| `queued`     | Keep waiting within a bounded polling window        |
| `processing` | Keep waiting; show phase/progress if useful         |
| `completed`  | Read the result and obtain file URLs                |
| `failed`     | Stop; show or record `job.error`                    |
| `cancelled`  | Stop; do not expect a result                        |
| `expired`    | Stop; the job is no longer available as active work |

## Completed results

A result can contain `fileId`, `files`, and an optional `thumbnailUrl`. The array contains `{ "fileId": "fil_example", "thumbnailUrl": "..." }` entries; thumbnails are optional.

```javascript
const files = job.result.files ?? [{ fileId: job.result.fileId }];
```

When the array exists, consume it rather than only its first element. A source album can return many files. These IDs are API file identities, not storage object keys.

## Explore a result

Switch between one file and an album, then select an item to see which lookup to make.

```visual
result-files
```

## Cancel a job

`POST /jobs/:id/cancel` requires the owning account and no body. It returns `200` with `{ "job": { ... } }` after cancellation is accepted.

A terminal job or a job that finishes during the cancellation attempt can return `409 JOB_NOT_CANCELLABLE`. Cancellation is not a deletion API for previously stored files.

## Server-sent events

`GET /jobs/:id/events` returns `text/event-stream` and uses the same authorization as job status. The event name is `job.updated`; its data is a JSON job snapshot. Comment heartbeats keep the stream alive.

```bash
curl -N 'https://api.mediafilez.online/api/v1/jobs/job_example/events' \
  -H "Authorization: ApiKey $MEDIAFILEZ_API_KEY"
```

An initial snapshot is sent, but event history is not replayed after reconnects. Recover by fetching the current job or polling. A browser's native `EventSource` cannot set an API-key header; use it only with an appropriate cookie-based session, or stream from your backend.

## Request examples

Choose a language. JavaScript and Node.js examples use a server environment, not a public browser key. Replace illustrative IDs with your own.

### Read job status

```request
{
    "method": "GET",
    "path": "/jobs/job_example"
}
```

### Cancel active work

```request
{
    "method": "POST",
    "path": "/jobs/job_example/cancel"
}
```
