HTTP 429 Too Many Requests and are not queued. Your integration must implement the client-side handling described below.
The limit applies to concurrent locations, not request rate. There is no cap on how many requests you may send to a single location, how quickly you may page through it, or how many locations you may sync in total.
Limits
Limits apply to every endpoint under
/api/v1/vendors/locations/{location_id}/. The locations list, the organizations endpoint, and the token endpoint are not limited.
- The unit is the location, not the request. A location occupies one slot while it has any request executing. Any number of concurrent requests for the same location share that slot.
- Slots free immediately. A location’s slot is released the instant its last in-flight request finishes — success or error. There are no fixed windows and no idle timers.
- The two pools are independent. Incremental polling never blocks initial syncs, and the same location may hold one slot in each pool at the same time.
- Budgets are per credential. Limits are counted per API credential across all your processes and servers combined. Other vendors’ traffic never affects yours.
- Rejected requests cost you nothing. A
429request is not executed, occupies no slot, and is not recorded against you. Nothing was read and no partial response was produced, so retrying is always safe. - Sequential clients are never limited. If you sync one location at a time, you cannot reach these limits.
Throttled Response Contract
When a limit is exceeded, the API responds as follows:Required Client Behavior
- MUST limit concurrent locations to 5 per sync mode. Initial and incremental are counted separately, so you may run up to 5 of each.
- MUST treat
HTTP 429as a retryable condition and wait at leastretry_after_seconds(or theRetry-Afterheader) before retrying. - MUST NOT retry in a tight loop without a delay.
- MUST cache the access token and reuse it. Tokens are valid for 6 hours; request a new one only when the current token expires.
- SHOULD detect this limit by checking the response body for
max_concurrent_locationsrather than assuming every429is a concurrency rejection. - SHOULD read the limit from
max_concurrent_locationsrather than hardcoding5, so a future change on our side requires no change on yours. - SHOULD parallelize freely within a location. Fetching one location’s patients, appointments, and treatments simultaneously consumes a single slot and is the most efficient way to sync.
- SHOULD set
itemsexplicitly when paging. Cursor pagination defaults to 10 records per page and accepts up to 5000; leaving it at the default makes large pulls far slower than necessary. - SHOULD add random jitter to retry delays if you run many workers, so they do not retry in lockstep.
- SHOULD use
q[fetch_modified_since]for routine polling. It returns only records withupdated_at >=your timestamp and routes the request to the incremental pool, so polling never competes with initial syncs.
429 regularly, your effective location fan-out is above 5. Correct the fan-out rather than relying on retries.
Reference Implementation
Minimal retry handling (Python; the same pattern applies in any language):Verifying Your Integration
The limit triggers as documented. Start pulls for 6 distinct locations simultaneously in the same pool. Requests for the first 5 locations succeed; requests for the 6th return429 with max_concurrent_locations in the body. Once one of the active locations finishes, the 6th is admitted on retry.
Same-location parallelism is unrestricted. Fire several endpoints for one location at once. None are rejected — they share a single slot.
The pools are independent. With 5 locations already active in the initial pool, a request carrying q[fetch_modified_since] for a 6th location still succeeds, because it draws on the incremental pool.
Normal operation is clean. Run your usual sync with fan-out capped at 5 per mode and confirm you see no 429 responses at all. A correctly capped client should never trigger this limit in steady state.
