SchoolScout API

Rate Limits

Understanding API rate limits and throttling

Overview

The SchoolScout API enforces rate limits to ensure fair usage and platform stability. Limits are applied per organization on a sliding 60-second window.

Limits by Plan

PlanRequests/minMax results/requestConcurrent scouting jobs
Free300501
Starter6001002
Growth1,2002005
Scale3,00050010
Pro5,0001,00025
Enterprise5,0001,00025

API key overrides: Individual API keys can have custom rate limits configured in Settings > API Keys.

Response Headers

Every response includes rate limit headers:

HeaderDescription
X-RateLimit-LimitMaximum requests allowed in the current window
X-RateLimit-RemainingRequests remaining in the current window
X-RateLimit-ResetUnix timestamp (seconds) when the window resets

When rate limited, a Retry-After header is also included.

Rate Limited Responses

When you exceed the rate limit, the API returns HTTP 429:

{
  "error": "Rate Limited",
  "message": "Too many requests. Please slow down.",
  "code": "RATE_LIMITED"
}

Handling Rate Limits

  1. Check headers proactively -- monitor X-RateLimit-Remaining to throttle before hitting the limit
  2. Use Retry-After -- wait the specified number of seconds before retrying
  3. Implement exponential backoff -- if you receive a 429, wait progressively longer between retries

Example retry logic:

import time
import requests

def api_request(url, headers, max_retries=3):
    for attempt in range(max_retries):
        response = requests.get(url, headers=headers)
        if response.status_code == 429:
            retry_after = int(response.headers.get("Retry-After", 2 ** attempt))
            time.sleep(retry_after)
            continue
        return response
    raise Exception("Rate limit exceeded after retries")

Concurrency Limits

Scouting (analysis) jobs have a separate concurrency limit per plan. If you exceed the limit, the scouting request returns HTTP 429 with a message indicating the concurrent job cap.

Best Practices

  • Batch where possible -- use bulk unlock (POST /unlock with entities array) instead of individual calls
  • Cache responses -- entities don't change frequently; cache district/school data for reasonable periods
  • Use filters -- narrow searches with state, status, and other filters to reduce result sizes
  • Paginate efficiently -- request only the limit you need; don't over-fetch

On this page