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

# Rate Limit Headers

> Rate-limited API responses include X-RateLimit-* headers so you can track your usage and remaining quota in real time without making a separate API call.

Swarms API responses include rate limit headers whenever the rate limiter runs on the request. These headers let you monitor your usage programmatically — build retry logic, display quota dashboards, or throttle requests before hitting limits.

<Info>
  Rate limit headers are present on every response where the rate limiter ran — including 429 rate-limit rejections and `/v1/rate/limits` itself. Errors returned before rate limiting runs (such as 402 insufficient-credit or 403 premium-required rejections from the authentication layer) do not carry these headers.
</Info>

***

## Headers

Rate-limited responses include these headers:

| Header                         | Type           | Description                                                             |
| ------------------------------ | -------------- | ----------------------------------------------------------------------- |
| `X-RateLimit-Limit-Minute`     | integer        | Maximum requests allowed per minute for your tier                       |
| `X-RateLimit-Remaining-Minute` | integer        | Requests remaining in the current minute window                         |
| `X-RateLimit-Limit-Day`        | integer        | Maximum requests allowed per day for your tier                          |
| `X-RateLimit-Remaining-Day`    | integer        | Requests remaining in the current day window                            |
| `X-RateLimit-Reset`            | unix timestamp | When the current minute window resets (seconds since epoch)             |
| `X-RateLimit-Tier`             | string         | Your current tier: `free` or `premium`                                  |
| `Retry-After`                  | integer        | Seconds until the rate limit resets. **Only present on 429 responses.** |

***

## Example Response Headers

```http theme={null}
HTTP/1.1 200 OK
Content-Type: application/json
X-RateLimit-Limit-Minute: 100
X-RateLimit-Remaining-Minute: 94
X-RateLimit-Limit-Day: 1200
X-RateLimit-Remaining-Day: 1047
X-RateLimit-Reset: 1713700800
X-RateLimit-Tier: free
```

***

## Example 429 Response

When you exceed a rate limit, the response includes a `Retry-After` header:

```http theme={null}
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
X-RateLimit-Limit-Minute: 100
X-RateLimit-Remaining-Minute: 0
X-RateLimit-Limit-Day: 1200
X-RateLimit-Remaining-Day: 1100
X-RateLimit-Reset: 1713700860
X-RateLimit-Tier: free
Retry-After: 42
```

```json theme={null}
{
  "detail": "Rate limit exceeded for minute window(s). Upgrade to Premium for increased limits (2,000/min, 10,000/hour, 100,000/day) at https://swarms.world/platform/account for just $99/month."
}
```

***

## Limits by Tier

|                      | Free    | Premium   |
| -------------------- | ------- | --------- |
| **Per minute**       | 100     | 2,000     |
| **Per hour**         | 350     | 10,000    |
| **Per day**          | 1,200   | 100,000   |
| **Tokens per agent** | 200,000 | 2,000,000 |

***

