Working inside HubSpot API rate limits when a registration file lands
HubSpot enforces two ceilings on private apps: a burst limit of 190 requests per ten seconds on Professional and Enterprise, 100 on Free and Starter, and a daily limit of one million calls on Enterprise. A 30,000 contact upload sent one record at a time takes about 26 minutes, or 16 seconds through the batch endpoint.
The show closes on Thursday. On Friday morning somebody exports 30,000 registrations and asks for them in HubSpot by lunchtime so the follow-up sequence can go out while the show is still in people's heads.
The integration exists. It has been running nightly all season, pushing a few hundred records at a time, and nobody has thought about it in months. Today it will be asked to do a hundred times its usual work in one pass, and whether that takes sixteen seconds or fifty minutes depends entirely on decisions made when it was written. HubSpot API rate limits are published in enough detail to work this out on paper, which is a better place to work it out than at 11:30 on the Friday.
What the two ceilings do differently
HubSpot (2026) documents a burst limit and a daily limit, and they fail in different ways.
For privately distributed apps the burst limit is "100 / app" per ten seconds on Free and Starter and "190 / app" per ten seconds on Professional and Enterprise. The daily limit is "250,000 / account" on Free and Starter, "625,000 / account" on Professional and "1,000,000 / account" on Enterprise. HubSpot is explicit that the burst limit applies individually per app while the daily limit is shared across every private app in the account.
That asymmetry is the design detail to internalise. Adding a second private app buys you a second burst allowance and buys you nothing daily. So an organisation running one app for the registration sync, one for the event app and one for a finance export has three independent ten second budgets drawing on one shared daily pot, and the pot is what runs out during show week.
The API limit increase add-on raises the burst ceiling to "250 / app" and adds "1,000,000 / account on top of your base subscription", and it can be bought up to twice per account. Worth knowing before somebody proposes a re-architecture that a purchase order would have solved.
How long does a 30,000 contact upload take?
Do it the obvious way first. One API call per contact, 30,000 contacts, on an Enterprise private app at 190 requests per ten seconds.
Thirty thousand divided by 190 is 157.9 ten second windows. Multiply by ten and you get 1,579 seconds, which is 26.3 minutes of continuous running at the absolute ceiling with zero margin and no other app touching the account.
Run the same file on Free or Starter at 100 per ten seconds and it is 300 windows, 3,000 seconds, 50 minutes. Run it from a public marketplace app at 110 per ten seconds and it is 272.7 windows, 2,727 seconds, about 45.5 minutes.
Against the daily ceiling, 30,000 calls is 3 per cent of the Enterprise million and 12 per cent of the Free and Starter 250,000. That looks survivable until you notice the job is scheduled hourly. Twenty-four runs of 30,000 calls is 720,000 requests, which is 72 per cent of Enterprise and 288 per cent of Free and Starter, and the second of those accounts stops working some time in the early afternoon.
The batch endpoint changes the arithmetic
HubSpot's CRM batch operations accept up to 100 records per request. That single fact is worth more than any amount of retry tuning.
Thirty thousand contacts at 100 per request is 300 requests. At 190 requests per ten seconds, 300 requests is 1.58 windows, so the upload finishes in about 16 seconds. The same job that took 26.3 minutes record by record takes a quarter of a minute, and it consumes 300 of the daily million rather than 30,000, which is 0.03 per cent instead of 3 per cent.
Run that hourly and it is 7,200 calls a day. On Free and Starter, where the record-by-record version was 288 per cent of the allowance, the batch version is 2.9 per cent.
Two caveats stop this being free. Batch responses report per-record outcomes inside a single HTTP response, so error handling has to read the body rather than the status code, and an integration written to catch exceptions will silently drop failures. And a batch of 100 that contains one malformed record behaves differently from 100 individual calls where one fails, so somebody has to decide whether a partial batch is acceptable. Both are half a day of work and both are worth it.
Which limit applies to your app?
Check the distribution setting rather than assuming, because the answer changes the design and it is not always the one people expect.
An app built for your own organisation and never listed is privately distributed, so it gets the per-app burst allowance for your subscription tier and shares the account daily pot. An app listed on the marketplace is publicly distributed, so every account that installs it is held to 110 requests every ten seconds, and HubSpot notes that "The API limit increase add-on does not increase the limits" for those apps.
The trap is the integration that starts private and is later listed, because the burst ceiling drops from 190 or 250 to 110 and no code changed. If there is any chance the thing you are building becomes a product, design it against 110 from the beginning and you will never have that conversation.
The same question is worth asking of every marketing platform in the stack, since each one draws its own line between what a private integration may do and what a distributed one may. The Marketo side of that has a different shape again, covered in the questions to settle before that integration goes live.
Reading a 429 instead of retrying blind
When you exceed a rate limit you get an HTTP 429, and the status code has a formal definition worth knowing.
Nottingham and Fielding specified it in RFC 6585 in April 2012: "The 429 status code indicates that the user has sent too many requests in a given amount of time ('rate limiting')", and the response "MAY include a Retry-After header indicating how long to wait before making a new request" (Nottingham and Fielding, 2012).
Two consequences for an events integration. First, a 429 carries information and most client code throws it away, so log the response body and any Retry-After value before you retry. Second, the specification makes the header optional, so a client that only knows how to wait for Retry-After will spin when the header is absent. Write the client to prefer the header and to fall back to a computed delay.
The wider question of which vendor errors mean retry, which mean fix the payload, and which mean stop the run entirely is a discipline in itself, and it is covered in reading API error responses and deciding what to retry.
The daily ceiling is the one that ends a show week
Burst limits produce a slow job. Daily limits produce a dead one, and the difference in consequence is large.
A burst limit reached at 11:30 means the upload finishes at 11:46 instead of 11:32. Somebody is mildly annoyed. A daily limit reached at 15:00 on the Wednesday of show week means every private app in the account stops until midnight, including the one that writes badge scans, the one that syncs the mobile app and the one finance is using. The blast radius is the account rather than the job.
Two habits keep you clear of it. Track daily consumption per app, because the shared pot means you cannot diagnose the problem without knowing which app spent it. And put a floor under it: have each job check remaining daily allowance before starting a large run and defer rather than half-complete, since a load that stops at record 18,000 of 30,000 is worse than one that never started.
Salesforce solves the same problem with a completely different shape, allocating a 24 hour bucket sized by licence count rather than a per-ten-second burst, and sizing a sync against that model needs different arithmetic.
Where this stops
Rate limit arithmetic tells you whether a job fits. It says nothing about whether the job should run at all, and that is where the more expensive mistakes live.
Pushing 30,000 post-show registrations into a marketing platform is a data protection decision before it is an engineering one. Consent captured on a registration form for one show is not automatically consent to receive marketing about the portfolio, and the batch endpoint will happily insert every row you hand it. The rate limit is not the thing that should be slowing you down here.
The second limit is that speed at the API boundary does not mean speed inside the platform. A batch of 100 contacts accepted in 200 milliseconds can trigger workflow enrolments, list recalculations and property rollups that take considerably longer, and a 30,000 record load landing in 16 seconds can leave the portal churning for an hour afterwards. If your follow-up sequence depends on list membership, test the whole path with a realistic volume rather than timing the upload and calling it done.
Start this week by counting calls per record. Take your current registration integration, run it against fifty records, and count the HTTP requests it makes. If the answer is fifty or more, the batch endpoint will cut your run time by roughly ninety-nine per cent for a day of work, and you can do that before the next show rather than during it. The rest of what an integration owes the systems around it sits with this cluster.
Questions people ask about hubspot api rate limits
- What are the HubSpot API rate limits for a private app?
- Privately distributed apps get 100 requests per ten seconds each on Free and Starter and 190 per ten seconds each on Professional and Enterprise. Daily limits are shared across every private app in the account: 250,000 calls on Free and Starter, 625,000 on Professional and 1,000,000 on Enterprise.
- Do public marketplace apps get the same limits?
- Publicly distributed OAuth apps are held to 110 requests every ten seconds per installed account, and HubSpot states that the API limit increase add-on does not raise them. An integration you plan to list on the marketplace therefore has to be designed against a tighter ceiling than one built privately for a single account.
- How many records can one HubSpot batch request carry?
- Batch operations on CRM objects are limited to 100 records per request. Sending 30,000 contacts through the batch endpoint therefore costs 300 requests instead of 30,000, which turns a run measured in tens of minutes into one measured in seconds and consumes a fraction of the daily allowance.
Related reading
- Sizing an event data sync against Salesforce API limits
- Questions to settle before a Marketo event integration goes live