Rate limits & idempotency

Rate limits

Every plan gets the same budgets, shared by all of your agency's API Keys:

  • 10 requests per second in bursts, and 300 per minute sustained, for everything except ingestion;
  • 60 per minute for POST /v1/leads:ingest, in a budget of its own, so a backfill never slows your other integrations.

Every answer tells you where you stand, in the IETF format and the common X- one:

RateLimit-Policy: "burst";q=10;w=1, "minute";q=300;w=60
RateLimit: "minute";r=287;t=4
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 287
X-RateLimit-Reset: 4

RateLimit and X-RateLimit-* describe the tightest budget: r requests remaining and t seconds until it is full again.

When a budget is spent the answer is 429 with Retry-After in seconds. Wait that long and retry; slow down when Remaining gets low.

Idempotency

Networks fail mid-request. To make retrying a POST safe, send an Idempotency-Key header — any unique string up to 255 characters, such as a UUID or the record's id in your system:

curl https://api.letsrealty.io/v1/leads:ingest \
  -H "Authorization: Bearer $LETSREALTY_API_KEY" \
  -H "Idempotency-Key: crm-export-000123" \
  -H "Content-Type: application/json" \
  -d '{ "source": "Old CRM", "type": "registration", "person": { "name": "Luis", "phone": "8888 0000" } }'
  • The first request with a key runs normally and its answer is stored for 24 hours.
  • A retry with the same key and the same body gets the stored answer — same status and body — with Idempotent-Replayed: true. Nothing runs twice.
  • A retry while the first is still running gets 409; try again shortly.
  • Reusing a key with a different body gets 422.
  • A request that fails validation stores nothing, so you can fix it and resend with the same key.

Keys are scoped to the API Key that sent them. Every POST in the API accepts one.