Too Many Requests Error
https://bessapay.net/errors/too-many-requestsOverview
A Too Many Requests error occurs when you have exceeded the rate limits for API calls. This error is returned with HTTP status code 429 and indicates that you should slow down the rate at which you are making requests.
Details
- Error Code: TOO_MANY_REQUESTS
- HTTP Status: 429
- Error Type: Client Error
Common scenarios
- • Exceeded requests per second limit
- • Exceeded daily or monthly API quota
- • Multiple concurrent requests to the same endpoint
- • Batch operations with too many items
- • Automated scripts without proper rate limiting
Example
1{
2 "type": "https://bessapay.net/errors/too-many-requests",
3 "title": "Too Many Requests",
4 "status": 429,
5 "detail": "Rate limit exceeded. Please wait before making additional requests.",
6 "instance": "/api/v1/transactions",
7 "errorCode": "TOO_MANY_REQUESTS",
8 "timestamp": "2023-06-15T16:45:12Z",
9 "rateLimit": {
10 "limit": 100,
11 "remaining": 0,
12 "reset": 1623772512
13 }
14}How to Fix
Implement rate limiting
Add rate limiting logic to your client applications to stay within the API limits. Use the rate limit information provided in response headers to adjust your request rate.
Implement exponential backoff
When encountering a 429 error, implement an exponential backoff strategy where you wait progressively longer between retries (e.g., 1s, 2s, 4s, 8s).
1async function fetchWithBackoff(url, options, maxRetries = 5) {
2 let retries = 0;
3
4 while (retries < maxRetries) {
5 try {
6 const response = await fetch(url, options);
7
8 if (response.status !== 429) {
9 return response;
10 }
11
12 // If we got a 429, get retry information
13 const retryAfter = response.headers.get('Retry-After');
14 const waitTime = retryAfter ? parseInt(retryAfter, 10) * 1000 : Math.pow(2, retries) * 1000;
15
16 console.log(`Rate limited. Waiting ${waitTime}ms before retry.`);
17 await new Promise(resolve => setTimeout(resolve, waitTime));
18
19 retries++;
20 } catch (error) {
21 throw error;
22 }
23 }
24
25 throw new Error('Maximum retries exceeded');
26}Monitor rate limits
BessaPay API includes rate limit information in response headers:
X-RateLimit-Limit: Maximum number of requests per time windowX-RateLimit-Remaining: Number of requests remaining in the current windowX-RateLimit-Reset: Unix timestamp when the rate limit window resets
Optimize request patterns
Consider batching multiple operations into single requests when possible. Cache responses that don't change frequently to reduce API calls.
Upgrade your plan
If you consistently hit rate limits, consider upgrading to a plan with higher limits that better suits your usage patterns.
Code Example: Handling Rate Limit Errors
1// Complete example of handling rate limits with queuing
2class ApiClient {
3 constructor(apiKey, baseUrl = 'https://api.semuni.com/v1') {
4 this.apiKey = apiKey;
5 this.baseUrl = baseUrl;
6 this.requestQueue = [];
7 this.isProcessingQueue = false;
8 this.rateLimitRemaining = null;
9 this.rateLimitReset = null;
10 }
11
12 async request(endpoint, options = {}) {
13 // Add to queue and process
14 return new Promise((resolve, reject) => {
15 this.requestQueue.push({
16 endpoint,
17 options,
18 resolve,
19 reject
20 });
21
22 this.processQueue();
23 });
24 }
25
26 async processQueue() {
27 if (this.isProcessingQueue || this.requestQueue.length === 0) {
28 return;
29 }
30
31 this.isProcessingQueue = true;
32
33 // Check if we need to wait for rate limit reset
34 if (this.rateLimitRemaining === 0 && this.rateLimitReset) {
35 const now = Math.floor(Date.now() / 1000);
36 if (now < this.rateLimitReset) {
37 const waitTime = (this.rateLimitReset - now) * 1000;
38 console.log(`Rate limit reached. Waiting ${waitTime}ms before continuing.`);
39 await new Promise(resolve => setTimeout(resolve, waitTime));
40 }
41 }
42
43 const { endpoint, options, resolve, reject } = this.requestQueue.shift();
44
45 try {
46 const response = await fetch(`${this.baseUrl}${endpoint}`, {
47 ...options,
48 headers: {
49 'Authorization': `Bearer ${this.apiKey}`,
50 'Content-Type': 'application/json',
51 ...options.headers
52 }
53 });
54
55 // Update rate limit info from headers
56 this.rateLimitRemaining = parseInt(response.headers.get('X-RateLimit-Remaining') || '1000', 10);
57 this.rateLimitReset = parseInt(response.headers.get('X-RateLimit-Reset') || '0', 10);
58
59 if (response.status === 429) {
60 // Put the request back in the queue
61 const retryAfter = parseInt(response.headers.get('Retry-After') || '1', 10);
62 console.log(`Rate limited. Retrying after ${retryAfter} seconds.`);
63
64 setTimeout(() => {
65 this.requestQueue.unshift({ endpoint, options, resolve, reject });
66 this.isProcessingQueue = false;
67 this.processQueue();
68 }, retryAfter * 1000);
69 return;
70 }
71
72 const data = await response.json();
73 resolve(data);
74 } catch (error) {
75 reject(error);
76 } finally {
77 this.isProcessingQueue = false;
78 // Continue processing queue after a small delay
79 setTimeout(() => this.processQueue(), 100);
80 }
81 }
82}
83
84// Usage example
85const client = new ApiClient('your-api-key');
86client.request('/transactions')
87 .then(data => console.log(data))
88 .catch(error => console.error(error));