Skip to content

Rate limits

Three independent limits govern every API key:

  1. Rate, requests per minute (sliding window). Trips 429 rate_limited.
  2. Concurrency, one in-flight request per key (see below). Extra parallel calls queue, they are not rejected.
  3. Credit balance, drawn down per successful call; 402 out_of_credits at zero. See Pricing.

For credit costs and plan tiers, see Pricing.

Per-minute limits

PlanRate limit (req/min)
Free20
Monthly200
Annual300
Enterprisecustom

The window is sliding, based on the last 60 seconds, not a calendar minute.

Concurrency = 1

Each API key runs one in-flight request at a time. This is a first-class limit, on par with your per-minute rate. Firing requests in parallel on a single key does not go faster, the extra calls serialize behind the one in flight. Scale throughput by raising your plan, not by adding parallelism. For large result sets, use async jobs + webhooks (below) instead of many concurrent syncs.

Result caps

One caps table for the whole API. maxItems on a search is the single knob that decides sync vs async: maxItems ≤ 50 runs synchronously; maxItems ≥ 51 flips the request to an async job (as do extractionMethod: PAGINATION_WITH_ZOOM_IN and async: true).

EndpointFieldBoundsSync ↔ async
POST /v1/search, POST /v1/listings/{for-sale,for-rent,sold}maxItems1 to ~820 (PAGINATION); ~500 (MAP_MARKERS)≤ 50 sync · ≥ 51 async · PAGINATION_WITH_ZOOM_IN always async
POST /v1/search/with-detailsmaxItems1 to ~820always async (two chained stages)
GET /v1/listings (REST wrapper)max_items1-50sync only, for >50 use POST /v1/search
POST /v1/properties/batchentries (urls + addresses)up to 500 per jobalways async
GET /v1/buildings/by-url--sync by default; set sync=false for large buildings
GET /v1/jobslimit1-500 (default 50)n/a
GET /v1/jobs/{id}/resultslimit1-1000 (default 100)n/a
GET /v1/usagelimit1-1000 (default 100)n/a

The earlier “up to 50”, “≤50”, and “1-500” figures refer to different knobs: 50 is the sync search cap, 500 is the batch entry cap, and 1000 is the job-results page cap. They are not in conflict.

429 response

{ "error": { "code": "rate_limited",
"message": "Rate limit exceeded for plan 'monthly' (200/min)",
"request_id": "..." } }

Handling 429

  • Back off with exponential jitter. Don’t retry faster than once every 2 seconds.
  • Use async + webhooks for any batch over ~50, sync calls have a 5-min ceiling.
  • Cache aggressively on your side for static fields (zpid, address, year built) so you don’t burn your rate limit re-fetching the same property.