Error Medic

Fixing HubSpot API 429 Too Many Requests and Timeout Errors

Resolve HubSpot API rate limits (429 Too Many Requests) and timeouts. Learn how to implement exponential backoff, optimize queries, and use bulk endpoints.

Last updated:
Last verified:
1,350 words
Key Takeaways
  • HubSpot enforces burst limits (typically 100-150 requests per 10 seconds) and daily limits based on your subscription tier, returning HTTP 429 Too Many Requests when exceeded.
  • API timeouts (HTTP 504 Gateway Timeout or client-side ReadTimeout) often occur when requesting too many properties, performing complex CRM Search queries, or neglecting pagination.
  • The most effective fixes are implementing exponential backoff with jitter, switching to Batch/Bulk endpoints, and monitoring the X-HubSpot-RateLimit-Remaining header.
Fix Approaches Compared
MethodWhen to UseTimeRisk
Exponential BackoffWhen encountering intermittent 429 burst limit errors.15 minsLow - Standard API best practice
Migrate to Batch EndpointsWhen syncing large volumes of Contacts, Companies, or Deals.2-4 hoursMedium - Requires refactoring payload structures
Optimize Search QueriesWhen experiencing 504 Timeouts on CRM Search endpoints.30 minsLow - Only changes request body
Upgrade API Limit Add-onWhen consistently hitting the daily 250k/500k request limit.ImmediateNone - But increases monthly billing costs

Understanding the Error

When integrating with the HubSpot API, developers frequently encounter two major roadblocks that halt data synchronization: Rate Limits and Timeouts. Understanding the distinction and root causes of each is critical for building a resilient integration.

HubSpot API Rate Limits (HTTP 429)

HubSpot enforces strict rate limiting to ensure platform stability. When you exceed these limits, HubSpot returns an HTTP 429 Too Many Requests status code. You will typically see a JSON response body similar to this:

{
  "status": "error",
  "message": "You have reached your minutely limit.",
  "errorType": "RATE_LIMIT",
  "correlationId": "a1b2c3d4-e5f6-7890-abcd-1234567890ab",
  "policyName": "SECONDLY:PRIVATE_APP"
}

There are two primary types of rate limits in HubSpot:

  1. Burst Limits (Secondly/Minutely): Depending on your authentication method (Private App vs. OAuth) and tier, this is usually 100 or 150 requests per 10 seconds. This is the most common limit developers hit when running parallel background jobs or loops.
  2. Daily Limits: The total number of requests allowed in a 24-hour period, resetting at midnight UTC. This ranges from 250,000 to 500,000+ depending on your HubSpot subscription (Professional vs. Enterprise) and purchased add-ons.

HubSpot API Timeouts (HTTP 504 / Client ReadTimeout)

Timeouts occur when the HubSpot server takes too long to process your request, or your client drops the connection before HubSpot can respond. This manifests as an HTTP 504 Gateway Timeout or a language-specific exception like Python's requests.exceptions.ReadTimeout.

Timeouts are usually caused by:

  • Requesting too many associations or properties in a single call.
  • Unoptimized CRM Search API filters.
  • Pulling maximum limit pages (e.g., limit=100) on complex objects without filtering.

Step 1: Diagnose the Root Cause

Before refactoring your code, you need to identify exactly which limit you are hitting or why the timeout is occurring.

Inspecting Rate Limit Headers

HubSpot includes specific HTTP headers in successful responses that tell you your current standing against the daily limit. Inspect your response headers for:

  • X-HubSpot-RateLimit-Daily: Your total daily allowance.
  • X-HubSpot-RateLimit-Daily-Remaining: How many requests you have left today.

Note: Burst limits (10-second intervals) do not have remaining headers and must be handled reactively when a 429 occurs.

Analyzing Timeouts

If you are experiencing timeouts, log the exact endpoint and payload. If you are hitting POST /crm/v3/objects/contacts/search, check your filter groups. Are you doing partial text matches (CONTAINS_TOKEN) on large datasets? Are you requesting 50+ custom properties in the properties array? These drastically increase query execution time on HubSpot's backend.

Step 2: Implement Fixes

Fix 1: Implement Exponential Backoff with Jitter

The most robust way to handle 429 Burst Limits is to implement an exponential backoff strategy. When your client receives a 429, it should pause for a short duration, then retry. If it fails again, the pause duration increases exponentially. Adding 'jitter' (randomness) prevents the 'thundering herd' problem if multiple threads are retrying simultaneously.

Instead of writing custom sleep logic, utilize robust libraries native to your language. For Python, the urllib3 Retry utility combined with requests is the standard approach (see the Code Block section for implementation).

Fix 2: Migrate to Batch / Bulk Endpoints

If you are syncing 1,000 contacts by making 1,000 separate POST /crm/v3/objects/contacts calls, you will instantly hit the 100 requests / 10 seconds burst limit.

HubSpot provides Batch endpoints for read, create, update, and archive operations. You can process up to 100 objects in a single API call.

Change this (Single Object): POST /crm/v3/objects/contacts

To this (Batch Object): POST /crm/v3/objects/contacts/batch/create

By batching in groups of 100, you reduce your API footprint by 99%, entirely avoiding burst limits and significantly reducing sync times.

Fix 3: Optimize Search and Read Queries

To resolve timeouts, you must reduce the workload on HubSpot's servers:

  1. Reduce Payload Size: Only request the exact properties you need using the properties array. Do not request associations unless strictly necessary.
  2. Lower Pagination Limits: If limit=100 times out, drop it to limit=50 or limit=25.
  3. Optimize Filters: Avoid leading wildcard searches. Whenever possible, filter by indexed properties or exact matches (EQ instead of CONTAINS_TOKEN).

Fix 4: Connection Pooling

If you are creating a new HTTP connection for every single request, the TCP handshake and TLS negotiation overhead can contribute to client-side timeouts. Ensure your HTTP client is utilizing Connection Pooling (e.g., using requests.Session() in Python) to reuse underlying TCP connections.

Frequently Asked Questions

python
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

def get_hubspot_session():
    """
    Creates a requests Session with built-in exponential backoff retries
    for handling HubSpot 429 Rate Limits and 50X Server Errors.
    """
    session = requests.Session()
    
    # Configure the retry strategy
    # backoff_factor=1 means sleep times will be: 1s, 2s, 4s, 8s, 16s
    retry_strategy = Retry(
        total=5,  # Maximum number of retries
        status_forcelist=[429, 500, 502, 503, 504],  # HTTP status codes to retry on
        allowed_methods=["HEAD", "GET", "OPTIONS", "POST", "PUT", "PATCH", "DELETE"],
        backoff_factor=1,
        respect_retry_after_header=True  # Respect Retry-After header if HubSpot provides it
    )
    
    # Mount the adapter to both HTTP and HTTPS
    adapter = HTTPAdapter(max_retries=retry_strategy)
    session.mount("https://", adapter)
    session.mount("http://", adapter)
    
    # Set default headers (e.g., Bearer token)
    # session.headers.update({"Authorization": "Bearer YOUR_HUBSPOT_TOKEN"})
    
    return session

# Example Usage:
# http = get_hubspot_session()
# response = http.get("https://api.hubapi.com/crm/v3/objects/contacts")
# response.raise_for_status()
E

Error Medic Editorial

Error Medic Editorial is a team of Senior Site Reliability Engineers and DevOps practitioners dedicated to solving complex infrastructure and API integration challenges. With decades of combined experience, we provide actionable, code-first solutions for modern engineering teams.

Sources

Related Guides