Every execution creates one account-scoped job. The same job resource is returned by the asynchronous execution path and by a `Prefer: wait` request whose wait window expires.

## Poll a job

```http
GET https://data.upscrape.com/jobs/JOB_ID
Authorization: Bearer UPSCRAPE_API_KEY
```

`GET /jobs/:id/result` remains available for compatibility and currently delegates to the same representation.

Jobs are account-scoped. A key from another account cannot retrieve them.

## Pending states

Queued, running, and retrying jobs return HTTP `202`:

```json
{
  "job_id": "job_id",
  "request_id": "job_id",
  "platform": "platform",
  "capability": "platform.capability.action",
  "state": "running"
}
```

Poll with bounded exponential backoff and jitter. A practical starting sequence is 1, 2, 4, 8, then 10 seconds. Stop after an application-defined deadline; timing out your local wait does not cancel the server-side job.

## Completed state

A completed job returns HTTP `200`, `state: "completed"`, `success: true`, a one-item `results` list, billing details, and execution statistics. Capability-specific JSON is under `results[0].data`.

Some supported q-commerce capabilities also include an additive `normalized` object. Raw output remains available and does not depend on normalization succeeding.

## Failed state

A failed job returns HTTP `200` with `state: "failed"`, `success: false`, and an error object:

```json
{
  "job_id": "job_id",
  "state": "failed",
  "success": false,
  "error": {
    "code": "upstream_error",
    "message": "sanitized failure description"
  },
  "results": null,
  "stats": null
}
```

Inspect the JSON state rather than treating every HTTP `200` poll response as success.

## Unknown jobs

An unknown or inaccessible job ID returns HTTP `404` with the stable `not_found` error code.
