Rate Limits

Rate Limits

Understand how rate limiting works and how to handle it in your application.

Overview

Rate limits help ensure fair usage and protect the stability of our APIs. Limits are applied per API key and vary based on your subscription plan.

PlanRequests/MinuteRequests/MonthOverage
Free101,000-
Starter6010,000AED0.008/req
Professional300100,000AED0.004/req
Business1000500,000AED0.002/req
EnterpriseCustomCustomAEDCustom/req

Response Headers

Every API response includes headers that help you track your rate limit status:

http
HTTP/1.1 200 OK
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1640995200
X-RateLimit-Limit

Maximum requests allowed per minute for your plan

X-RateLimit-Remaining

Requests remaining in the current window

X-RateLimit-Reset

Unix timestamp when the rate limit resets

Handling Rate Limits

When you exceed your rate limit, the API returns a 429 Too Many Requests response. Here's how to handle it:

javascript
import { KhaleejiAPI } from '@khaleejiapi/sdk';
const client = new KhaleejiAPI('your_api_key', {
// SDK handles rate limiting automatically
retryOnRateLimit: true,
maxRetries: 3
});
// Or handle manually
try {
const result = await client.ip.lookup('8.8.8.8');
} catch (error) {
if (error.code === 'RATE_LIMITED') {
const retryAfter = error.retryAfter; // seconds to wait
console.log(`Rate limited. Retry after ${retryAfter} seconds`);
}
}

Python (requests + exponential backoff)

Honours the Retry-After header when present and falls back to exponential backoff with full jitter to avoid retry stampedes.

python
import time
import random
import requests
API_KEY = "your_api_key"
BASE_URL = "https://khaleejiapi.dev/api/v1"
def call_with_backoff(path, *, params=None, max_retries=5):
"""Call KhaleejiAPI with exponential backoff + full jitter on 429s."""
for attempt in range(max_retries):
resp = requests.get(
f"{BASE_URL}{path}",
headers={"Authorization": f"Bearer {API_KEY}"},
params=params,
timeout=10,
)
if resp.status_code != 429:
resp.raise_for_status()
return resp.json()
# Honour Retry-After when present, otherwise back off exponentially.
retry_after = resp.headers.get("Retry-After")
if retry_after is not None:
sleep_for = float(retry_after)
else:
sleep_for = min(60, (2 ** attempt)) * random.random()
time.sleep(sleep_for)
raise RuntimeError("Rate limited after max retries")
data = call_with_backoff("/ip/lookup", params={"ip": "8.8.8.8"})
print(data)

Go (net/http + exponential backoff)

Idiomatic Go example using net/http. Same retry policy as the Python sample: respect Retry-After, otherwise exponential backoff capped at 60 seconds with full jitter.

go
package main
import (
"encoding/json"
"errors"
"fmt"
"io"
"math"
"math/rand"
"net/http"
"strconv"
"time"
)
const (
apiKey = "your_api_key"
baseURL = "https://khaleejiapi.dev/api/v1"
)
// callWithBackoff retries on 429 with exponential backoff + full jitter.
// It honours the server-provided Retry-After header when present.
func callWithBackoff(path string, maxRetries int) ([]byte, error) {
client := &http.Client{Timeout: 10 * time.Second}
for attempt := 0; attempt < maxRetries; attempt++ {
req, err := http.NewRequest(http.MethodGet, baseURL+path, nil)
if err != nil {
return nil, err
}
req.Header.Set("Authorization", "Bearer "+apiKey)
resp, err := client.Do(req)
if err != nil {
return nil, err
}
body, _ := io.ReadAll(resp.Body)
resp.Body.Close()
if resp.StatusCode != http.StatusTooManyRequests {
if resp.StatusCode >= 400 {
return nil, fmt.Errorf("api error %d: %s", resp.StatusCode, body)
}
return body, nil
}
var sleep time.Duration
if ra := resp.Header.Get("Retry-After"); ra != "" {
if secs, err := strconv.Atoi(ra); err == nil {
sleep = time.Duration(secs) * time.Second
}
}
if sleep == 0 {
backoff := math.Min(60, math.Pow(2, float64(attempt)))
sleep = time.Duration(backoff*rand.Float64()) * time.Second
}
time.Sleep(sleep)
}
return nil, errors.New("rate limited after max retries")
}
func main() {
body, err := callWithBackoff("/ip/lookup?ip=8.8.8.8", 5)
if err != nil {
panic(err)
}
var out map[string]any
_ = json.Unmarshal(body, &out)
fmt.Println(out)
}

Best Practices

Implement Caching

Cache API responses when possible to reduce the number of requests. Many of our endpoints return data that doesn't change frequently (e.g., IP geolocation).

Use Batch Requests

Some endpoints support batch operations. Use them to process multiple items in a single request instead of making multiple individual calls.

Monitor Your Usage

Keep track of your API usage in your dashboard. Set up alerts to notify you when you're approaching your limits.

Upgrade When Needed

If you consistently hit rate limits, consider upgrading your plan for higher limits and better overage rates.