Error Medic

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

Fix HubSpot API 429 Too Many Requests and 504 Gateway Timeouts by implementing exponential backoff, request batching, and optimizing CRM search payload sizes.

Last updated:
Last verified:
1,251 words
Key Takeaways
  • Burst limits (100-150 requests per 10 seconds) trigger TEN_SECOND_ROLLING_WINDOW_EXCEEDED 429 errors.
  • Daily limits (250,000 to 1,000,000 requests) trigger DAILY_LIMIT_EXCEEDED 429 errors and require an API Add-on or architectural changes.
  • 504 Gateway Timeouts occur during unoptimized CRM Search queries or massive association fetching.
  • Quick fix summary: Implement HTTP 429 retry logic using Exponential Backoff with Jitter, switch to Batch API endpoints, and reduce requested properties.
Fix Approaches Compared
MethodWhen to UseTimeRisk
Exponential BackoffHandling 429 Burst Limits2-4 HoursLow
Batch API EndpointsBulk creates/updates/reads1-2 DaysLow
Webhook MigrationReplacing polling architectures1-2 WeeksMedium
Payload OptimizationFixing 504 Gateway TimeoutsHoursLow

Understanding HubSpot API Rate Limits and Timeouts

When scaling integrations with the HubSpot API, engineers inevitably encounter two major bottlenecks: HTTP 429 (Too Many Requests) and HTTP 504 (Gateway Timeout). Because HubSpot acts as the central CRM for mission-critical operations, failing to handle these errors gracefully can lead to data desynchronization, missed lead routing, and broken reporting pipelines.

The Anatomy of a HubSpot 429 Error

HubSpot enforces two distinct tiers of rate limits depending on your authentication method (OAuth vs. Private App) and your account tier (Free, Starter, Professional, Enterprise, or API Add-on).

  1. The Burst Limit (10-Second Rolling Window): This is the most frequently hit limit. HubSpot restricts accounts to either 100 or 150 requests per 10 seconds. When you exceed this, you receive a 429 Too Many Requests response with the TEN_SECOND_ROLLING_WINDOW_EXCEEDED error category.
  2. The Daily Limit: Depending on your tier, you are allocated between 250,000 and 1,000,000 requests per day (resetting at midnight EST). Exceeding this triggers the DAILY_LIMIT_EXCEEDED category.

A typical 429 error payload looks like this:

{
  "status": "error",
  "message": "You have reached your ten second limit.",
  "errorType": "RATE_LIMIT",
  "correlationId": "a1b2c3d4-e5f6-7890-1234-56789abcdef0",
  "category": "TEN_SECOND_ROLLING_WINDOW_EXCEEDED"
}

Diagnosing API Limits Using Response Headers

Before implementing a fix, you must diagnose which limit you are hitting. HubSpot includes vital rate-limit headers in every API response:

  • X-HubSpot-RateLimit-Daily: Your total daily quota.
  • X-HubSpot-RateLimit-Daily-Remaining: The number of calls remaining for the day.
  • X-HubSpot-RateLimit-Remaining: The number of calls remaining in the current 10-second rolling window.
  • X-HubSpot-RateLimit-Max: The maximum calls allowed per 10-second window.

Monitor X-HubSpot-RateLimit-Remaining. If this number consistently approaches zero, you need to throttle your outbound requests.

Step 1: Implementing Exponential Backoff for Burst Limits

The industry standard for handling 429 burst limits is Exponential Backoff with Jitter. If a request fails with a 429, the application should sleep for a short duration and retry. If it fails again, the sleep duration doubles, and so on. Jitter (a randomized variance) is added to prevent "thundering herd" scenarios where multiple parallel threads wake up and retry at the exact same millisecond.

Do not simply sleep(10) blindly. A smart implementation checks the error category. If it is DAILY_LIMIT_EXCEEDED, retrying is useless until the next day. You must log a critical alert and halt the queue. If it is TEN_SECOND_ROLLING_WINDOW_EXCEEDED, a brief backoff (e.g., 1-3 seconds) is usually sufficient to clear the rolling window.

Step 2: Transitioning to the Batch API

