How to Handle API Rate Limits
Overview
Testlify enforces rate limiting on all API requests to prevent abuse and ensure fair resource usage across all users. When you exceed your limit, the API returns a 429 Too Many Requests response. This guide explains the rate limit headers, how limits are tracked and reset, and how to handle 429 errors automatically in your integration.
Before You Begin
- You must have API access enabled on your Testlify account.
- You need a valid API key to authenticate requests.
- Basic familiarity with HTTP headers and response codes is recommended.
Rate Limit Response Headers
Every API response includes the following three headers. Monitor them to stay within your quota and avoid throttling.
- Retry-After — The time in milliseconds you must wait before sending another request after exceeding your rate limit. This header only appears after a 429 response.
- X-Ratelimit-Consumed — The number of API calls you have made within the current rate limit window. This value increments with each request.
- X-Ratelimit-Remaining — The number of API calls remaining in the current window. When this reaches 0, your quota is exhausted and all subsequent requests will be blocked until the window resets.
Example Response Headers
Here is a sample of what these headers look like in an API response:
{
"retry-after": "23284",
"x-ratelimit-consumed": "34",
"x-ratelimit-remaining": "166"
}
- retry-after: 23284 — Wait 23,284 milliseconds (approximately 23 seconds) before retrying.
- x-ratelimit-consumed: 34 — 34 requests have been made in the current window.
- x-ratelimit-remaining: 166 — 166 requests are still available before hitting the rate limit.
How Rate Limit Windows Work
The API uses a time-based window (for example, per minute, hour, or day) to track usage. Here is what happens with each request you send:
- X-Ratelimit-Consumed increments by 1.
- X-Ratelimit-Remaining decrements by 1.
When X-Ratelimit-Remaining reaches 0, the API returns 429 Too Many Requests for all subsequent requests until the window resets. Check the Retry-After header to know exactly how long to wait. Both X-Ratelimit-Consumed and X-Ratelimit-Remaining reset automatically at the start of the next window.
Handling 429 Errors Automatically
Use one of the following JavaScript approaches to detect and recover from rate limit errors automatically. Both examples read the Retry-After header and pause execution for the specified duration before retrying.
Option 1: Manual Retry Loop with Axios
This approach uses a while (true) loop with a try/catch block. On a 429 response, it reads Retry-After, waits the required time, and retries the request.
const axios = require('axios');
async function callApiWithRateLimitHandling(url, headers = {}) {
while (true) {
try {
const response = await axios.get(url, { headers });
return response.data;
} catch (error) {
if (error.response && error.response.status === 429) {
const retryAfter = parseInt(error.response.headers['retry-after'], 10) || 0;
console.warn(`Rate limit exceeded. Retrying after ${retryAfter} ms...`);
await new Promise(resolve => setTimeout(resolve, retryAfter));
} else {
throw error; // Re-throw non-rate-limit errors immediately
}
}
}
}
// Usage
const url = 'https://api.testlify.com/ping';
const headers = { Authorization: 'Bearer YOUR_API_KEY' };
callApiWithRateLimitHandling(url, headers)
.then(data => console.log(data))
.catch(error => console.error('API call failed:', error));
Option 2: Automatic Retry with the axios-retry Library
The axios-retry library adds retry logic to any Axios instance with minimal configuration. It automatically stops after the defined number of retry attempts, preventing infinite loops.
const axios = require('axios');
const axiosRetry = require('axios-retry');
const axiosInstance = axios.create();
axiosRetry(axiosInstance, {
retries: 3,
retryCondition: (error) => error.response && error.response.status === 429,
retryDelay: (retryCount, error) => {
const retryAfter = parseInt(error.response.headers['retry-after'], 10) || 0;
console.warn(`Retry attempt ${retryCount}. Waiting for ${retryAfter} ms...`);
return retryAfter;
}
});
// Usage
const url = 'https://api.testlify.com/ping';
const headers = { Authorization: 'Bearer YOUR_API_KEY' };
axiosInstance.get(url, { headers })
.then(response => console.log(response.data))
.catch(error => console.error('API call failed:', error));
Tip: Use Option 2 (axios-retry) if you already use Axios in your project. It requires less boilerplate and caps the number of retries at 3, so your app will not loop indefinitely if the API is unavailable.
Best Practices
- Monitor X-Ratelimit-Remaining proactively — Check this header before sending batches of requests and slow down as it approaches 0, rather than waiting for a 429 response.
- Implement exponential backoff — If you hit the rate limit frequently, increase the delay between retries exponentially (for example, 1s, 2s, 4s, 8s) to reduce load on the API and give the window time to reset.
- Batch and optimize requests — Combine multiple operations into fewer API calls wherever possible to stay within your quota. Avoid polling in tight loops.
- Use Retry-After precisely — The value is in milliseconds for fine-grained control. Pass it directly to
setTimeoutto avoid retrying too early and receiving another 429.
Summary
- Watch X-Ratelimit-Remaining on every response to track how many calls you have left.
- When you receive a 429 Too Many Requests response, read Retry-After (in milliseconds) and wait before retrying.
- Implement automatic retry logic using one of the Axios examples above to handle rate limits gracefully without manual intervention.
Need help? Contact support.