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

# Rate Limits

> API rate limiting policies and response headers

sunor enforces rate limits to ensure fair usage and platform stability. Limits are applied per API key across all endpoints.

## Limits

| Scope       | Limit                 |
| ----------- | --------------------- |
| Per API key | 120 requests / minute |

All API endpoints share the same rate limit window. The limit resets every 60 seconds.

## When you hit the limit

If you exceed the rate limit, the API returns a `429 Too Many Requests` response with a `Retry-After` header indicating how many seconds to wait.

```json theme={null}
{
  "code": 429,
  "message": "Rate limit exceeded. Try again in 30 seconds."
}
```

### Response headers

| Header                  | Sent on        | Description                               |
| ----------------------- | -------------- | ----------------------------------------- |
| `X-RateLimit-Remaining` | Every response | Requests remaining in the current window  |
| `Retry-After`           | 429 only       | Number of seconds to wait before retrying |

## Best practices

<CardGroup cols={2}>
  <Card title="Respect Retry-After" icon="clock">
    When you receive a 429 response, wait for the duration specified in the `Retry-After` header before making another request.
  </Card>

  <Card title="Use exponential backoff" icon="arrow-trend-up">
    For automated systems, implement exponential backoff when receiving rate limit errors to avoid hammering the API.
  </Card>

  <Card title="Batch wisely" icon="layer-group">
    Instead of submitting many tasks simultaneously, spread submissions over time to stay within limits.
  </Card>

  <Card title="Monitor remaining quota" icon="gauge">
    Check `X-RateLimit-Remaining` in response headers to proactively slow down before hitting the limit.
  </Card>
</CardGroup>

## Example: rate-limit-aware polling

<CodeGroup>
  ```python Python theme={null}
  import time
  import requests

  def poll_with_rate_limit(api_key, task_id, interval=5):
      while True:
          response = requests.get(
              f"https://sunor.cc/api/v1/task/{task_id}",
              headers={"x-api-key": api_key},
          )

          # Check rate limit headers
          remaining = int(response.headers.get("X-RateLimit-Remaining", 1))
          if remaining < 5:
              print("Approaching rate limit, slowing down...")
              interval = max(interval, 10)

          if response.status_code == 429:
              retry_after = int(response.headers.get("Retry-After", 30))
              print(f"Rate limited. Waiting {retry_after}s...")
              time.sleep(retry_after)
              continue

          data = response.json()["data"]
          if data["status"] in ("success", "failure", "timeout"):
              return data

          time.sleep(interval)
  ```

  ```javascript Node.js theme={null}
  async function pollWithRateLimit(apiKey, taskId, interval = 5000) {
    while (true) {
      const response = await fetch(
        `https://sunor.cc/api/v1/task/${taskId}`,
        { headers: { "x-api-key": apiKey } }
      );

      // Check rate limit headers
      const remaining = parseInt(response.headers.get("X-RateLimit-Remaining") || "1");
      if (remaining < 5) {
        console.log("Approaching rate limit, slowing down...");
        interval = Math.max(interval, 10000);
      }

      if (response.status === 429) {
        const retryAfter = parseInt(response.headers.get("Retry-After") || "30");
        console.log(`Rate limited. Waiting ${retryAfter}s...`);
        await new Promise((r) => setTimeout(r, retryAfter * 1000));
        continue;
      }

      const { data } = await response.json();
      if (["success", "failure", "timeout"].includes(data.status)) {
        return data;
      }

      await new Promise((r) => setTimeout(r, interval));
    }
  }
  ```
</CodeGroup>