If you are hitting rate limits while syncing databases or creating multiple records, you are likely using the single-object endpoints (e.g., POST /crm/v3/objects/contacts). This is an anti-pattern for bulk operations.

HubSpot offers Batch APIs (e.g., POST /crm/v3/objects/contacts/batch/create) that allow you to process up to 100 records in a single API call. By batching your requests, you reduce your API footprint by 99%, instantly resolving most 10-second and daily rate limit issues.

Step 3: Diagnosing and Fixing 504 Gateway Timeouts

Unlike 429s, a 504 Gateway Timeout indicates that HubSpot's servers took too long to process your request and forcefully terminated the connection. This almost never happens on simple reads by ID. It predominantly occurs on the CRM Search API (POST /crm/v3/objects/{objectType}/search) under the following conditions:

  1. Over-fetching Properties: Requesting hundreds of properties in the properties array forces HubSpot's database to join massive amounts of data.
  2. Complex Filter Groups: Using deeply nested AND/OR logic with wildcard CONTAINS_TOKEN operators on non-indexed fields.
  3. Deep Associations: Attempting to read objects and resolve complex associations across thousands of records simultaneously.
How to Fix HubSpot 504 Timeouts:
  • Reduce Payload Size: Only include the exact properties you need in your request body. Never use a wildcard or fetch properties "just in case."
  • Optimize Search Filters: Avoid CONTAINS_TOKEN or HAS_PROPERTY on massive datasets. Prefer exact match operators (EQ, IN) on standard, indexed properties like email or domain.
  • Paginate Properly: Use the limit parameter to fetch smaller chunks (e.g., 50 instead of 100) and rely on the after cursor for pagination.
  • Isolate Associations: If you need associations, do not append them to a massive search query. Run a lightweight search to get the Object IDs, then use the Batch Read API to fetch the specific properties and associations by ID.

Frequently Asked Questions

python
import requests
import time
import logging
import random

logging.basicConfig(level=logging.INFO)

def hubspot_request_with_retry(method, url, headers, data=None, max_retries=5):
    """
    Executes a HubSpot API request with exponential backoff and jitter
    to handle 429 TEN_SECOND_ROLLING_WINDOW_EXCEEDED limits.
    """
    base_delay = 1.0  # initial delay in seconds
    
    for attempt in range(max_retries):
        try:
            response = requests.request(method, url, headers=headers, json=data)
            
            # If successful or client error (not rate limit), return immediately
            if response.status_code != 429 and response.status_code != 504:
                response.raise_for_status()
                return response.json()
                
            if response.status_code == 429:
                error_data = response.json()
                category = error_data.get("category")
                
                if category == "DAILY_LIMIT_EXCEEDED":
                    logging.error("HubSpot Daily Limit Exceeded. Halting operations.")
                    raise Exception("DAILY_LIMIT_EXCEEDED")
                    
                logging.warning(f"429 Burst Limit Hit. Retrying attempt {attempt + 1}/{max_retries}")
            elif response.status_code == 504:
                logging.warning(f"504 Gateway Timeout. Retrying attempt {attempt + 1}/{max_retries}")
                
        except requests.exceptions.RequestException as e:
            logging.warning(f"Network error: {e}")
            
        # Calculate exponential backoff with jitter
        # attempt 0: ~1s, attempt 1: ~2s, attempt 2: ~4s, attempt 3: ~8s
        sleep_time = (base_delay * (2 ** attempt)) + random.uniform(0.1, 0.5)
        logging.info(f"Sleeping for {sleep_time:.2f} seconds before retry...")
        time.sleep(sleep_time)
        
    raise Exception("Max retries exceeded for HubSpot API request.")

# Usage example:
# headers = {"Authorization": "Bearer YOUR_PAT"}
# data = hubspot_request_with_retry("GET", "https://api.hubapi.com/crm/v3/objects/contacts", headers)
E

Error Medic Editorial

A collective of Senior Site Reliability Engineers and Integration Architects dedicated to untangling the modern SaaS ecosystem. We provide battle-tested code and production-ready architectures.

Sources

Related Guides