# Tasks

## Task states

| Status       | Meaning                                             | Next step                                 |
| ------------ | --------------------------------------------------- | ----------------------------------------- |
| `processing` | The task has been accepted and is not yet finished. | Continue polling.                         |
| `completed`  | The task succeeded.                                 | Read `output.data[].url`.                 |
| `failed`     | The task did not complete successfully.             | Inspect `error`; the task is not charged. |

## Submission response

Submission returns a task reference:

```json
{
  "id": "task_...",
  "model": "gpt-image-2",
  "status": "processing",
  "created_at": 1789970508
}
```

### Poll the task

```bash
curl https://api.seedrouter.ai/v1/tasks/YOUR_TASK_ID \
  -H "Authorization: Bearer $SEEDROUTER_API_KEY"
```

Poll at a modest interval, such as every three seconds, until `status` is `completed` or `failed`. A network timeout while polling does not mean generation failed: keep the task ID and resume checking it. Do not create another task to check progress.

### Complete polling example

Run this after the Python submission example in the [Quickstart](https://seedrouter.ai/docs/api/quickstart). It uses the returned `task_id` and waits up to ten minutes. Reaching this local deadline stops polling only; retain the ID and resume querying the same task.

```python
import time

print(f"Task ID: {task_id}")
deadline = time.monotonic() + 600
while time.monotonic() < deadline:
    result = requests.get(
        f"https://api.seedrouter.ai/v1/tasks/{task_id}",
        headers={"Authorization": f"Bearer {os.environ['SEEDROUTER_API_KEY']}"},
        timeout=30,
    )
    result.raise_for_status()
    task = result.json()
    if task["status"] == "completed":
        for image in task["output"]["data"]:
            print(image["url"])
        break
    if task["status"] == "failed":
        raise RuntimeError(task["error"]["message"])
    time.sleep(3)
else:
    raise TimeoutError(f"Still waiting. Resume polling task {task_id}.")
```

### Completed task

A completed task returns hosted image URLs and usage:

```json
{
  "id": "task_...",
  "model": "gpt-image-2",
  "status": "completed",
  "created_at": 1789970508,
  "finished_at": 1789970538,
  "output": {
    "created": 1789970532,
    "data": [{"url": "https://static.seedrouter.ai/media/tasks/task_example/0.png"}],
    "usage": {
      "input_tokens": 29,
      "output_tokens": 196,
      "total_tokens": 225
    }
  }
}
```

| Field                       | Meaning                                                                                       |
| --------------------------- | --------------------------------------------------------------------------------------------- |
| `id`                        | Keep this ID for subsequent queries.                                                          |
| `status`                    | `processing`, `completed`, or `failed`.                                                       |
| `created_at`, `finished_at` | Unix timestamps in seconds; completion time is unset or zero while processing.                |
| `output.data[].url`         | Generated image URLs, available on completion.                                                |
| `output.usage`              | Reported token usage, when available. Detail objects may contain text and image token counts. |
| `error`                     | Structured error on a failed task.                                                            |

This API uses asynchronous task delivery. It is not a synchronous Images SDK replacement; `stream` and `partial_images` are not supported.
