The Grouparoo Blog

CRM System Rate Limiting Overview

Tagged in Engineering Sync 
By Brian Leonard on 2021-03-10

Rate limiting is the method by which an API limits the calls for its use. When creating a data sync implementation with an API, it's important to adapt the approach that the remote system takes.

Whether stated or not, all systems have a rate limit. Even if not addressed explicitly, there is still some finite number of parallel connections that a set of servers can handle. Instead of leaving it to chance, SaaS providers tend to understand their limitations and use technology at the edge to reject requests that exceed some limit. Sometimes, this limit is configurable depending on your pricing plan.

At Grouparoo, we have integrated with several CRM (customer relationship management) tools. These often take the form of systems for Sales or email automation tools for Marketing. This article presents an overview of the approaches that we have encountered.

Calls per time

The most common approach is limiting the caller to a certain of calls per a unit of time. These vary by service. Here are some examples:

ServiceLimitPer TimePer MinuteNotes
Salesforce100,000day69Many nuances around certain types of calls and options to buy more.
Hubspot10010 seconds600Also daily limit of 250,000
Braze250,000hour4,167Some endpoints have other limits
Iterable500second30,000500/second is for updating users. Others are much lower, for example getting information about a user by email is 3/second.
Marketo50,000day35There is also 100 calls per 20 second limit.
Pardot25,000day17You can buy a higher limit
Eloqua2,000day1.4They are heavily encouraging using their batch API.
Sailthru300second18,000Different APIs have different limits. Deleting users, for example, is 40/second.

The ones with lower limits tend to highly encourage batching.

Concurrent calls

In addition to (or instead of) calls per time, some services limit concurrent access. For example, Mailchimp allows you to have 10 threads talking to Mailchimp at any given time. In effect, this ends up being the same as a number of calls per second. It just happens to depend on how long the call takes.

ServiceIn Parallel


When you reach your API limit for a time period, many APIs respond with the 429 HTTP response code. This is defined as "Too Many Requests" in the spec.

The response content often looks something like this:

  "status": "error",
  "message": "You have reached your daily limit.",
  "errorType": "RATE_LIMIT",
  "correlationId": "c033cdaa-2c40-4a64-ae48-b4cec88dad24",
  "policyName": "DAILY",
  "requestId": "3d3e35b7-0dae-4b9f-a6e3-9c230cbcf8dd"

The APIs that do this well give plenty of information about how a caller is progressing towards their rate limit. The most common approach is returning rate limit information in the headers of each response.

For example, here are the Intercom headers:

X-RateLimit-Limit:  Maximum number of requests allowed for the app.
X-RateLimit-Remaining:  Number of requests left in the current time.
X-RateLimit-Reset:  Time when the number of requests will be reset to the maximum limit. Shown as UNIX timestamp.

Handling rate limits

When writing code to sync data to these CRM systems, you will have to catch errors and handle the rate limit response. Ideally, you would use the headers to try again at the appropriate time.

For example, here is the Node.js / Typescript code that handles the above Intercom headers.

export const exportProfile = async (args) => {
  try {
    return sendProfile(args);
  } catch (error) {
    if (error.statusCode === 429) {
      const headers = error.headers || {};
      const now = Math.ceil(new Date().getTime() / 1000.0);
      const resetEpoch = headers["x-ratelimit-reset"] || 0;
      let retryIn = now - resetEpoch;
      if (retryIn <= 0) {
        retryIn = 60;

      // add some random time to that to spread it out
      retryIn += Math.floor(Math.random() * 30) + 1;
      return { error, success: false, retryDelay: 1000 * retryIn };

    throw error;

Because the Intercom API is per minute, this code tries to use the header but defaults to trying again a minute later. It also takes the approach of adding a bit of random time on top of that. We have seen that if all the requests were to use the exact time, it would likely trigger the rate limiting again. This code spreads it out.

In this case, the Grouparoo platform knows how to handle the retryDelay to re-run the code after the given delay.

Grouparoo also knows how to handle the currency limits. A Grouparoo app can set its parallelism to limit how many background workers are being processed at a given time. For example, Mailchimp is set to never go over 10 concurrent workers.

A Dam holding back the water

Get Started with Grouparoo

Start syncing your data with Grouparoo Cloud

Start Free Trial

Or download and try our open source Community edition.