Error Medic

Resolving HubSpot API Rate Limit (429 Too Many Requests) & Timeout Errors

Fix HubSpot API rate limit (429) and timeout errors by implementing exponential backoff, request batching, and optimizing API call concurrency. Step-by-step gui

Last updated:
Last verified:
1,292 words
Key Takeaways
  • HubSpot imposes strict rate limits: typically 100 requests per 10 seconds for standard accounts and 150 for API add-ons.
  • Daily limits exist alongside burst limits; exceeding 500,000 requests/day (or higher with add-ons) requires architectural changes.
  • Timeouts (504 Gateway Timeout or client-side) often occur when batching too many complex objects or hitting endpoint-specific bottlenecks.
  • Quick fix: Implement exponential backoff with jitter and utilize HubSpot's batch APIs to consolidate requests.
Rate Limit & Timeout Mitigation Strategies
MethodWhen to UseImplementation TimeRisk of Data Loss
Exponential BackoffAlways. Required for robust API integrations.Low (1-2 hours)Low
Request BatchingWhen syncing multiple contacts, companies, or deals at once.Medium (1-2 days)Low
Webhook SubscriptionsWhen polling for changes (e.g., pulling updated contacts every minute).High (1 week)Medium (requires reliable endpoint)
Concurrency ThrottlingWhen running parallel workers or serverless functions.MediumLow

Understanding the Error

When integrating with the HubSpot API, developers frequently encounter two related issues: Rate Limiting and Timeouts. Understanding the distinction and root causes is critical for building resilient integrations.

1. The 429 Too Many Requests Error

HubSpot enforces strict limits on how many API calls you can make within a specific timeframe. When you exceed this, the API responds with an HTTP 429 Too Many Requests status code. The response body usually looks like this:

{
  "status": "error",
  "message": "You have reached your minutely limit.",
  "errorType": "RATE_LIMIT",
  "correlationId": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
  "policyName": "MINUTELY"
}

HubSpot's Primary Limits:

  • Burst Limit (10-second limit): 100 requests per 10 seconds (150 with API add-on).
  • Daily Limit: 500,000 requests per day (up to 1,000,000 with add-ons).

2. The HubSpot API Timeout

Timeouts occur when your client closes the connection before HubSpot responds, or when HubSpot's gateway terminates a long-running request (often yielding a 504 Gateway Timeout or 502 Bad Gateway). This is distinct from a rate limit but often caused by similar architectural flaws, such as attempting to process massive payloads in a single synchronous call, or querying non-indexed properties.


Step 1: Diagnose the Bottleneck

Before writing code, identify exactly which limit you are hitting.

A. Inspect Response Headers HubSpot returns rate limit context in the HTTP response headers of every successful (and 429) API call:

  • X-HubSpot-RateLimit-Daily: Your total daily quota.
  • X-HubSpot-RateLimit-Daily-Remaining: How many daily calls you have left.
  • X-HubSpot-RateLimit-Max: Your burst limit (per 10 seconds).
  • X-HubSpot-RateLimit-Remaining: How many burst calls you have left in the current 10-second window.

B. Review the API Dashboard Navigate to your HubSpot App settings or the API usage dashboard in your portal to see visual spikes in errors and overall volume.


Step 2: Implement Exponential Backoff

The most critical fix for a 429 error is an exponential backoff retry mechanism. When a 429 is received, your application must pause before retrying, increasing the pause duration with each subsequent failure.

Why Jitter Matters: If you have 50 parallel workers that all hit a rate limit simultaneously, a standard 5-second backoff means all 50 workers will retry at exactly the same moment 5 seconds later, instantly triggering another 429. Adding 'jitter' (randomness) staggers the retries.


Step 3: Utilize Batch Operations

If you are creating 100 contacts using the POST /crm/v3/objects/contacts endpoint, that consumes 100 API calls. By switching to the batch endpoint POST /crm/v3/objects/contacts/batch/create, you can create up to 100 contacts in a single API call.

This immediately reduces your burst API consumption by 99%.

Common Batch Endpoints:

  • /crm/v3/objects/contacts/batch/create
  • /crm/v3/objects/contacts/batch/update
  • /crm/v3/objects/contacts/batch/read (For fetching multiple records by ID)

