Pagination & sync

Cursor pages

Lists answer one page at a time:

{ "data": [ { "id": "…", "updated_at": "2026-09-30T14:05:00Z", "…": "…" } ], "next_cursor": "WyIyMDI2LTA5…" }

Pass limit (up to 200) and, for the next page, the next_cursor you got as cursor. next_cursor is null on the last page. A cursor is opaque — don't build or edit one.

curl "https://api.letsrealty.io/v1/leads?limit=200&cursor=WyIyMDI2LTA5…" \
  -H "Authorization: Bearer $LETSREALTY_API_KEY"

Lists are in change order: least recently updated first, by (updated_at, id). A record changed while you page moves to the end, so a full pass never skips anything.

Paged lists: GET /v1/leads, GET /v1/inquiries, GET /v1/activities, GET /v1/leads/{lead_id}/activities and GET /v1/events.

Keeping a copy in sync

Use updated_since to fetch only what changed:

  1. Do a full pass once and store the newest updated_at you saw.
  2. Every few minutes, list with updated_since set to one minute before that time, page to the end, and upsert by id.

The minute of overlap covers writes that commit a moment after their timestamp; upserting makes the repeats harmless.

curl "https://api.letsrealty.io/v1/leads?updated_since=2026-09-30T14:04:00Z" \
  -H "Authorization: Bearer $LETSREALTY_API_KEY"

updated_since needs a UTC offset (Z or +00:00).

Archived Leads

DELETE /v1/leads/{lead_id} archives a Lead (is_active: false) and sends lead.archived; nothing is ever hard-deleted through the API. Lists leave archived Leads out unless you pass include_archived=true — do that when syncing, so archives reach your copy.

Filters

GET /v1/leads also takes status, tier, owner and q (a text search). GET /v1/inquiries takes lead_id and property_id. See the API reference.

Webhooks or polling?

Webhooks tell you about changes within a minute. Polling with updated_since is the safety net: if your endpoint was down for longer than the retries, a sync pass catches everything up. GET /v1/events keeps the last 30 days of events for the same purpose.