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

# Rate limits

> SOAX API rate limits: 5 requests/second per API key and 500 requests/minute per IP, how the 429 response looks, how to check remaining quota, and other usage constraints.

The SOAX API enforces two independent rate limits, and a request must pass **both**:

| Limit                     | Applies to             | Window                |
| ------------------------- | ---------------------- | --------------------- |
| **5 requests / second**   | each API key           | fixed 1-second window |
| **500 requests / minute** | each client IP address | fixed 1-minute window |

Two keys used from the same machine share the IP budget; the same key used from two machines shares the key budget. Limits are fixed-window: the counter resets at each window boundary rather than sliding continuously.

## The 429 response

Exceeding either limit returns `429 Too Many Requests`:

```json theme={null}
{ "error": "Rate limit exceeded: 5 per 1 second" }
```

The response carries standard rate-limit headers telling you exactly when to retry:

| Header                | Meaning                                            |
| --------------------- | -------------------------------------------------- |
| `Retry-After`         | Seconds to wait before retrying (at least 1)       |
| `RateLimit-Limit`     | The bucket size (e.g. `5`)                         |
| `RateLimit-Remaining` | Requests left in the current window (`0` on a 429) |
| `RateLimit-Reset`     | Unix timestamp when the window resets              |

Honor `Retry-After` rather than guessing:

```python theme={null}
import time, requests

def get_with_retry(url, headers, max_attempts=5):
    for _ in range(max_attempts):
        resp = requests.get(url, headers=headers)
        if resp.status_code != 429:
            return resp
        time.sleep(int(resp.headers.get("Retry-After", 1)))
    raise RuntimeError("still rate limited after retries")
```

For sustained workloads, spacing requests (a client-side throttle at \~4 requests/second per key) is more effective than reacting to 429s.

## Checking your quota

Every authenticated response — not just 429s — includes the `RateLimit-Limit`, `RateLimit-Remaining`, `RateLimit-Reset`, and `Retry-After` headers for your key's bucket, so you can track quota passively from responses you're already making.

If you want it in a body instead, [`GET /v1/api-keys/me`](/api/keys/me) returns the same information (note that this call itself counts against the limit):

```json theme={null}
{
  "rate_limit": {
    "configured_limit": "5/second",
    "remaining_quota": 3
  }
}
```

## Other usage constraints

Beyond request rates, individual endpoints enforce these caps:

| Constraint                     | Value                                  | Where                                                     |
| ------------------------------ | -------------------------------------- | --------------------------------------------------------- |
| Packages per page              | `limit` 1–100 (default 20)             | [List packages](/api/packages/list)                       |
| Connection strings per request | `count` 1–1000                         | [Get connection strings](/api/packages/connection-string) |
| Analytics date range           | at most 365 days                       | all [analytics endpoints](/api/analytics/summary)         |
| `interval=hour`                | range under 24 hours                   | [Traffic breakdown](/api/analytics/traffic)               |
| `interval=day`                 | range between 24 hours and 180 days    | [Traffic breakdown](/api/analytics/traffic)               |
| `interval=month`               | range of at least 60 days              | [Traffic breakdown](/api/analytics/traffic)               |
| `session` ID format            | lowercase letters/digits, max 16 chars | [Get connection strings](/api/packages/connection-string) |

## Tips for staying under the limits

* **Cache reference data.** Tiers, countries, and package location lists change rarely — fetch them once and refresh occasionally, don't call them per request.
* **Batch connection strings.** One call with `count=100` gives you 100 session-distinct connection strings; you don't need 100 calls.
* **Use one key per service, not per request.** Each key gets its own 5 req/s budget, but creating keys in a hot path is an anti-pattern — create them ahead of time.

<Note>
  These limits apply to the management API only. Proxy traffic through `proxy.soax.com:1337` is governed by your package's own limits (concurrent connections, traffic volume), not by these API rate limits.
</Note>
