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

# Request IDs, timeouts, and retries

> Use request IDs to locate issues, and set safe retries for timeouts, rate limits, and upstream fluctuations.

Production environments should set connection timeout, total timeout, retry limit, and request tracking ID simultaneously.

## Request IDs

Record the request identifiers from APIONE responses. Different interfaces or routes may return `X-Request-ID`, `X-Maxx-Trace-Id`, or `X-Maxx-Request-ID`; retain the actual field names and values received. When reporting issues, provide request time and timezone, model ID, complete endpoint, status code, error code, and request identifier.

Do not submit complete API Keys, sensitive prompts, or unsanitized files.

![APIONE request details and call status](https://mintcdn.com/apione/pAFvFGkbmcRZirTZ/images/ui/request-logs.png?fit=max\&auto=format\&n=pAFvFGkbmcRZirTZ\&q=85\&s=093db383e228008dc3c42cb6a7849d28)

Console request details can be filtered by time, source, API Key, and request ID, and checked for status, latency, tokens, and cost.

## When to retry

| Situation | Recommendation |
| - | - |
| 400, 401, 403, 404 | Fix the request, authentication, permission, or path; do not auto-retry |
| 402 | Top up balance or adjust limits; do not auto-retry |
| 429 | Read `Retry-After`, wait, then retry a limited number of times |
| 5xx, network interruption | Use exponential backoff with random jitter, and set a maximum attempt count |

> [!WARNING]
>
> When creating potentially billable tasks such as images or videos, do not retry infinitely while the result is unknown. First query status using the request ID or task ID to avoid duplicate creation.

## Timeout recommendations

* Set separate connection timeout and read timeout for text requests.
* For streaming requests, use the first event and continuous read as boundaries; do not apply a short ordinary-request timeout.
* Video generation is an asynchronous task. After successful creation, poll the task status; do not let one HTTP connection wait until generation finishes.

## Smart routing boundaries

APIONE selects or switches among available routes for the same model. If the model, permission, balance, or request parameters themselves are incorrect, switching routes cannot solve the problem. If all routes are unavailable, the request may still fail.

## Recommended backoff strategy

Wait a short time after the first failure, then increase wait time exponentially, and add random jitter to avoid multiple requests retrying simultaneously. Total attempts should be limited, and the business side should also set a total time budget.

```text theme={null}
delay = min(baseDelay x 2^attempt + randomJitter, maxDelay)
```

The following Node.js example is suitable for replayable requests that have been confirmed as retry-safe. `maxAttempts` includes the first request; the last HTTP failure retains the original response for reading status code and error body. `Retry-After` supports both seconds and HTTP dates; use backoff delay when missing or invalid.

The caller should check the final response's `ok` status and set timeouts according to business needs. The request body should use replayable string or byte data; if the SDK already retries automatically, coordinate the total attempt count.

Combine the two JavaScript blocks below in order, save as `example.mjs`. First set `APIONE_API_KEY` as described in the [quickstart](https://apione.ai/docs/en/quickstart.md), then run `node example.mjs` in the same terminal. Use Node.js 18 or higher; built-in `fetch` requires no extra dependencies.

```javascript theme={null}
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

function retryDelay(response, attempt) {
  const value = response?.headers.get("retry-after")?.trim();
  if (value) {
    const seconds = Number(value);
    if (Number.isFinite(seconds) && seconds >= 0) return seconds * 1000;
    const retryAt = Date.parse(value);
    if (Number.isFinite(retryAt)) return Math.max(0, retryAt - Date.now());
  }
  return Math.min(1000 * 2 ** attempt + Math.random() * 300, 8000);
}

async function requestWithRetry(url, options = {}, maxAttempts = 3) {
  if (!Number.isInteger(maxAttempts) || maxAttempts < 1) {
    throw new RangeError("maxAttempts must be a positive integer");
  }

  for (let attempt = 0; attempt < maxAttempts; attempt++) {
    let response;
    try {
      response = await fetch(url, options);
    } catch (error) {
      if (options.signal?.aborted || attempt === maxAttempts - 1) throw error;
      await sleep(retryDelay(null, attempt));
      continue;
    }

    const retryable = response.status === 429 || response.status >= 500;
    if (!retryable || attempt === maxAttempts - 1) return response;

    const delay = retryDelay(response, attempt);
    await response.body?.cancel();
    await sleep(delay);
  }
}
```

### Reading request identifiers

```javascript theme={null}
const apiKey = process.env.APIONE_API_KEY;
if (!apiKey) throw new Error("Set APIONE_API_KEY first");
const response = await requestWithRetry("https://api.apione.ai/v1/models", {
  headers: { Authorization: `Bearer ${apiKey}` },
  signal: AbortSignal.timeout(30_000),
});
const requestIds = Object.fromEntries(
  ["X-Request-ID", "X-Maxx-Trace-Id", "X-Maxx-Request-ID"]
    .map(name => [name, response.headers.get(name)])
    .filter(([, value]) => value)
);
console.log(response.status, requestIds);
if (!response.ok) {
  throw new Error(`HTTP ${response.status}: ${await response.text()}`);
}
```

## Prevent duplicate creation

Text queries can usually be safely retried, but image, video, or other creation requests may have already been received by the server. A connection interruption does not mean the task was not created. Applications should save the following information:

| Information | Purpose |
| - | - |
| Local business request ID | Associate a user action with a single call |
| Actual returned request identifier and field name | Query gateway records from APIONE |
| Video task ID | Query asynchronous task status |
| Creation time and model | Determine whether it is the same operation |
| Request parameter summary | Deduplicate; do not save sensitive original text |

When status is unknown, query records or tasks first; do not immediately recreate.

## Timeout layers

| Timeout | Controls | Recommendation |
| - | - | - |
| Connection timeout | Establishing connection to the gateway | Set short; after failure check DNS, proxy, and network |
| First-byte timeout | Waiting for the model to begin returning | Reasoning models may be significantly longer than ordinary chat |
| Read timeout | Waiting between adjacent data chunks | Streaming requests should allow continuous reading |
| Total timeout | Entire synchronous request time | Cancel proactively after expiry and record the request ID |
| Task deadline | Total wait for asynchronous media tasks | Stop high-frequency polling after timeout and retain the task ID |

## Production checklist

* Use different API Keys for testing and production to facilitate limits, revocation, and auditing.
* Record status code, latency, model, and request ID; do not record the full key.
* Limit maximum concurrency and total retries to avoid amplifying traffic during failures.
* Handle halfway errors, client cancellation, and incomplete JSON for streaming output.
* Distinguish "creation successful", "generation successful", and "result downloaded" for media tasks.
* Monitor success rate, time to first byte, total latency, and 429 and 5xx ratios.

Next: [Error codes and troubleshooting](https://apione.ai/docs/en/support/errors.md), [Video tasks](https://apione.ai/docs/en/api/videos.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.