# Jobs and polling (https://docs.propertypixel.app/jobs)

How edits run in the background and how to wait for results.



Every edit you start (enhance, stage, apply recommendations, video) returns immediately with one **job** per result. Jobs run in the background:

| Kind          | Typical time                |
| ------------- | --------------------------- |
| `enhancement` | 30–90 seconds               |
| `staging`     | 30–90 seconds per variation |
| `video`       | a few minutes               |

## Statuses [#statuses]

`pending` → `processing` → `completed` | `failed` | `cancelled`

A failed job is refunded automatically, and its `error` holds a `code` and a `message`.

## Polling [#polling]

Call `get_job_status` (REST: `GET /v1/jobs?ids=<id>,<id>`, up to 100 IDs). The response contains:

* `jobs`: the current state of each job, with `progress` (0–100) while processing.
* `all_done`: `true` once every job has reached a final status.
* `poll_after_ms`: how long to wait before polling again (`0` when everything is done).

Wait `poll_after_ms` between calls. In ChatGPT and Claude, the PropertyPixel widget polls for you and shows progress live.

```bash
curl "https://api.propertypixel.app/v1/jobs?ids=$JOB_ID" \
  -H "Authorization: Bearer $PROPERTYPIXEL_API_KEY"
```

## Results [#results]

When a job is `completed`, `result` is `{ url, expires_at }`. The URL is a signed link that stays valid for about an hour. Fetch the job again for a fresh link. `thumbnail` is a smaller preview. Trial accounts receive watermarked results (`watermarked: true`).

To download several results as one file, use `get_download_link` (`POST /v1/downloads`) with `job_ids`, or `project_id` plus `picks_only: true`.

## Webhooks instead of polling [#webhooks-instead-of-polling]

Scripts can subscribe to `job.completed`, `job.failed` and `video.completed` instead of polling. See [Webhooks](/docs/webhooks).