## Code Examples

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    import os
    import requests
    from dotenv import load_dotenv

    load_dotenv()

    API_KEY = os.getenv("SWARMS_API_KEY")
    BASE_URL = "https://api.swarms.world"

    headers = {
        "x-api-key": API_KEY,
        "Content-Type": "application/json",
    }

    response = requests.post(
        f"{BASE_URL}/v1/agent/completions",
        headers=headers,
        json={
            "agent_config": {
                "agent_name": "test",
                "model_name": "gpt-4o-mini",
                "system_prompt": "You are helpful.",
                "max_loops": 1,
            },
            "task": "Say hello.",
        },
    )

    # Read rate limit headers
    remaining = int(response.headers["X-RateLimit-Remaining-Minute"])
    limit = int(response.headers["X-RateLimit-Limit-Minute"])
    tier = response.headers["X-RateLimit-Tier"]

    print(f"Tier: {tier} | {remaining}/{limit} requests remaining this minute")
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    import "dotenv/config";

    const API_KEY = process.env.SWARMS_API_KEY;
    const BASE_URL = "https://api.swarms.world";

    if (!API_KEY) {
      throw new Error("SWARMS_API_KEY is not set");
    }

    const response = await fetch(`${BASE_URL}/v1/agent/completions`, {
      method: "POST",
      headers: {
        "x-api-key": API_KEY,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        agent_config: {
          agent_name: "test",
          model_name: "gpt-4o-mini",
          system_prompt: "You are helpful.",
          max_loops: 1,
        },
        task: "Say hello.",
      }),
    });

    // Read rate limit headers
    const remaining = parseInt(response.headers.get("X-RateLimit-Remaining-Minute") ?? "0");
    const limit = parseInt(response.headers.get("X-RateLimit-Limit-Minute") ?? "0");
    const tier = response.headers.get("X-RateLimit-Tier");

    console.log(`Tier: ${tier} | ${remaining}/${limit} requests remaining this minute`);
    ```
  </Tab>

  <Tab title="Rust">
    ```rust theme={null}
    use std::env;
    use reqwest::blocking::Client;

    fn main() -> Result<(), Box<dyn std::error::Error>> {
        let api_key = env::var("SWARMS_API_KEY")
            .expect("SWARMS_API_KEY environment variable is required");

        let client = Client::new();

        let response = client
            .post("https://api.swarms.world/v1/agent/completions")
            .header("x-api-key", &api_key)
            .header("Content-Type", "application/json")
            .body(r#"{
                "agent_config": {
                    "agent_name": "test",
                    "model_name": "gpt-4o-mini",
                    "system_prompt": "You are helpful.",
                    "max_loops": 1
                },
                "task": "Say hello."
            }"#)
            .send()?;

        // Read rate limit headers
        let remaining = response.headers()
            .get("X-RateLimit-Remaining-Minute")
            .and_then(|v| v.to_str().ok())
            .unwrap_or("0");
        let limit = response.headers()
            .get("X-RateLimit-Limit-Minute")
            .and_then(|v| v.to_str().ok())
            .unwrap_or("0");
        let tier = response.headers()
            .get("X-RateLimit-Tier")
            .and_then(|v| v.to_str().ok())
            .unwrap_or("unknown");

        println!("Tier: {} | {}/{} requests remaining this minute", tier, remaining, limit);

        Ok(())
    }
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={null}
    package main

    import (
        "fmt"
        "log"
        "net/http"
        "os"
        "strings"
    )

    func main() {
        apiKey := os.Getenv("SWARMS_API_KEY")
        if apiKey == "" {
            log.Fatal("SWARMS_API_KEY environment variable is required")
        }

        body := strings.NewReader(`{
            "agent_config": {
                "agent_name": "test",
                "model_name": "gpt-4o-mini",
                "system_prompt": "You are helpful.",
                "max_loops": 1
            },
            "task": "Say hello."
        }`)

        req, err := http.NewRequest("POST", "https://api.swarms.world/v1/agent/completions", body)
        if err != nil {
            log.Fatal(err)
        }

        req.Header.Set("x-api-key", apiKey)
        req.Header.Set("Content-Type", "application/json")

        resp, err := http.DefaultClient.Do(req)
        if err != nil {
            log.Fatal(err)
        }
        defer resp.Body.Close()

        // Read rate limit headers
        remaining := resp.Header.Get("X-RateLimit-Remaining-Minute")
        limit := resp.Header.Get("X-RateLimit-Limit-Minute")
        tier := resp.Header.Get("X-RateLimit-Tier")

        fmt.Printf("Tier: %s | %s/%s requests remaining this minute\n", tier, remaining, limit)
    }
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    # The -i flag prints response headers
    curl -i -X POST https://api.swarms.world/v1/agent/completions \
      -H "x-api-key: $SWARMS_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "agent_config": {
          "agent_name": "test",
          "model_name": "gpt-4o-mini",
          "system_prompt": "You are helpful.",
          "max_loops": 1
        },
        "task": "Say hello."
      }'
    ```
  </Tab>
</Tabs>

***

## Retry Logic

Use the `Retry-After` header to implement automatic retry on 429 responses:

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    import time
    import requests

    def call_with_retry(url, headers, payload, max_retries=3):
        for attempt in range(max_retries):
            response = requests.post(url, headers=headers, json=payload)

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

            return response

        raise Exception("Max retries exceeded")
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    async function callWithRetry(
      url: string,
      headers: Record<string, string>,
      payload: object,
      maxRetries = 3
    ): Promise<Response> {
      for (let attempt = 0; attempt < maxRetries; attempt++) {
        const response = await fetch(url, {
          method: "POST",
          headers,
          body: JSON.stringify(payload),
        });

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

        return response;
      }

      throw new Error("Max retries exceeded");
    }
    ```
  </Tab>

  <Tab title="Rust">
    ```rust theme={null}
    use reqwest::blocking::{Client, Response};
    use std::thread;
    use std::time::Duration;

    fn call_with_retry(
        client: &Client,
        url: &str,
        api_key: &str,
        body: &str,
        max_retries: u32,
    ) -> Result<Response, Box<dyn std::error::Error>> {
        for _ in 0..max_retries {
            let response = client
                .post(url)
                .header("x-api-key", api_key)
                .header("Content-Type", "application/json")
                .body(body.to_string())
                .send()?;

            if response.status().as_u16() == 429 {
                let retry_after: u64 = response.headers()
                    .get("Retry-After")
                    .and_then(|v| v.to_str().ok())
                    .and_then(|v| v.parse().ok())
                    .unwrap_or(60);
                println!("Rate limited. Retrying in {}s...", retry_after);
                thread::sleep(Duration::from_secs(retry_after));
                continue;
            }

            return Ok(response);
        }

        Err("Max retries exceeded".into())
    }
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={null}
    package main

    import (
        "fmt"
        "net/http"
        "strconv"
        "strings"
        "time"
    )

    func callWithRetry(url, apiKey, body string, maxRetries int) (*http.Response, error) {
        for attempt := 0; attempt < maxRetries; attempt++ {
            req, err := http.NewRequest("POST", url, strings.NewReader(body))
            if err != nil {
                return nil, err
            }
            req.Header.Set("x-api-key", apiKey)
            req.Header.Set("Content-Type", "application/json")

            resp, err := http.DefaultClient.Do(req)
            if err != nil {
                return nil, err
            }

            if resp.StatusCode == 429 {
                retryAfter, _ := strconv.Atoi(resp.Header.Get("Retry-After"))
                if retryAfter == 0 {
                    retryAfter = 60
                }
                fmt.Printf("Rate limited. Retrying in %ds...\n", retryAfter)
                resp.Body.Close()
                time.Sleep(time.Duration(retryAfter) * time.Second)
                continue
            }

            return resp, nil
        }

        return nil, fmt.Errorf("max retries exceeded")
    }
    ```
  </Tab>
</Tabs>

***

## Best Practices

1. **Check `Remaining-Minute` before sending requests** — if it's low, slow down or queue requests.
2. **Use `Retry-After` on 429s** — don't guess the wait time, the header tells you exactly how long.
3. **Log your tier** — use `X-RateLimit-Tier` to confirm your account is on the expected plan.
4. **Build dashboards** — track `Remaining-Day` over time to understand your usage patterns and plan upgrades.

***

## Related

* [Rate Limits](/docs/documentation/resources/ratelimits) — full rate limit tiers, windows, and how limiting works
* [Pricing Details](/docs/documentation/resources/pricing) — per-operation costs
* [Premium Endpoints](/docs/documentation/resources/premium-endpoints) — endpoints available on premium plans
* [Rate Limits API Example](/docs/examples/api_examples/rate_limits) — check rate limit status via the API
