Rate Limits

Understand request quotas for the Unduit API and how to handle rate limit responses in your integration.

60 requests per minute

The same limit applies to every /api/v1 endpoint, including login and refresh-token.

Overview

The API enforces a global rate limit per client IP address. All routes under /api/v1 share one counter — authenticated and unauthenticated requests count toward the same limit.

PolicyValue
Limit60 requests
Window1 minute (rolling)
ScopeAll /api/v1/* endpoints
KeyClient IP address

Response headers

Successful and rate-limited responses include standard rate-limit headers so you can track usage and backoff before hitting the cap.

HeaderDescription
RateLimit-LimitMaximum requests allowed per window (60).
RateLimit-RemainingRequests remaining in the current window.
RateLimit-ResetUNIX timestamp when the window resets.

429 Too Many Requests

When the limit is exceeded, the API returns HTTP 429 with a JSON body:

{
  "message": "Too many requests. Please try again later."
}

Check RateLimit-Reset or use exponential backoff before retrying. Do not retry immediately in a tight loop.

Best practices

  • Use pagination instead of firing many parallel list requests.
  • Cache responses where appropriate (e.g. reference data, wallet balance) to reduce call volume.
  • Serialize bulk operations — spread imports or sync jobs over time rather than bursting hundreds of requests in one second.
  • Read RateLimit-Remaining from response headers and slow down proactively when it approaches zero.

Example: handling 429

async function fetchWithBackoff(url, options, maxRetries = 3) {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    const response = await fetch(url, options);

    if (response.status !== 429) {
      return response;
    }

    const reset = response.headers.get('RateLimit-Reset');
    const waitMs = reset
      ? Math.max((Number(reset) * 1000) - Date.now(), 1000)
      : Math.min(1000 * 2 ** attempt, 30000);

    await new Promise((r) => setTimeout(r, waitMs));
  }

  throw new Error('Rate limit exceeded after retries');
}

Next steps