General reference

API Rate Limits

Rate Limits

The Incode Omni API uses a token bucket algorithm to enforce rate limits. It's important to understand how limits work and how to handle them gracefully. This will help you build integrations that stay within bounds under normal conditions. It will also help you recover cleanly when limits are reached.

How rate limiting works

Each API endpoint belongs to one of three categories. Each category has its own independent token bucket. When you make a request, one token is consumed from that category's bucket. If the bucket is empty, the request is rejected with a 429 Too Many Requests response.

Buckets refill automatically at a fixed rate (maxRps) up to their maximum capacity (burst). The burst value defines the maximum number of requests you can make in a single second before the bucket empties.

Endpoint categories and limits

Category Endpoints maxRps Burst
SUPER_HEAVY ID capture and processing (add/front, add/back, process/id) 1 req/sec 5
HEAVY Face capture and processing (add/face, process/face) 1 req/sec 5
OTHER All other endpoints 100 req/sec 50

Note

The category for a given endpoint is fixed. You cannot move endpoints between categories or configure per-endpoint limits. For special cases where the default limits are insufficient, contact your Incode Customer Success representative.

Reading a rate limit example

The SUPER_HEAVY bucket has a burst capacity of 5. If you send 5 requests to add/front within the same second, the bucket empties and any additional requests within that second return 429 Too Many Requests. The bucket then refills at 1 token per second until it reaches capacity again.

In practice, a typical onboarding session might call add/front, add/back, and process/id sequentially. Thus, a single session's document capture flow consumes 3 tokens. The burst capacity of 5 accommodates a small amount of concurrent sessions. High-volume production traffic will approach limits in the SUPER_HEAVY category more quickly than in OTHER.

Handling 429 responses

When your integration receives a 429 response, do not retry immediately. Implement an exponential backoff strategy:

  1. On the first 429, wait before retrying.
  2. Double the wait time on each subsequent retry.
  3. Add a small random jitter to prevent synchronized retries across concurrent requests.
  4. Set a maximum retry count or total wait time to avoid indefinite loops.
async function requestWithBackoff(fn, maxRetries = 4) {
  let delay = 1000; {/* start with 1 second */}
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      return await fn();
    } catch (err) {
      if (err.status !== 429 || attempt === maxRetries) throw err;
      const jitter = Math.random() * 500;
      await new Promise(res => setTimeout(res, delay + jitter));
      delay *= 2;
    }
  }
}

{/* REVIEW: Confirm whether the API returns a Retry-After header on 429 responses. If so, add guidance here to read that header value instead of computing backoff independently. */}

Request and response size limits

Two additional constraints apply regardless of rate category:

  • Maximum request/response size: 10 MB. Images and files larger than 10 MB cannot be uploaded or retrieved.
  • Request timeout: 30 seconds. Any request that exceeds this limit returns a timeout error.

{/* REVIEW: Confirm the exact error code or message returned on timeout. The source material does not specify. */}

Was this page helpful?