Skip to content
API v1 preview — endpoints and fields may change before general availability.

Rate limits

How many requests can I send, and what do I do on a 429?

View .md

Each account can send a fixed number of requests per time window. Responses tell you where you stand, so you can slow down before you hit the limit. If you do hit it, you get 429 rate_limited and a Retry-After header that says how long to wait.

GET /v1/account returns your limit as rate_limit. It is free.

{
"plan": "growth",
"credits_remaining": 9841,
"credits_reset_at": "2026-11-01T00:00:00Z",
"providers_enabled": ["betterjobs", "theirstack", "techmap"],
"rate_limit": { "limit": 60, "window_seconds": 60 }
}

Illustrative. limit is requests per window and window_seconds is the window length. Read your own values from the endpoint rather than hard-coding them.

Header On What it tells you
RateLimit-Limit Responses Requests allowed in the current window.
RateLimit-Remaining Responses Requests left in the current window.
RateLimit-Reset Responses Seconds until the window resets.
Retry-After 429 only Seconds to wait before you retry.

The names follow the IETF draft RateLimit header fields, without an X- prefix. RateLimit-Reset is a number of seconds from now, not a Unix timestamp.

A 429 body uses the standard error shape:

{
"error": {
"type": "rate_limit_error",
"code": "rate_limited",
"message": "Rate limit exceeded. Retry after 12 seconds.",
"doc_url": "https://docs.betterjobs.cc/platform/errors/#rate_limited",
"request_id": "req_0Ig1JqH5sT"
}
}

A 429 returns no jobs, so it charges nothing.

Wrap every call in one helper:

  • On 429, wait exactly Retry-After seconds.
  • On 5xx or a network error, wait with exponential backoff plus jitter, capped at 30 seconds.
  • Stop after a few attempts and raise.
  • For POST, pass the same Idempotency-Key on every attempt, so a retry can never double up. See Idempotency.
Terminal window
# curl waits for Retry-After on 429 and backs off on 5xx.
curl https://api.betterjobs.cc/v1/jobs/search \
--retry 5 --retry-max-time 120 \
-H "Authorization: Bearer $BETTERJOBS_API_KEY" \
-H "BetterJobs-Version: 2026-10-01" \
-H "Idempotency-Key: 7b8f2c4e-1a3d-4f5b-9c6e-0d2a4b6c8e1f" \
-H "Content-Type: application/json" \
-d '{ "filters": { "title_or": ["Head of RevOps"], "country_code_or": ["DE", "AT", "CH"] } }'

Backoff handles the occasional 429. For steady workloads, avoid them:

  • Pace on RateLimit-Remaining. When it reaches 0, wait RateLimit-Reset seconds before the next call.
  • Ask for bigger pages. limit: 100 on POST /v1/jobs/search needs a quarter of the requests that the default 25 does.
  • Use async searches for bulk work. One POST /v1/searches collects up to 10,000 jobs. See Async searches.
  • Prefer webhooks to polling. A watch or webhook_url pushes events to you. Polling GET /v1/searches/{id} or GET /v1/events in a tight loop spends requests on “nothing yet”.
  • Share one limiter. Parallel workers on one account share one budget. Put one rate limiter in front of all of them.