Step 4: Resolve HubSpot API Timeouts

If you are experiencing timeouts rather than rate limits, the strategy shifts to optimizing the workload of individual requests.

  1. Reduce Batch Sizes: If you are batching 100 complex objects with dozens of associations, HubSpot's backend might struggle to process it within the timeout window (typically 10-30 seconds). Reduce your batch size from 100 to 50, or even 25.
  2. Filter Complexity: When using the Search API (POST /crm/v3/objects/contacts/search), avoid complex CONTAINS or HAS_PROPERTY filters on custom properties that aren't indexed. Stick to exact matches (EQ) on standard identifiers whenever possible.
  3. Increase Client Timeout: Ensure your HTTP client isn't giving up too early. Set your client timeout to at least 30 seconds for HubSpot API calls.

Step 5: Architecture Review (Polling vs. Webhooks)

If you are hitting your daily limit of 500,000 requests, you have an architectural problem. Often, this is caused by aggressive polling (e.g., asking HubSpot "Are there any new contacts?" every second).

The Fix: Switch to Webhooks. Configure a HubSpot App to subscribe to contact.creation or contact.propertyChange events. HubSpot will push the data to your server when an event occurs, completely eliminating the need for polling API calls.

Frequently Asked Questions

python
import time
import random
import requests
from requests.exceptions import RequestException

def hubspot_api_call_with_retry(url, headers, payload, max_retries=5):
    """
    Executes a HubSpot API call with exponential backoff and jitter.
    Handles 429 Too Many Requests and 502/504 Timeouts.
    """
    base_delay = 1.0  # Initial delay in seconds
    
    for attempt in range(max_retries):
        try:
            response = requests.post(url, headers=headers, json=payload, timeout=30)
            
            # Success
            if response.status_code in (200, 201, 202):
                return response.json()
                
            # Rate Limit Hit
            elif response.status_code == 429:
                # HubSpot sometimes provides a Retry-After header
                retry_after = int(response.headers.get('Retry-After', 0))
                
                if retry_after > 0:
                    sleep_time = retry_after
                else:
                    # Exponential backoff: 1s, 2s, 4s, 8s...
                    sleep_time = base_delay * (2 ** attempt)
                    # Add jitter (0 to 1 second) to prevent thundering herd
                    sleep_time += random.uniform(0, 1)
                
                print(f"[429 Rate Limit] Retrying in {sleep_time:.2f}s (Attempt {attempt + 1}/{max_retries})")
                time.sleep(sleep_time)
                continue
                
            # Gateway Timeouts
            elif response.status_code in (502, 503, 504):
                 sleep_time = base_delay * (2 ** attempt) + random.uniform(0, 1)
                 print(f"[{response.status_code} Timeout] Retrying in {sleep_time:.2f}s (Attempt {attempt + 1}/{max_retries})")
                 time.sleep(sleep_time)
                 continue
                 
            # Other errors (400, 401, etc.) should not be retried blindly
            else:
                response.raise_for_status()
                
        except requests.exceptions.Timeout:
             sleep_time = base_delay * (2 ** attempt) + random.uniform(0, 1)
             print(f"[Client Timeout] Retrying in {sleep_time:.2f}s (Attempt {attempt + 1}/{max_retries})")
             time.sleep(sleep_time)
             continue
             
        except RequestException as e:
            print(f"Request failed: {e}")
            raise
            
    raise Exception("Max retries exceeded for HubSpot API call.")

# Example usage for batch creation
# headers = {"Authorization": "Bearer YOUR_TOKEN", "Content-Type": "application/json"}
# payload = {"inputs": [{"properties": {"email": "test1@example.com"}}, {"properties": {"email": "test2@example.com"}}]}
# result = hubspot_api_call_with_retry("https://api.hubapi.com/crm/v3/objects/contacts/batch/create", headers, payload)
E

Error Medic Editorial

Error Medic Editorial comprises senior SREs, DevOps engineers, and cloud architects dedicated to documenting robust solutions for enterprise API integrations and infrastructure reliability.

Sources

Related Articles in Hubspot Api

Explore More API Errors Guides