Log In

How to design an API client around rate limits

Every API enforces limits to keep load manageable. Clients that ignore those signals trigger 429 responses, waste retries, and can lose access. The practical approach is to read the headers the server sends, apply measured delays, limit concurrent work, and retry only when the response indicates a temporary condition. GitHub’s REST API documentation and the IETF draft on rate-limit headers both describe the same core fields that let clients stay within bounds without guessing. Understanding these signals helps clients maintain steady operation across repeated calls rather than reacting only after problems appear.

Read the rate-limit headers on every response

GitHub returns x-ratelimit-limit, x-ratelimit-remaining, x-ratelimit-used, and x-ratelimit-reset on every authenticated call. The remaining count drops with each request; when it reaches zero the client must wait until the reset time shown in UTC epoch seconds. Tracking these values after each response gives a running picture of available capacity and prevents unnecessary attempts once the quota is exhausted.

The IETF RateLimit header draft defines RateLimit and RateLimit-Policy fields that generalize the same information across providers. When both RateLimit and Retry-After appear, the Retry-After value takes precedence. Clients benefit from treating the headers as the authoritative source instead of maintaining separate internal counters that can drift from server state.

Key principle Read every response header before the next request. x-ratelimit-remaining and x-ratelimit-reset give the exact window; Retry-After overrides any local calculation when present.

Apply backoff instead of fixed delays

Fixed sleep intervals either waste time or still trigger secondary limits. Exponential backoff with jitter spreads retries and reduces the chance that many clients retry at the same moment. This approach lets the client adapt to varying server load without assuming a constant recovery interval.

GitHub guidance states that after a secondary rate limit the client should wait at least one minute, then increase the interval on continued failures. The IETF draft notes that servers may return Retry-After to indicate the exact wait required. Using the server-provided value when available avoids both under-waiting and over-waiting that can occur with purely local calculations.

Limit concurrency to avoid secondary limits

Secondary rate limits on GitHub block bursts of concurrent requests even when the primary hourly quota remains. The documentation recommends serial execution or a queue when many calls are needed. Running requests one after another or through a small pool keeps the request pattern predictable and lowers the risk of hitting additional throttling layers.

Making authenticated conditional requests with ETag or Last-Modified headers returns 304 when data is unchanged, preserving quota for actual changes. This technique reduces the total number of full responses required and stretches the available quota across a longer period of operation.

Retry only on clear transient signals

A 429 or 403 with a rate-limit message means the client exceeded a quota. GitHub instructs clients to stop sending requests until the time in x-ratelimit-reset or the Retry-After header. Continuing to retry while remaining is zero can lead to account-level blocks. Distinguishing rate-related responses from other errors prevents wasted effort and protects long-term access.

The troubleshooting section repeats the same rule: wait the indicated interval or at least one minute, then increase the delay on repeated failures. Logging the exact headers received during each throttled response creates a record that helps diagnose whether the client is consistently approaching limits or only encountering them during specific usage patterns.

Monitor and surface quota usage

Clients that expose current remaining quota and next reset time let operators adjust schedules before limits are hit. Regular review of logged headers reveals whether the client is approaching limits consistently or only during peak periods. Surface-level visibility turns rate-limit data into actionable information rather than an after-the-fact surprise.

Test the full retry path with a proxy that returns 429 responses after a fixed number of calls. Such controlled tests verify that backoff, header reading, and concurrency controls function together without requiring live service interaction for every validation run.

Sources

See our free AI tools →