# Runs & results

Create, follow, find and cancel a generation.

A run is one generation request. Submit it once, keep its ID, then receive its result by [webhook](/api/webhooks) or read it from the API. The same run is returned through either channel.

## Create a run

```bash
curl 'https://fusara.ai/api/v3/run' \
  -H "Authorization: Bearer $FUSARA_API_KEY" \
  -H 'Content-Type: application/json' \
  --data-raw '{
  "model": "qwen-image21-create",
  "prompt": "A white ceramic lamp on a pale lavender background, soft studio light."
}'
```

Put model settings at the top level alongside `model`. Use the exact ID and fields from the [model catalog](/api/models); do not wrap inputs in `input`, `parameters` or `options`.

The response is `202` while processing and `200` if already terminal. Keep `id` immediately. The `Location` header points to the same run resource.

## Understand the lifecycle

| Status | Meaning | Next step |
| --- | --- | --- |
| `queued` | Accepted and waiting for execution. | Wait for a webhook or read again later. |
| `running` | Execution is in progress. | Continue waiting. |
| `succeeded` | Generation finished successfully. | Save the outputs. |
| `failed` | Generation ended with an error. | Read `error` and preserve any partial outputs. |
| `canceled` | Canceled before execution admission. | No further generation result is expected. |

The final three statuses are terminal. Stop polling for generation progress when you see one of them. Billing can still settle afterward: `cost.status` has its own lifecycle, described in [Balance & pricing](/api/billing#understand-the-final-charge).

## Read a result

```bash
curl 'https://fusara.ai/api/v3/run/123456' \
  -H "Authorization: Bearer $FUSARA_API_KEY"
```

Polling every few seconds is a reasonable starting point; increase the interval for longer generations. Polling frequency does not speed up execution. A read returning HTTP `200` can contain a failed run.

```json
{
  "id": 123456,
  "status": "succeeded",
  "cost": {
    "unit": "common_fuz",
    "expected": "40.0000",
    "status": "settled",
    "charged": "40.0000"
  },
  "outputs": [
    {
      "type": "image",
      "media_id": 901,
      "url": "https://media.example/result.png",
      "url_expires_at": "2026-10-25T12:00:00Z"
    }
  ]
}
```

Outputs are typed. For `image`, `video` and `audio`, use `url` and keep `media_id` if you want to reuse the media. For `text`, `json` and `boolean`, read `value`. A run can have more than one output. Follow the types and fields returned by your model rather than assuming every result is an image.

For example, inline results use the same field for each type:

```json
{
  "id": 123457,
  "status": "succeeded",
  "cost": {
    "unit": "common_fuz",
    "expected": "10.0000",
    "status": "settled",
    "charged": "10.0000"
  },
  "outputs": [
    {
      "type": "text",
      "value": "A cat sitting on a windowsill."
    },
    {
      "type": "json",
      "value": {
        "objects": [
          "cat"
        ],
        "count": 1
      }
    },
    {
      "type": "boolean",
      "value": false
    }
  ]
}
```

`json` values are native JSON, not JSON encoded inside a string. Preserve `false`, `0`, empty strings and `null`; they are values, not missing results. Webhooks contain these same output objects.

Save files before `url_expires_at`. Expired output metadata can remain available with `expired: true` and no URL. Reading a run does not guarantee that its files are still downloadable.

## Retry a submission safely

`Idempotency-Key` is optional. Use it when your application may repeat a submission after a connection failure. Create one key per intended generation and persist it with the original body before sending.

```bash
curl 'https://fusara.ai/api/v3/run' \
  -H "Authorization: Bearer $FUSARA_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: product-784-cover-v1' \
  --data-raw '{
  "model": "qwen-image21-create",
  "prompt": "A white ceramic lamp on a pale lavender background, soft studio light."
}'
```

Repeating the same key and request for the same account returns the original run instead of generating again. Keep the request unchanged, including `webhook_url`. Reusing a key for a different request returns `422 idempotency_conflict` with `retryable: false`.

If the original submission is still being accepted, the replay returns `409 request_in_progress` with `retryable: true` and `Retry-After: 2`. Wait for the indicated delay, then retry with the same key and unchanged body.

A new key means a new generation. Do not generate a fresh key inside an automatic retry loop. If you already know the run ID, retrieve that run instead of submitting again. See [uncertain submission outcomes](/api/errors#when-a-submission-times-out).

## Browse run history

```bash
curl 'https://fusara.ai/api/v3/run?status=succeeded&model=qwen-image21-create' \
  -H "Authorization: Bearer $FUSARA_API_KEY"
```

History contains your account's API v3 runs. It returns up to **100 runs per page**, newest first; there is no `limit`, `page` or `offset` parameter for runs.

| Filter | Value | Behavior |
| --- | --- | --- |
| `model` | An exact public model ID. | Matches that model variant. |
| `status` | One or more comma-separated statuses. | Matches any supplied status, for example `succeeded,failed`. |
| `created_from` | RFC 3339 timestamp with a timezone. | Includes runs created at or after this time. |
| `created_to` | RFC 3339 timestamp with a timezone. | Includes runs created before this time. |
| `ids` | Up to 100 comma-separated run IDs. | Finds a known set of your runs. |

Different filters are combined with AND. A date window such as `created_from=2026-10-01T00:00:00Z&created_to=2026-10-02T00:00:00Z` selects one UTC day. Encode query values normally, including `+` in timezone offsets.

### Move between pages

Follow the response's `next` or `previous` URL unchanged, with your usual API-key header. `next` moves to older runs and `previous` to newer ones. Missing links mean there is no page in that direction. An empty result is `{"data":[]}`.

Pagination links carry an opaque `cursor`; do not build or decode it, and do not add the original filters to a cursor URL. Cursors expire 24 hours after the first page. On `410 cursor_expired`, restart from your initial filtered request.

New runs do not move the head of a traversal already in progress. Existing runs' status and cost can still change, so history is not an event stream. Refresh the first page when you want the newest runs.

History returns summaries and output descriptors. Read `GET /run/{id}` when you need full inline output values.

## Cancel a run

```bash
curl 'https://fusara.ai/api/v3/run/123456/cancel' \
  --request POST \
  -H "Authorization: Bearer $FUSARA_API_KEY"
```

Send this request with no body. Cancellation succeeds only before the run enters execution admission or dispatch. Even a run currently shown as `queued` can be too late to cancel; in that case the API returns `409 run_not_cancelable`.

A successfully canceled run has status `canceled` and no generation charge. If the run is already terminal, the method returns its current result unchanged. Cancellation is not a way to undo a finished generation or request a refund.

## Recover after an interruption

Keep your run ID independently of your browser tab or worker process. If a webhook is missed, `GET /run/{id}` retrieves the same result. If your application lost an ID, use history and its filters to locate your runs; do not automatically resubmit every unfinished local task.
