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

# Polling for status

> Track a generation or bulk job until it completes

Every generate call returns a job reference immediately, before rendering finishes. Use the status endpoints to check progress — or better, use a [webhook](/docs/guides/webhooks) so you don't have to poll at all.

## The whole job

```bash theme={null}
curl "https://dev-backend-ai.truefans.in/api/external/v1/bulk-jobs/{bulk_job_id}/status/" \
  -H "Authorization: Bearer $TRUEFAN_API_KEY"
```

A job's own `status` reflects every row as a whole. `summary.pending` tells you how many rows are still in flight — poll until it reaches zero, then check `csv_ready` and download [the CSV export](/docs/api-reference/status/export-bulk-job-csv) for every row's result.

## One video

While a batch is still processing, check a specific row using the `external_id` you supplied for it — you won't have TrueFan's own `generation_id` until the batch is done:

```bash theme={null}
curl "https://dev-backend-ai.truefans.in/api/external/v1/bulk-jobs/{bulk_job_id}/generations/{external_id}/status/" \
  -H "Authorization: Bearer $TRUEFAN_API_KEY"
```

`status` is one of `pending`, `processing`, `success`, `failed`. Once it reaches `success`, `result_video_url` and `thumbnail_url` are populated. Once `failed`, `error_message` explains why.

Once the batch is done, [download the CSV export](/docs/api-reference/status/export-bulk-job-csv) instead — it has every row's result, not just one, in a single request.

## A simple polling loop

```python theme={null}
import time
import requests

def wait_for_batch(bulk_job_id, api_key, timeout_s=300, interval_s=3):
    url = f"https://dev-backend-ai.truefans.in/api/external/v1/bulk-jobs/{bulk_job_id}/status/"
    headers = {"Authorization": f"Bearer {api_key}"}
    deadline = time.monotonic() + timeout_s

    while time.monotonic() < deadline:
        resp = requests.get(url, headers=headers)
        resp.raise_for_status()
        data = resp.json()
        if data["csv_ready"]:
            return data
        time.sleep(interval_s)

    raise TimeoutError(f"bulk job {bulk_job_id} did not finish in {timeout_s}s")
```

<Warning>
  Polling too aggressively (sub-second intervals) doesn't make a render finish faster — a few seconds between checks is plenty. Prefer a [webhook](/docs/guides/webhooks) over polling entirely where you can.
</Warning>
