September 18, 2026 · Muhammad Rehan
Reading Retry-After-Ms Instead of Guessing at Backoff
- Systems Integration
- AI
- Engineering
Why a system re-engaging 50,000+ CRM contacts reads the Retry-After-Ms header on 429s instead of guessing with fixed exponential backoff.

The Easy Logistics Re-engagement system runs a daily job against a Pipedrive CRM holding 50,000+ contacts: find the ones who've gone quiet for 60-90 days, pull their real conversation history, and have GPT-4 draft a follow-up in that thread before sending it through Office 365. At that scale, a single run means tens of thousands of calls into two different third-party APIs, each with its own rate limiter, and neither one forgiving of a system that just fires requests as fast as it can.
Two rate limiters, no shared clock
Pipedrive and OpenAI don't throttle on the same schedule, and neither publishes a single safe number you can hardcode into a cron job and trust forever. Account usage shifts, limits get adjusted, and a job built to run unattended every day can't assume that whatever rate worked last week is still safe this week. Push either API hard enough and it answers the same way: a 429.
Fixed backoff is a guess dressed up as a strategy
The common fix is exponential backoff: wait a second, then two, then four, and so on until a retry succeeds. It works, but it's still a guess. Wait too little and the next call hits another 429. Wait too much and a daily job that has 50,000 contacts to get through burns time it didn't need to burn. Neither failure mode is visible until the job is already running at scale, and by then the fixed schedule is either too cautious or not cautious enough for what the API is actually willing to tolerate right now.
Ask the API instead of estimating
Both Pipedrive and OpenAI return a Retry-After-Ms header on their 429 responses — an explicit answer to the question a backoff formula is trying to guess at. The re-engagement system's retry logic reads that header and waits exactly that long, no formula involved. It's paired with batching: contacts are processed in controlled groups with a deliberate pause between batches, rather than firing every request in parallel and hoping the rate limiter can keep up. Together, the two techniques mean the job stays inside whatever headroom each API is actually giving it at that moment, instead of inside headroom the code assumed six months ago.
Why this matters for a job nobody watches
This job runs on a cron, unattended, against two independent rate limiters that neither of us controls. The value of reading Retry-After-Ms isn't cleverness — it's that the system adapts to whatever the API is telling it today, rather than to whatever a constant said when it was last tuned by hand. For integration work that has to survive without a human checking in every morning, that difference is the whole point.