← Back to Platform

API Rate Limits

Understand rate limits per tier, response headers, and how to handle 429 Too Many Requests gracefully.

Limits by Tier

Rate limits are enforced per API key on a rolling 24-hour window. Limits reset at midnight UTC.

Explorer

3 / day
3 requests per 24 hours
Free

Starter

25 / day
25 requests per 24 hours
$99/mo

Professional

100 / day
100 requests per 24 hours
$249/mo

Business

Unlimited requests
$499/mo
Note

The /health endpoint is not rate-limited. Marketplace management endpoints (/marketplace/*) have separate limits and do not count against your daily quota.

Rate Limit Headers

Every API response includes rate limit information in the response headers.

HeaderDescriptionExample
X-RateLimit-LimitMaximum requests allowed per day for your tier100
X-RateLimit-RemainingRequests remaining in the current window73
X-RateLimit-ResetUnix timestamp when the rate limit window resets (midnight UTC)1740528000
Retry-AfterSeconds until you can retry (only on 429 responses)3600

Handling 429 Too Many Requests

When you exceed your rate limit, the API returns a 429 status code with a JSON error body and a Retry-After header.

429 Response Example

Response HTTP/1.1 429 Too Many Requests Content-Type: application/json X-RateLimit-Limit: 25 X-RateLimit-Remaining: 0 X-RateLimit-Reset: 1740528000 Retry-After: 3600 { "detail": "Rate limit exceeded. 25/25 requests used today. Resets at midnight UTC.", "upgrade_url": "https://thinkkits.com/pricing" }
Important

Do not retry immediately on a 429. Always respect the Retry-After header. Clients that repeatedly ignore rate limits may be temporarily blocked.

Code Examples

curl

bash # Check remaining quota in response headers curl -si "https://api.thinkkits.com/schools/search?q=Springfield" \ -H "X-API-Key: tk_live_abc123" \ | grep -i "x-ratelimit" # Output: # X-RateLimit-Limit: 100 # X-RateLimit-Remaining: 99 # X-RateLimit-Reset: 1740528000

JavaScript (fetch with retry)

JavaScript async function fetchWithRetry(url, options, maxRetries = 3) { for (let attempt = 0; attempt < maxRetries; attempt++) { const res = await fetch(url, options); // Log remaining quota const remaining = res.headers.get('X-RateLimit-Remaining'); console.log(`Requests remaining: ${remaining}`); if (res.status !== 429) return res; // Respect Retry-After header const retryAfter = parseInt(res.headers.get('Retry-After') || '60'); console.warn(`Rate limited. Retrying in ${retryAfter}s...`); await new Promise(r => setTimeout(r, retryAfter * 1000)); } throw new Error('Max retries exceeded'); } // Usage const res = await fetchWithRetry( 'https://api.thinkkits.com/schools/search?q=Springfield', { headers: { 'X-API-Key': 'tk_live_abc123' } } ); const data = await res.json();

Python (requests with retry)

Python import time import requests API_KEY = "tk_live_abc123" BASE_URL = "https://api.thinkkits.com" def api_request(endpoint, params=None, max_retries=3): headers = {"X-API-Key": API_KEY} for attempt in range(max_retries): resp = requests.get(f"{BASE_URL}{endpoint}", headers=headers, params=params) # Log remaining quota remaining = resp.headers.get("X-RateLimit-Remaining", "?") print(f"Requests remaining: {remaining}") if resp.status_code != 429: resp.raise_for_status() return resp.json() # Respect Retry-After header retry_after = int(resp.headers.get("Retry-After", "60")) print(f"Rate limited. Waiting {retry_after}s...") time.sleep(retry_after) raise Exception("Max retries exceeded") # Usage schools = api_request("/schools/search", {"q": "Springfield"})

Best Practices

  1. Monitor your usage. Check X-RateLimit-Remaining headers proactively. Don't wait for a 429 to learn you're at your limit.
  2. Cache aggressively. School profiles and funding data change infrequently. Cache responses for 24 hours to reduce API calls.
  3. Use bulk endpoints. The /schools/bulk-import endpoint lets you look up many schools in one request (Business tier), saving rate limit budget.
  4. Implement exponential backoff. If you get a 429, wait the Retry-After duration. If you get a second 429, double the wait time.
  5. Upgrade when you need more. If you consistently hit limits, upgrading from Starter ($99/mo) to Professional ($249/mo) gives you 4x the daily quota. Business tier has no limits.
  6. Use webhooks instead of polling. Instead of polling for changes, subscribe to customer webhooks to receive events in real-time.

Upgrading Your Tier

Need more requests? Upgrade your plan through the billing portal or API.

curl # Check current usage curl "https://api.thinkkits.com/marketplace/usage" \ -H "X-API-Key: tk_live_abc123" # Upgrade tier curl -X POST "https://api.thinkkits.com/marketplace/keys/abc123/upgrade" \ -H "X-API-Key: tk_live_abc123" \ -H "Content-Type: application/json" \ -d '{"new_tier": "PREMIUM"}'

Need a custom rate limit for your use case? Contact our API team.

← Full API Documentation · API Changelog · Back to Platform

Was this article helpful?

← Back to Help Center