How to Fix HubSpot API '429 Too Many Requests' and Rate Limit Errors
Fix HubSpot API 429 Too Many Requests and timeout errors. Learn how to handle TEN_SECONDLY_ROLLING limits, implement exponential backoff, and optimize API calls
- Identify if you are hitting the 10-second (burst) or daily rate limit by inspecting response headers.
- Implement exponential backoff and retry logic in your API client to handle 429 status codes gracefully.
- Optimize API calls by using batch endpoints and webhook subscriptions to drastically reduce overall request volume.
| Method | When to Use | Time | Risk |
|---|---|---|---|
| Exponential Backoff | Standard best practice for all API integrations | Medium | Low |
| Batch Processing | When updating or creating multiple records at once | Medium | Low |
| Upgrading HubSpot Tier | When daily limits are consistently exceeded legitimately | Low | High (Cost) |
| Caching Strategies | Read-heavy applications fetching standard CRM data | High | Medium (Stale data) |
Understanding HubSpot API Rate Limits
When integrating with HubSpot, developers frequently encounter the 429 Too Many Requests error. This status code indicates that your application has exceeded the number of API calls permitted within a specific timeframe. HubSpot enforces rate limits to ensure stability and fair usage across all accounts. Closely related are 504 Gateway Timeout or hubspot api timeout errors, which can occur if your connection drops while waiting for a bulk operation or if HubSpot's servers are overloaded by burst traffic.
HubSpot employs two primary types of rate limits:
- Secondly Limits (Burst): typically 100 or 150 requests per 10 seconds, depending on your authentication method (OAuth vs. Private App) and HubSpot subscription tier.
- Daily Limits: ranging from 250,000 to 1,000,000 requests per day, resetting at midnight Eastern Time (EST/EDT).
The error payload usually looks like this:
{
"status": "error",
"message": "You have reached your ten_secondly_rolling limit.",
"errorType": "RATE_LIMIT",
"correlationId": "1234abcd-5678-efgh-9012-ijklmnop3456",
"policyName": "TEN_SECONDLY_ROLLING"
}
Step 1: Diagnose the Root Cause
Before writing a fix, determine which limit you are hitting.
Inspect the HTTP response headers returned by HubSpot. HubSpot provides rate limit headers with every response:
X-HubSpot-RateLimit-Daily: Your daily limit.X-HubSpot-RateLimit-Daily-Remaining: The number of API calls remaining for the day.X-HubSpot-RateLimit-Secondly: Your 10-second burst limit.X-HubSpot-RateLimit-Secondly-Remaining: Remaining burst limit capacity.
If X-HubSpot-RateLimit-Secondly-Remaining drops to 0, your application is firing requests too rapidly. If X-HubSpot-RateLimit-Daily-Remaining hits 0, your overall integration volume is too high.
Additionally, check for hubspot api timeout (504/502 errors). These happen when you send massive payloads (like batch importing 10,000 contacts in a single heavily-associated request) that take too long for the server to process before the connection times out.
Step 2: Implement Exponential Backoff (The Standard Fix)
The most robust way to handle 429 Too Many Requests is by implementing an exponential backoff algorithm. When a 429 error occurs, your application should pause, wait for a short duration, and retry. If it fails again, the wait time increases exponentially.
Here is the logic flow:
- Make an API call.
- If response is
200 OK, continue. - If response is
429 Too Many Requests, prepare to pause. - Wait for $2^n$ seconds (plus some random jitter to avoid thundering herd problems) where $n$ is the retry attempt.
- Retry the request.
Step 3: Optimize with Batch Endpoints
If you are iterating through a list of contacts and making a separate API call for each (an N+1 problem), you will quickly burn through your 10-second limit.
Anti-Pattern (Causes 429s):
// DO NOT DO THIS
for (const contact of contactList) {
await hubspotClient.crm.contacts.basicApi.create(contact);
}
Best Practice (Batching): Use HubSpot's batch endpoints to send up to 100 records per single API call.
// DO THIS INSTEAD
const batchInput = { inputs: contactList };
await hubspotClient.crm.contacts.batchApi.create(batchInput);
Step 4: Caching and Webhooks
To drastically reduce read requests and prevent daily limit exhaustion:
- Caching: Cache frequently accessed, rarely changing data (like custom property definitions or owner IDs) in a local Redis instance or application memory.
- Webhooks: Instead of polling HubSpot every 5 minutes to see if a contact changed, set up Webhooks. HubSpot will push a payload to your endpoint only when an event actually occurs. This shifts the architecture from pull to push, nearly eliminating unnecessary API polling calls.
Frequently Asked Questions
import time
import random
import requests
from requests.exceptions import HTTPError
def hubspot_api_request_with_backoff(url, headers, data=None, max_retries=5):
retries = 0
backoff_factor = 2
while retries < max_retries:
try:
if data:
response = requests.post(url, headers=headers, json=data)
else:
response = requests.get(url, headers=headers)
response.raise_for_status()
return response.json()
except HTTPError as e:
if response.status_code == 429:
# Exponential backoff with jitter
wait_time = (backoff_factor ** retries) + random.uniform(0, 1)
print(f"Rate limit hit (429). Retrying in {wait_time:.2f} seconds...")
time.sleep(wait_time)
retries += 1
elif response.status_code in [502, 504]:
print("HubSpot API timeout. Reducing payload size or retrying...")
time.sleep(5)
retries += 1
else:
raise e
raise Exception("Max retries exceeded for HubSpot API call")
# Example Usage:
# headers = {"Authorization": "Bearer YOUR_PAT"}
# result = hubspot_api_request_with_backoff('https://api.hubapi.com/crm/v3/objects/contacts', headers)Error Medic Editorial
Error Medic Editorial is a team of veteran Site Reliability Engineers and DevOps practitioners dedicated to solving complex integration, infrastructure, and API challenges.