Skip to main content
The Hyparrow API enforces rate limits to protect service availability. When you exceed your limit, the API returns a 429 Too Many Requests response and stops processing further requests until the current window resets.

Default limits

SettingValue
Window duration15 minutes (900 seconds)
Requests per window100
Limit scopePer API key (or per IP address for unauthenticated requests)
These defaults apply to all API keys. Individual API keys may have a custom rateLimit configured at creation time — contact support if you need a higher limit.

How limits are applied

The rate limiter counts requests within a sliding window. Each API key gets its own counter:
  • Authenticated requests (using X-API-Key / X-API-Secret): the limit is tracked per API key. Multiple servers sharing the same credentials share a single counter.
  • Unauthenticated requests: the limit falls back to tracking by client IP address.
The counter resets after the 15-minute window expires. Requests at exactly the limit boundary (current >= limit) are rejected before the counter increments, so the 101st request in a window always fails.

429 response

When you exceed the limit, you receive:
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
{
  "success": false,
  "error": "Too many requests, please try again later"
}
The API does not currently return Retry-After or X-RateLimit-* headers. To determine when the window resets, track the timestamp of your first request in the current window and add 900 seconds.

Best practices

Cache read responses

Endpoints like /api/v1/bills/categories, /api/v1/bills/services, and /api/v1/transfers/banks return data that changes infrequently. Cache these responses locally for at least 15 minutes to avoid burning your quota on repeated lookups.

Exponential backoff on 429

When you receive a 429, wait before retrying. Start with a 1-second delay and double it on each subsequent 429, up to a maximum of 60 seconds. Add random jitter to avoid synchronized retries across multiple instances.

Batch status checks

If you need to poll for transaction status, use a single request per transaction at increasing intervals rather than polling every few seconds. Consider webhook notifications instead of polling where possible.

Separate keys per environment

Use different API keys for production and staging. This keeps limits independent and prevents test traffic from consuming your production quota.

Backoff implementation example

async function requestWithBackoff(fn, maxRetries = 5) {
  let delay = 1000; // 1 second initial delay

  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    const response = await fn();

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

    if (attempt === maxRetries) {
      throw new Error('Rate limit exceeded after max retries');
    }

    // Exponential backoff with jitter
    const jitter = Math.random() * 500;
    await new Promise(resolve => setTimeout(resolve, delay + jitter));
    delay = Math.min(delay * 2, 60000); // cap at 60 seconds
  }
}

Request budgeting

With 100 requests per 15-minute window, plan your integration around these approximate budgets:
Use caseEstimated requestsNotes
Single bill payment flow3–4Validate customer, get service options, pay, check status
Single bank transfer flow2–3Account inquiry, initiate transfer, check status
KYC verification1 per checkEach endpoint call counts as one request
Listing billers + categories1–2Cache results; these rarely change
If your use case requires more than 100 requests per 15 minutes, contact support to discuss a higher rate limit for your API key.