Skip to content
OmniLeadDocs
Sign in

Rate limits

How many requests each API key can make, the headers that tell you where you stand, and how to back off when you get a 429.

Available on Agency2 min readLast updated

Each API key can make 120 requests per minute. The limit keeps the API fast for everyone and stops a runaway script from burning through your credits. Every response tells you how much of the limit you have left, so a well-behaved client never needs to hit it.

How the limit works

  • The limit is per key, counted in one-minute windows.
  • Every request counts, whatever its result, including errors.
  • Two keys in the same workspace each get their own 120 requests a minute.
  • Webhook deliveries from OmniLead to you don't count.

The limit is separate from credits. A search page costs 1 credit and 1 request; a lead update costs 0 credits and 1 request.

Rate limit headers

Every response includes three headers:

HeaderMeaningExample
RateLimit-LimitRequests allowed per window for this key120
RateLimit-RemainingRequests left in the current window117
RateLimit-ResetSeconds until the window resets42
Response headers
HTTP/2 200
content-type: application/json
ratelimit-limit: 120
ratelimit-remaining: 117
ratelimit-reset: 42

When you hit the limit

Request number 121 within a window gets a 429 Too Many Requests response with a Retry-After header, in seconds:

429 Too Many Requests
{
  "error": {
    "type": "rate_limit_error",
    "code": "rate_limited",
    "message": "Rate limit of 120 requests per minute exceeded. Retry after 18 seconds.",
    "doc_url": "https://omni.cloudgens.net/docs/api/errors#rate_limited"
  }
}

Nothing happens on a rate-limited request: no credits are charged and no data changes. Wait the number of seconds in Retry-After and send it again.

Retry with backoff

Retry 429 and 5xx responses with exponential backoff, and always honor Retry-After when it's there. Send the same Idempotency-Key on retried POST requests so nothing is done twice.

async function omnilead(path, init = {}, attempt = 0) {
  const res = await fetch(`https://omni.cloudgens.net/api/v1${path}`, {
    ...init,
    headers: {
      Authorization: `Bearer ${process.env.OMNILEAD_API_KEY}`,
      "OmniLead-Version": "2026-09-28",
      ...init.headers,
    },
  });
  if ((res.status === 429 || res.status >= 500) && attempt < 5) {
    const retryAfter = Number(res.headers.get("retry-after"));
    const wait = retryAfter > 0 ? retryAfter * 1000 : 2 ** attempt * 500 + Math.random() * 250;
    await new Promise((r) => setTimeout(r, wait));
    return omnilead(path, init, attempt + 1);
  }
  return res;
}

Stay under the limit

  • Read the headers. When RateLimit-Remaining gets low, pause until RateLimit-Reset.
  • Use webhooks instead of polling. A webhook on lead.updated or email.replied replaces thousands of GET requests.
  • Page with big pages. limit=100 fetches the same data in a quarter of the requests of the default 25.
  • Batch where the API allows it. One POST /sequences/{id}/enrollments call enrolls up to 500 leads.
  • Use exports for bulk reads. POST /exports returns every lead in one file, for one request plus a few status checks.
  • Spread scheduled jobs. Run nightly syncs at a random minute rather than on the hour.

Need more?

If your integration genuinely needs more than 120 requests a minute after using webhooks and exports, contact support with what you're building and your expected volume.

Does the Try it console in the reference count?

Yes. It sends real requests with your test key, so they count toward that key's limit.

Is there a daily limit?

No daily request limit. Search and reveal are limited by your credits.

What's next