Skip to content
Beta

Reference Rate limits

Rate limits

How much a key can read per minute and per day, what counts toward each limit, how to retry after a 429, and how long an initial sync takes.

Each key has two limits, shared by every team it reads: a rate limit on how fast it reads, and a daily quota on how much. Both count items, not requests. An item is one object in a response: a feed page of 100 changes is 100 items, removals included.

Two limits per key

Which requests count toward which limit:

RequestsRate limitDaily quota
The changes feed, every list, a lead's activities, GET /v1/teams, GET /v1/members and GET /v1/booking_servicesYesYes
A request for one record, such as GET /v1/leads/{id}, and also POST /v1/leads/search and GET /v1/meYesNo
GET /v1/healthNoNo

Each endpoint in the reference shows its row: Sync for the first, Read for the second.

Rate limit

A key reads up to 2,000 items a minute, with bursts of up to 10,000. Capacity you do not use builds back up at that pace until the burst is full again. Past the limit, the API answers 429 rate_limited, and Retry-After says how long until there is room for your request.

How a request counts:

  • Before it runs, a request reserves its limit. A list or feed request that sends no limit reserves 25; a request for one record reserves one.
  • Once it has run, it is charged for the items it returned, and at least one. A short page gives back the difference, but a request that returns nothing still costs one item: a search that finds no lead, an id that answers 404, or any other error it gets once it runs, quota_exceeded included.
  • A request refused before it runs is not charged, such as a failed authentication, a missing permission or, on a route that takes Totem-Team, a team the key cannot read or that is not ready yet. A request that names a record by its id, such as GET /v1/leads/{id} or a lead's activities, checks its team as it runs, so a refusal for that team costs one item.
  • A request for one record is charged for what it returns: GET /v1/leads/{id} returns a lead with its two facets, so it counts up to three items. A search counts each lead it returns, or one when it finds none.

Because a request reserves its full limit first, a smaller limit lets you keep reading when little capacity is left.

429 rate_limited can also mean that your IP address or your key is locked out after too many failed authentication attempts. Retry-After tells the two apart: a lockout always sends 600 seconds, the full length of the lock, while the rate limit asks for the few seconds your request needs. Slowing down does not end a lockout: find the process at that address that sends a missing, malformed, wrong or unknown key, fix it, then wait. Authentication explains what counts as a failed attempt.

Daily quota

Each UTC day, a key can read 250,000 items, or 3 times the number of records in its teams if that is more. Records of every kind count toward that number, removals included. Every item returned by the requests in the first row of the table counts toward the quota, whatever its kind.

The number of records is taken at the key's first request of each UTC day, so a team added to the key later that day may raise the quota only from the next day. Plan the initial sync of a large team for when its quota allows it.

The quota leaves room for an initial sync of every team and a day of polling. Re-reading whole lists again and again is what spends it.

Past the quota, those requests answer 429 quota_exceeded until 00:00 UTC, when the quota resets. Retry-After counts the seconds until then. Requests for one record, search and GET /v1/me keep working.

Retry after a 429

Retry-After comes with every 429 the API itself returns, and it is always a whole number of seconds. Wait at least that long, then send the same request again, with the same cursor. Nothing is lost while you wait: the feed keeps every change for you.

  • After rate_limited, the wait is usually a few seconds, or 600 seconds after an authentication lockout.
  • After quota_exceeded, the wait runs until 00:00 UTC and can last hours. Do not keep a process asleep that long: end the run, and schedule the next one for that time. The reference client does this with its retry_later outcome.

A 429 from the firewall in front of the API has no Retry-After and no JSON error body: back off exponentially. A 5xx carries no Retry-After either: retry it with exponential backoff too.

Initial sync estimates

The table gives the minimum time the rate limit adds to an initial sync at the limits on this page, for one key with no other traffic; during the Beta it is approximate, as the note at the top of this page explains. It counts records of every kind, one item each: a lead with its attribution, its response and three activities is six records. Network time, and the time Totem needs to prepare a team just added to a key, come on top. A copy that fits within the burst shows Under 1 minute: the rate limit adds nothing to it, but it still takes the time of its requests.

Minimum duration of an initial sync, set by the feed's rate limit alone: the first 10,000 records at once, then 2,000 records per minute. A real sync takes longer.
Records (all kinds)Minimum time
1,000Under 1 minute
10,000Under 1 minute
50,00020 min
100,00045 min
250,0002 h

Good practice

  • Run one sync process per key and team. Several workers on one key share the same limits, so they only make each other wait.
  • Ask for full pages of 100 items during an initial sync.
  • Poll the changes feed every 1 to 5 minutes. A poll that finds nothing new costs one item of the rate limit and nothing of the daily quota.
  • Read members and bookable services when you start a team, when you meet an id you do not know, and once a day: not on every run, and not again for an id the last read did not resolve.
  • Never create more integrations or keys to get around the limits. If they are too low for what you need, tell us.

API version 1.0a