GET /v1/changes endpoint returns metadata for changed tables and supports conditional requests via ETag to skip polling when nothing is new.
With a
transformed key, /v1/changes lists only tables within the key’s categories and tables; tables without a category are never listed, and ?category=X outside the key’s scope returns 403. A raw key sees all tables — see Key types.1
Poll for changed tables
Send a Example response:
GET request to /v1/changes with an ISO-8601 since timestamp (UTC, e.g. …Z). An offset such as +02:00 is converted to UTC; in a query string write the + as %2B, otherwise it is read as a space and the request fails with 400. The response lists every table whose last_sync_at is after that timestamp, including the corresponding endpoint URL. A table listed here has to be fetched in full again — /v1/changes reports changed tables, not changed rows. endpoint_url points to the path to fetch: /v1/{category}/{table} for category tables, /v1/raw/{table} for raw tables. Raw tables that are blocked for your account are not listed. Add an optional category parameter (e.g. category=property) to only return tables belonging to that category.2
Fetch only changed tables
For each item returned by
/v1/changes, request the corresponding endpoint only. Skip any table that is absent from the response. This avoids unnecessary data transfer and preserves your 2,500 req/h rate limit budget.3
Use conditional GET on subsequent polls
Store the The
ETag header from the first successful /v1/changes response. On your next poll, send it back as If-None-Match.ETag depends on since and category as well, so keep the ETag together with the since it was issued for. If no tables have changed since the ETag was issued, the API returns 304 Not Modified with an empty body and skips the database query. The request still counts toward your rate limit.4
Advance the since parameter
After a successful sync, store the highest
last_sync_at from the /v1/changes response and use it as the since value for the next poll. This creates a sliding window so each run evaluates only the interval since the previous run. If the response is empty, keep the old since.Do not use your own clock here. Client and server clocks drift, and a table that finished syncing shortly before your timestamp would never appear in a later /v1/changes response.5
Full Python example
A complete poller that tracks the
since timestamp and ETag between runs, and only
processes tables that actually changed. Requires the
requests package.poll_changes.py