# Batch results

> POST /ai_agent/results. Fetch the result of a batch translation by job_id. The three statuses, polling guidance, and the one case where a wrong job_id looks like processing.

Source: https://www.fluentc.ai/docs/api/batch-results/

```http
POST https://api.fluentc.ai/ai_agent/results
```

Returns the current state of a batch job started with [Translate](https://www.fluentc.ai/docs/api/translate.md) in `batch` mode.

## Request

Headers are the same as every endpoint: `Authorization` with your key and `Content-Type: application/json`.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `job_id` | string | Yes | The `job_id` returned by the batch request. |

```bash
curl -X POST https://api.fluentc.ai/ai_agent/results \
  -H "Authorization: $FLUENTC_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "job_id": "abc123def456" }'
```

## Response

The HTTP status is `200` for all three states. Read `status` to tell them apart.

### `complete`

```json
{
  "status": "complete",
  "translation": "<h1>Bienvenue</h1><p>Ceci est un exemple de page.</p>",
  "token_count": 31,
  "source_language_detected": "en"
}
```

| Field | Type | Description |
| --- | --- | --- |
| `translation` | string | The translated content. For `json` input it is a JSON-encoded string; parse it. |
| `token_count` | integer | The size of the translation. |
| `source_language_detected` | string | The source language code. |

### `processing`

```json
{
  "status": "processing",
  "estimated_wait_seconds": 5,
  "next_poll_after": "2026-01-15T10:30:00Z"
}
```

| Field | Type | Description |
| --- | --- | --- |
| `estimated_wait_seconds` | integer | How long to wait before asking again. |
| `next_poll_after` | string | The same moment as an ISO 8601 timestamp. |

### `failed`

```json
{
  "status": "failed",
  "error": "Translation failed for the given job_id; content was recognized but the translation is unavailable."
}
```

The job was recognised but no translation could be produced. Resubmit the request. Because job IDs are deterministic, resubmitting returns the same `job_id`.

## Polling

1. Submit the batch request and keep the `job_id`.
2. Call this endpoint. If `status` is `processing`, wait `max(estimated_wait_seconds, 5)` seconds and call again.
3. Stop on `complete` or `failed`.
4. **Cap the number of attempts** (60 is a sensible limit).

> **Warning:** A `job_id` that doesn't exist, or one you mistyped, is reported as `processing`, not as an error. Without a cap, a wrong ID polls forever.

JavaScript:

```js
async function waitForTranslation(jobId, { maxAttempts = 60 } = {}) {
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
    const res = await fetch("https://api.fluentc.ai/ai_agent/results", {
      method: "POST",
      headers: {
        Authorization: process.env.FLUENTC_KEY,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ job_id: jobId }),
    });
    const body = await res.json();
    if (!res.ok) throw new Error(`${res.status}: ${body.error}`);

    if (body.status === "complete") return body.translation;
    if (body.status === "failed") throw new Error(body.error);

    const waitSeconds = Math.max(body.estimated_wait_seconds ?? 5, 5);
    await new Promise((resolve) => setTimeout(resolve, waitSeconds * 1000));
  }
  throw new Error(`Job ${jobId} did not finish after ${maxAttempts} attempts`);
}
```

## Errors

| Status | Message | Cause |
| --- | --- | --- |
| `422` | `job_id (hash_key) is missing` | The body has no `job_id`. |
| `401`, `403` | See [Authentication](https://www.fluentc.ai/docs/authentication.md) | Key or account problem. |

All error shapes are on [Errors](https://www.fluentc.ai/docs/api/errors.md).
