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.
| Plan | Requests/Minute | Requests/Month | Overage |
|---|---|---|---|
| Free | 10 | 1,000 | - |
| Starter | 60 | 10,000 | |
| Professional | 300 | 100,000 | |
| Business | 1000 | 500,000 | |
| Enterprise | Custom | Custom |
Response Headers
Every API response includes headers that help you track your rate limit status:
HTTP/1.1 200 OKX-RateLimit-Limit: 100X-RateLimit-Remaining: 95X-RateLimit-Reset: 1640995200X-RateLimit-LimitMaximum requests allowed per minute for your plan
X-RateLimit-RemainingRequests remaining in the current window
X-RateLimit-ResetUnix 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:
import { KhaleejiAPI } from '@khaleejiapi/sdk'; const client = new KhaleejiAPI('your_api_key', { // SDK handles rate limiting automatically retryOnRateLimit: true, maxRetries: 3}); // Or handle manuallytry { 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.
import timeimport randomimport 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.
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.