SearchJetEngine

Rate Limits & Quotas

## Overview SearchJet enforces rate limits and quotas to ensure fair usage and platform stability. Understanding these limits helps you design resilient applications and avoid service disruptions. --- ## Rate Limits by Plan | Plan | Requests / Minute | Requests / Day | Index Documents / Day | Search Queries / Day | |---|---|---|---|---| | **Free** | 60 | 10,000 | 1,000 | 5,000 | | **Pro** | 300 | 100,000 | 50,000 | 500,000 | | **Growth** | 600 | 500,000 | 500,000 | 5,000,000 | | **Enterprise** | Custom | Custom | Custom | Custom | Limits are enforced per API key. Each plan tier includes higher throughput and larger daily quotas. --- ## Rate Limit Headers Every API response includes headers indicating your current rate limit status: | Header | Description | |---|---| | `X-RateLimit-Limit` | Maximum requests allowed per minute | | `X-RateLimit-Remaining` | Requests remaining in the current window | | `X-RateLimit-Reset` | Unix timestamp when the rate limit window resets | ### Example Headers ``` X-RateLimit-Limit: 300 X-RateLimit-Remaining: 247 X-RateLimit-Reset: 1720647600 ``` Monitor these headers in your application to proactively manage your request rate. --- ## Handling 429 Responses When you exceed the rate limit, SearchJet returns a `429 Too Many Requests` response. ### Response Body ```json { "error": "rate_limit_exceeded", "message": "You have exceeded the rate limit of 300 requests per minute", "retry_after": 12, "limit": 300, "remaining": 0, "reset_at": "2025-07-10T14:31:00Z" } ``` ### Retry-After Header The response includes a `Retry-After` header specifying how many seconds to wait before retrying: ``` Retry-After: 12 ``` ### Exponential Backoff Strategy Implement exponential backoff with jitter for automatic retries: ```python import time import random import requests def search_with_retry(query, max_retries=3): for attempt in range(max_retries): response = requests.get( "https://app.searchjetengine.com/api/v1/search", headers={"Authorization": "Bearer YOUR_API_KEY"}, params={"q": query} ) if response.status_code != 429: return response.json() retry_after = int(response.headers.get("Retry-After", 1)) jitter = random.uniform(0, 1) wait_time = retry_after + (2 ** attempt) + jitter print(f"Rate limited. Retrying in {wait_time:.1f}s...") time.sleep(wait_time) raise Exception("Max retries exceeded") ``` --- ## Usage Reporting Report usage from your application to SearchJet for accurate quota tracking and analytics. ### Report Usage ``` POST /api/v1/sites/{siteId}/usage ``` #### Request Body ```json { "searches": 150, "index_operations": 500, "timestamp": "2025-07-10T14:00:00Z" } ``` | Field | Type | Description | |---|---|---| | `searches` | integer | Number of search queries performed | | `index_operations` | integer | Number of index add/update/delete operations | | `timestamp` | string | ISO 8601 timestamp for the usage period | #### Response ```json { "recorded": true, "period": "2025-07-10", "total_searches_today": 1250, "total_index_ops_today": 8750 } ``` ### Get Usage Stats ``` GET /api/v1/sites/{siteId}/usage ``` #### Query Parameters | Parameter | Type | Default | Description | |---|---|---|---| | `period` | string | `today` | `today`, `this_week`, `this_month`, or `all` | #### Response ```json { "siteId": "site_abc123", "plan": "pro", "period": "today", "searches": { "used": 1250, "limit": 500000, "remaining": 498750, "percent_used": 0.25 }, "index_operations": { "used": 8750, "limit": 50000, "remaining": 41250, "percent_used": 17.5 }, "requests": { "used": 4520, "limit": 100000, "remaining": 95480, "percent_used": 4.52 }, "remaining_quota": true } ``` The `remaining_quota` field provides a quick boolean check: `true` if you have quota available, `false` if you are at or near your limit. --- ## What Happens When You Exceed Limits | Limit Type | Behavior | |---|---| | **Rate limit (per minute)** | 429 response with `Retry-After` header | | **Daily search quota** | 403 response — search queries rejected until next day | | **Daily index quota** | 403 response — index operations rejected until next day | | **Daily request quota** | 403 response — all requests rejected until next day | Quotas reset at midnight UTC. Rate limits use a sliding window. --- ## Best Practices for Staying Within Limits - **Monitor headers.** Check `X-RateLimit-Remaining` on every response and slow down proactively when remaining drops below 20%. - **Cache search results.** Cache popular queries for 60-300 seconds to reduce redundant API calls. - **Batch index operations.** Use the bulk endpoints to send multiple documents in one request. - **Implement backoff.** Use exponential backoff with jitter on 429 responses. - **Track daily usage.** Poll the usage endpoint or maintain your own counters to avoid hitting daily quotas. - **Use server-side search.** Never expose API keys in client-side code, which can lead to uncontrolled usage spikes. - **Set alerts.** Configure alerts at 75% and 90% of daily quotas to get advance warning. --- ## Upgrading Your Plan If you consistently approach your quota limits, consider upgrading: 1. Navigate to your SearchJet dashboard 2. Go to **Settings > Billing** 3. Select a plan that meets your usage needs 4. Upgrade takes effect immediately — rate limits and quotas update in real time Enterprise customers can contact support for custom limits and dedicated infrastructure. --- ## Code Examples ### Check Remaining Quota ```python import requests def check_quota(site_id): response = requests.get( f"https://app.searchjetengine.com/api/v1/sites/{site_id}/usage", headers={"Authorization": "Bearer YOUR_API_KEY"}, params={"period": "today"} ) data = response.json() if data["searches"]["percent_used"] > 80: print(f"Warning: {data['searches']['percent_used']}% of search quota used") return data["remaining_quota"] remaining = check_quota("site_abc123") print(f"Quota remaining: {remaining}") ``` ### Handle Rate Limits in JavaScript ```javascript async function searchWithRateLimitHandling(query) { const response = await fetch( `https://app.searchjetengine.com/api/v1/search?q=${encodeURIComponent(query)}`, { headers: { Authorization: `Bearer ${process.env.SEARCHJET_API_KEY}` } } ); const remaining = parseInt(response.headers.get("X-RateLimit-Remaining")); if (remaining < 50) { console.warn(`Low rate limit remaining: ${remaining}`); } if (response.status === 429) { const retryAfter = parseInt(response.headers.get("Retry-After")) || 5; console.log(`Rate limited. Retrying in ${retryAfter}s...`); await new Promise(resolve => setTimeout(resolve, retryAfter * 1000)); return searchWithRateLimitHandling(query); } return response.json(); } ``` ### Monitor Quota with cURL ```bash curl -X GET "https://app.searchjetengine.com/api/v1/sites/site_abc123/usage?period=today" \ -H "Authorization: Bearer YOUR_API_KEY" | jq '.searches' ``` --- ## Related Pages - [Search API](/docs/search-api) — Query your indexed data - [Error Handling](/docs/error-handling) — Comprehensive error code reference - [API Key Setup](/docs/api-key-setup) — Create and manage keys