## TL;DR

HubSpot rate-limits by rolling windows, so a fast batch loop trips 429 even under the daily cap. Read the Retry-After header, sleep, and retry the same batch; then slow the loop with smaller batches and spacing. Never drop the batch on a 429; the data is not written.

## Error

```text
{
  "status": "error",
  "message": "You have reached your daily limit",
  "errorType": "RATE_LIMIT"
}
```

## Steps

1. On a 429, read the Retry-After response header and sleep that many seconds plus a small buffer. Expected: the retry succeeds instead of hammering the limit.
2. Cut the batch size in half (for example from 100 to 50) and add a short sleep between batches. Expected: the loop stays under the rolling window.
3. Track usage via the X-HubSpot-RateLimit headers returned on every response. Expected: you see remaining quota before you hit zero.
4. For large backfills, spread the work across the day or across multiple days rather than one burst. Expected: no 429s and no daily-limit lockout.
5. Make the retry loop idempotent: re-sending the same batch update must be safe. Expected: a retried batch never creates duplicates or double-writes.

## When to use

- HubSpot API returns 429 during batch contact updates.
- An agent enrichment run dies halfway with rate limit errors.
- Daily backfills that used to finish now stall.

## When not to use

- Salesforce REQUEST_LIMIT_EXCEEDED (different limits, different headers).
- 403 insufficient permissions (scopes, not rate).
- A single request 429ing (check for a loop, not a limit).

## Tool compatibility

- HubSpot CRM API v3 batch endpoints; private apps.
- Any HTTP client that can read response headers.

## Variant phrasings

### You have exceeded the rate limit

The rolling-window form; slow down and retry with backoff.

### daily limit reached on private app

The daily cap form; the only fix is waiting or spreading load.

## Why it happens

HubSpot enforces both per-second and daily limits. Batch endpoints let you send a lot quickly, which is exactly how agents trip the per-second window while barely denting the daily allowance.

## Edge cases

- Retry-After is in seconds; some clients misread it as milliseconds and retry far too early.
- Different endpoints share one quota pool; a search-heavy agent can starve its own write loop.
- 429s during OAuth token refresh need the same backoff; do not spin on refresh.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_bDDXSlO38IbN1AZZ86Urdw
