# Rate limits and retries

An integration needs both a request-rate limit and a concurrency bound. Sending fewer requests per minute does not prevent long generations from filling all concurrent slots.

## Read the current status

~~~bash
curl --fail-with-body https://api.simplellm.eu/v1/rate-limit \
  -H "Authorization: Bearer $SIMPLELLM_API_KEY"
~~~

The V1 status includes general requests-per-minute counters and free-model hourly/daily request and token counters. It is not a complete summary of every key, model, and upstream limit.

| Fields | Meaning |
| --- | --- |
| `limit_rpm`, `used_rpm`, `remaining_rpm` | General minute request bucket |
| `limit_rph`, `used_rph`, `remaining_rph` | Free-model hourly requests |
| `limit_rpd`, `used_rpd`, `remaining_rpd` | Free-model daily requests |
| `limit_tph`, `used_tph`, `remaining_tph` | Free-model hourly tokens |
| `limit_tpd`, `used_tpd`, `remaining_tpd` | Free-model daily tokens |
| `reset_seconds` | Seconds until the minute bucket resets, not all buckets |

Read key-specific configuration with [current key metadata](/docs/reference/getCurrentKey.html). Do not copy a fixed Free/Standard/Premium rate table into your integration; active limits depend on configuration.

## Response headers

V1 can return `X-RateLimit-Limit` and `X-RateLimit-Remaining` for the general request limit. Rate-limit or capacity responses can include `Retry-After`.

~~~http
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 30
~~~

Not every response or upstream failure contains every header. Parse available headers defensively.

## Decide whether to retry

| Situation | Suggested behavior |
| --- | --- |
| 400 or 404 | Fix request parameters, model selection, or URL |
| 401 or 403 | Fix credentials or permissions |
| 402 | Resolve insufficient credits |
| 429 before output | Respect Retry-After and reduce load |
| 502 / 503 / 504 before output | Consider a bounded retry; first failure may still have incurred work |
| Stream failed after output | Mark incomplete; no silent replay |
| User cancelled | Stop; do not retry automatically |

A missing response does not prove that no upstream work occurred. There is no documented universal idempotency guarantee for chat requests.

## Backoff with a budget

For a retryable failure before output, wait at least the server's Retry-After value when present. Without it, increase the delay between attempts and add random jitter so concurrent clients do not retry together.

Set a small maximum number of attempts and a total elapsed-time budget. Stop when either is reached; do not retry forever. If your SDK has built-in retries, avoid adding a second uncoordinated retry loop around it.

## Bound concurrency

Use an application queue or semaphore around inference requests. Release the slot in a cleanup block after success, error, or cancellation; a streaming request occupies its slot until the stream is closed.

Separate time to first output from ongoing stream progress. A reasoning model can take time before visible text appears; choose application deadlines based on the task and expose waiting/cancelled states to your users.

## Free models

Free-model request and token budgets are separate from paid-model pricing. Check the current counters instead of treating a zero token price as unlimited throughput.

The status route itself is an authenticated API request. Poll at a reasonable interval, not for every generated token.
