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

Plan Rate limit (req/min)
Free 20
Monthly 200
Annual 300
Enterprise custom

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).

Endpoint Field Bounds Sync ↔ async
POST /v1/search, POST /v1/listings/{for-sale,for-rent,sold} maxItems 1 to ~820 (PAGINATION); ~500 (MAP_MARKERS) ≤ 50 sync · ≥ 51 async · PAGINATION_WITH_ZOOM_IN always async
POST /v1/search/with-details maxItems 1 to ~820 always async (two chained stages)
GET /v1/listings (REST wrapper) max_items 1-50 sync only, for >50 use POST /v1/search
POST /v1/properties/batch entries (urls + addresses) up to 500 per job always async
GET /v1/buildings/by-url - - sync by default; set sync=false for large buildings
GET /v1/jobs limit 1-500 (default 50) n/a
GET /v1/jobs/{id}/results limit 1-1000 (default 100) n/a
GET /v1/usage limit 1-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.