Handle Rate Limits

What to do when you hit rate limits, how to read the rate limit headers, and how to avoid hitting them.

The Jobven API enforces two kinds of limits. Both return a 429 status when exceeded, but you handle them differently:

  • Burst limit — a per-second cap on how fast you can send requests. Retry after a short pause.
  • Monthly quota — the total calls included in your plan each billing period. Retrying won't help until the period resets.

The exact numbers for each plan are listed under Authentication → Rate Limiting.

Response Headers

Every response includes headers describing your monthly quota:

X-RateLimit-Limit: 30000
X-RateLimit-Remaining: 28750
X-RateLimit-Reset: 1735257660
HeaderDescription
X-RateLimit-LimitCalls included this billing period. This is the limit actually enforced on your account, which is your plan's allowance unless a different one was agreed with us.
X-RateLimit-RemainingCalls left this billing period
X-RateLimit-ResetUnix timestamp (seconds) when your quota resets
X-Request-Time-MsHow long the request took to process
There is no Retry-After header. When you hit the burst limit, the 429 response body includes a retryAfter value (in seconds) instead.

Read the header, not your plan's advertised allowance

X-RateLimit-Limit is the ceiling actually enforced on your account. If we agreed a different limit with you, your plan's published number is not the one you are held to, and the header is where that difference shows up. Every API response carries it, so there is no separate call to make.

If you track usage programmatically, X-RateLimit-Limit and X-RateLimit-Remaining are the only two numbers you need. Credits are no longer part of how a request is accepted or rejected.

Telling the Two Limits Apart

Both limits return 429, so check the error field in the response body to decide how to react.

Burst limit (slow down and retry):

{
  "statusCode": 429,
  "message": "Rate limit exceeded",
  "error": "Too Many Requests",
  "retryAfter": 1
}

Monthly quota (stop and upgrade or wait for reset):

{
  "statusCode": 429,
  "message": "Monthly API call limit exceeded",
  "error": "Quota Exceeded",
  "resetAt": 1735257660
}

Handling 429 Responses

Retry on the burst limit, but stop on a quota error — retrying won't return data until your billing period resets.

JavaScript

async function fetchWithRetry(url, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    const response = await fetch(url, {
      headers: { 'X-API-Key': process.env.JOBVEN_API_KEY }
    });

    if (response.status === 429) {
      const body = await response.json();

      // Monthly quota - retrying won't help until reset
      if (body.error === 'Quota Exceeded') {
        throw new Error('Monthly quota exhausted. Upgrade your plan or wait for reset.');
      }

      // Burst limit - wait and retry
      const wait = body.retryAfter ?? 1;
      console.log(`Rate limited. Waiting ${wait}s...`);
      await new Promise(r => setTimeout(r, wait * 1000));
      continue;
    }

    if (!response.ok) {
      throw new Error(`API error: ${response.status}`);
    }

    return response;
  }

  throw new Error('Max retries exceeded');
}

Python

import os
import time
import requests

def fetch_with_retry(url, params=None, max_retries=3):
    headers = {'X-API-Key': os.environ['JOBVEN_API_KEY']}

    for attempt in range(max_retries):
        response = requests.get(url, headers=headers, params=params)

        if response.status_code == 429:
            body = response.json()

            # Monthly quota - retrying won't help until reset
            if body.get('error') == 'Quota Exceeded':
                raise Exception('Monthly quota exhausted. Upgrade your plan or wait for reset.')

            # Burst limit - wait and retry
            wait = body.get('retryAfter', 1)
            print(f"Rate limited. Waiting {wait}s...")
            time.sleep(wait)
            continue

        response.raise_for_status()
        return response

    raise Exception('Max retries exceeded')

Avoiding Rate Limits

  • Use the maximum limit - The default is 10 jobs per request, but your plan allows more: 25 on Free, 50 on Starter, 100 on Growth and above. One request counts as one call regardless of how many jobs come back, so requesting the maximum stretches your monthly quota and reduces the number of round trips.
  • Use incremental sync - Fetch only new jobs with postedAfter instead of everything. See Incremental Sync.
  • Cache responses - Don't fetch the same data repeatedly. Cache results for as long as makes sense for your use case.
  • Watch your remaining quota - Monitor X-RateLimit-Remaining and slow down before it reaches zero.

Next Steps

Fetch All Jobs

Paginate through large result sets.

Incremental Sync

Reduce API calls by fetching only new jobs.