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

# Rocketpunch API Rate Limits, Quotas, and Retry Logic

> Learn about Rocketpunch API rate limits and request quotas, how to read rate limit headers, and how to handle 429 responses gracefully.

Rate limits protect the Rocketpunch API from excessive traffic so that all developers get consistent, reliable performance. Every API key is subject to a request quota measured over a rolling time window. When your app exceeds its quota, the API returns a `429 Too Many Requests` response until the window resets. Building retry logic and caching into your integration from the start prevents these limits from affecting your users.

<Note>
  Specific rate limit values for your app tier are displayed in your developer console at [developers.rocketpunch.com](https://developers.rocketpunch.com). If your use case requires a higher quota, contact [support@rocketpunch.com](mailto:support@rocketpunch.com) to discuss an increase.
</Note>

## Rate Limit Headers

Every API response includes headers that tell you the current state of your quota. Read these headers to monitor your usage and avoid hitting limits unexpectedly.

| Header                  | Description                                                                    |
| ----------------------- | ------------------------------------------------------------------------------ |
| `X-RateLimit-Limit`     | Total number of requests allowed in the current window                         |
| `X-RateLimit-Remaining` | Requests remaining before you hit the limit                                    |
| `X-RateLimit-Reset`     | Unix timestamp (UTC) when the current window resets and your quota is restored |

Here is an example of what these headers look like on a successful response:

```http theme={null}
HTTP/1.1 200 OK
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 847
X-RateLimit-Reset: 1718150400
Content-Type: application/json
```

You can calculate seconds until reset with:

```javascript theme={null}
const resetTime = parseInt(response.headers.get("X-RateLimit-Reset"), 10);
const secondsUntilReset = resetTime - Math.floor(Date.now() / 1000);
```

## Handling Rate Limit Errors

When your app exhausts its quota, the API responds with `429 Too Many Requests` and a `Retry-After` header indicating how many seconds to wait before retrying.

```http theme={null}
HTTP/1.1 429 Too Many Requests
Retry-After: 30
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1718150400
Content-Type: application/json

{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Too many requests. Please retry after the reset window.",
    "status": 429
  }
}
```

The most resilient pattern for handling rate limits is **exponential backoff with jitter**: wait a base interval after the first failure, double it on each subsequent failure, and add a small random offset to prevent synchronized retries from multiple instances.

<CodeGroup>
  ```javascript Node.js theme={null}
  async function fetchWithRetry(url, options, maxRetries = 4) {
    let attempt = 0;

    while (attempt <= maxRetries) {
      const response = await fetch(url, options);

      if (response.status !== 429) {
        return response; // Success or a non-rate-limit error
      }

      if (attempt === maxRetries) {
        throw new Error(`Rate limit exceeded after ${maxRetries} retries`);
      }

      // Read Retry-After header, fall back to exponential backoff
      const retryAfter = response.headers.get("Retry-After");
      const baseDelay = retryAfter
        ? parseInt(retryAfter, 10) * 1000
        : Math.pow(2, attempt) * 1000;

      // Add jitter (±20%) to avoid synchronized retries
      const jitter = baseDelay * 0.2 * (Math.random() * 2 - 1);
      const delay = Math.round(baseDelay + jitter);

      console.log(`Rate limited. Retrying in ${delay}ms (attempt ${attempt + 1})`);
      await new Promise((resolve) => setTimeout(resolve, delay));
      attempt++;
    }
  }

  // Usage
  const response = await fetchWithRetry(
    "https://openapi.rocketpunch.com/api/v1/jobs",
    {
      headers: {
        "X-RP-API-Key": process.env.RP_API_KEY,
      },
    }
  );
  const data = await response.json();
  ```

  ```python Python theme={null}
  import time
  import random
  import requests

  def fetch_with_retry(url, headers, max_retries=4):
      attempt = 0

      while attempt <= max_retries:
          response = requests.get(url, headers=headers)

          if response.status_code != 429:
              return response  # Success or a non-rate-limit error

          if attempt == max_retries:
              raise Exception(f"Rate limit exceeded after {max_retries} retries")

          # Read Retry-After header, fall back to exponential backoff
          retry_after = response.headers.get("Retry-After")
          base_delay = float(retry_after) if retry_after else (2 ** attempt)

          # Add jitter (±20%) to avoid synchronized retries
          jitter = base_delay * 0.2 * (random.random() * 2 - 1)
          delay = base_delay + jitter

          print(f"Rate limited. Retrying in {delay:.1f}s (attempt {attempt + 1})")
          time.sleep(delay)
          attempt += 1

  # Usage
  response = fetch_with_retry(
      "https://openapi.rocketpunch.com/api/v1/jobs",
      headers={"X-RP-API-Key": os.environ["RP_API_KEY"]},
  )
  data = response.json()
  ```
</CodeGroup>

## Best Practices

Follow these practices to keep your integration well within rate limits under normal operation.

**Cache responses locally.** Job listings, company profiles, and event data do not change by the second. Store API responses in your application cache and serve them directly to users instead of making a live API call on every request. Refresh the cache on a schedule appropriate for your use case — every few minutes for high-traffic apps, hourly for less time-sensitive data.

**Use pagination instead of bulk fetching.** Avoid requesting large page sizes to retrieve all records at once. Use the `per_page` parameter to fetch a reasonable number of results per page, and only load additional pages when your user actually requests them.

**Deduplicate requests.** If multiple parts of your application might request the same resource simultaneously (for example, during high-traffic bursts), use a request-coalescing pattern so that concurrent calls share a single in-flight HTTP request.

**Monitor your usage.** Check the `X-RateLimit-Remaining` header in your responses and log a warning when it drops below a threshold you define. Your developer console at [developers.rocketpunch.com](https://developers.rocketpunch.com) also shows aggregate usage statistics for your app key.

**Back off proactively.** If `X-RateLimit-Remaining` drops to a low value, slow your request rate voluntarily rather than waiting for a `429` response. This keeps your app responsive and avoids gaps in service for your users.

<Tip>
  For read-heavy applications, consider caching job and company data locally and refreshing it on a scheduled interval — for example, every 10 minutes. This pattern can reduce your API call volume by an order of magnitude compared to making a live request for every user page load.
</Tip>
