## TL;DR

When HubSpot returns a 429, never mark the lead as processed. Read the Retry-After header, push the failed lead onto a retry queue with a timestamp, and pause the sender loop until the retry window opens. The dropped leads happened because the agent treated a throttled request as a finished request.

```
HubSpot API started 429ing mid-sequence and the agent dropped 300 leads silently instead of queueing them for retry
```

## Steps

1. Stop the sender loop the moment you see a 429 status code. Do not continue iterating through the lead list. Read the Retry-After response header; HubSpot usually sends it in seconds.
   Expected: the loop halts instead of burning through remaining leads.

2. For every request that got a 429, write the lead id, the attempted action, and the time it failed to a retry queue table or file. Mark these leads as pending retry, not contacted.
   Expected: failed leads are recoverable later, none are marked sent.

3. Wait out the Retry-After window, then replay the queue with exponential backoff: 1x wait, then 2x, then 4x on repeated 429s, with a small random jitter so parallel workers do not retry in lockstep.
   Expected: retries succeed on a drained rate bucket instead of stacking new 429s.

4. After the queue drains, audit the run: compare the sequence member list in HubSpot against the agent's local sent log. Any lead on one list but not the other is a silent drop to investigate.
   Expected: the two lists match exactly.

5. Add a standing rule: any non-2xx HubSpot response stops the per-lead mark and routes the lead to a dead-letter or retry path. Silent success logging is banned.
   Expected: future throttles become visible retries, not silent drops.

## Use this when

- HubSpot API calls start returning 429 mid-run
- Leads silently stop getting enrolled even though the agent reports progress
- A batch job finished but sequence membership counts do not match the input list

## Not for this skill when

- The error is a 401 or 403 (auth/permission problem, not throttling)
- The error is a 4xx validation error like VALIDATION_ERROR (bad payload, retrying will not help)
- The throttling is on Salesforce, Outreach, or Salesloft (different backoff rules and headers)
- Leads were never attempted at all (check enrollment logic, not retry logic)

## Variant phrasings

- "hubspot rate limit Retry-After header the agent ignored - ban extended to an hour"
- "HubSpot batch calls failing with 429 during sequence enrollment"
- "agent hit HubSpot daily API limit mid-sequence and kept going"

## Why it happens

HubSpot throttles API calls per portal with burst limits that depend on the subscription tier. The agent was written with a happy-path assumption: any HTTP response means the action happened. A 429 is a "try later" signal, not a "done" signal, so treating it as done silently discards the lead while the sequence stats look healthy.

## Edge cases

- HubSpot sometimes 429s without a Retry-After header. Default to a 60-second wait with backoff in that case.
- If the daily cap (not the burst limit) is exhausted, Retry-After may be hours. Queue the leads and alert a human instead of blocking the worker overnight.
- Parallel workers sharing one portal key share one rate bucket. Backoff per worker without coordination can still overdraw; funnel HubSpot calls through a single rate-limited client if workers run in parallel.
- A lead 429d, retried, then 404d on the retry (deleted between attempts). Log it as gone and move on rather than retrying forever.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_Kwnx_Zrj0vB-f0-OmZYhqQ
