AI & Agents

GitHub API Rate Limit Guide: Best Practices for AI Agents

GitHub API rate limits restrict the number of requests an application or user can make within a specific timeframe to protect service availability and prevent abuse. For developers building autonomous AI agents, handling these limits requires proper implementation of rate monitoring headers, conditional requests, webhooks, and client-side queueing. This guide explains how to avoid 429 Too Many Requests errors and configure resilient agent environments.

Fast.io Editorial Team 12 min read
GitHub API rate limits dictate how AI agents query repositories and manage developer resources.

How GitHub API Rate Limit Quotas are Structured

GitHub limits unauthenticated REST API requests to 60 per hour, while authenticated requests receive a ceiling of 5,000 per hour [GitHub REST API Documentation]. For recursive AI agents traversing repository files or writing automated pull request comments, a simple bug in a polling loop can consume this entire budget in less than four seconds. Understanding the exact thresholds of GitHub's primary and secondary rate limits is critical for designing reliable runtimes.

Primary rate limits are calculated based on the authentication method:

  • Unauthenticated Requests: The primary rate limit for unauthenticated requests is 60 requests per hour. These requests are tracked by the originating IP address and are intended only for simple public data retrieval.
  • Authenticated Users: Requests count towards your personal rate limit of 5,000 requests per hour. This applies to requests made with personal access tokens or OAuth tokens.
  • GitHub App Installations: A minimum of 5,000 requests per hour. For installations with more than 20 repositories or 20 users, the limit scales up by adding 50 requests per hour for each repository/user, capping at 12,500 requests per hour.
  • Enterprise Cloud Accounts: Requests made on your behalf by a GitHub App that is owned by a GitHub Enterprise Cloud organization have a higher rate limit of 15,000 requests per hour. This higher tier applies to authenticated user requests, OAuth apps, and GitHub App installations belonging to a GitHub Enterprise Cloud organization.
  • GitHub Actions GITHUB_TOKEN: The rate limit for GITHUB_TOKEN is 1,000 requests per hour per repository. If the repository belongs to an Enterprise Cloud organization, the limit increases to 15,000 requests per hour.

In addition to these primary caps, GitHub enforces secondary rate limits to prevent abuse and block distributed denial of service activity:

  • Concurrency: No more than 100 concurrent requests are allowed across the REST and GraphQL APIs.
  • Endpoint Points: A maximum of 900 points per minute for REST API calls. Most REST API GET, HEAD, and OPTIONS requests cost 1 point, while most REST API POST, PATCH, PUT, or DELETE requests cost 5 points.
  • Content Creation: In general, no more than 80 content-generating requests per minute and no more than 500 content-generating requests per hour are allowed. This includes creating issues, posting comments, and modifying pull requests.
  • Compute Time: No more than 90 seconds of CPU processing time per 60 seconds of real time is allowed.

For developers writing automated tools, these metrics define the maximum throughput your agent can sustain before encountering service errors. More details on limits can be found in the GitHub REST API rate limits documentation online page.

How to Check Rate Limit Status and Handle API Errors

When an agent exceeds a rate limit, the GitHub API returns an HTTP 429 Too Many Requests or HTTP 403 Forbidden status code. Programmatic clients must inspect the HTTP response headers to differentiate rate limit errors from authentication failures and to determine when it is safe to resume calls.

Every response from the GitHub API includes headers that track the current state of the client's rate limit budget:

  • x-ratelimit-limit: The maximum number of requests allowed per hour.
  • x-ratelimit-remaining: The number of requests remaining in the current hourly window.
  • x-ratelimit-used: The number of requests already consumed in the current window.
  • x-ratelimit-reset: The Unix epoch timestamp (in UTC seconds) indicating when the current rate limit window resets.
  • x-ratelimit-resource: The rate limit category the request was counted against.

If the x-ratelimit-remaining header drops to 0, the client must pause all requests. The reset time is absolute, meaning the agent should extract the x-ratelimit-reset header, compute the delta between the current time and the reset timestamp, and sleep for that duration.

When a secondary rate limit is triggered, the response header retry-after is typically present. This header specifies the exact number of seconds the client must wait before retrying the request. If retry-after is missing but the client receives an HTTP 403 or 429 secondary limit warning, the agent should default to waiting at least 60 seconds before making subsequent attempts.

Below is a JavaScript example showing how to programmatically inspect rate limit headers and handle errors using standard libraries:

const fetch = require('node-fetch');
async function makeRequest(url, headers) {
  const response = await fetch(url, { headers });
  if (response.status === 403 || response.status === 429) {
    const remaining = response.headers.get('x-ratelimit-remaining');
    const resetTime = response.headers.get('x-ratelimit-reset');
    const retryAfter = response.headers.get('retry-after');
    if (retryAfter) {
      const waitSeconds = parseInt(retryAfter, 10);
      console.log(`Secondary limit hit. Waiting ${waitSeconds} seconds.`);
      await new Promise(r => setTimeout(r, waitSeconds * 1000));
      return makeRequest(url, headers);
    }
    if (remaining === '0' && resetTime) {
      const waitSeconds = Math.max(0, parseInt(resetTime, 10) - Math.floor(Date.now() / 1000)) + 5;
      console.log(`Primary limit exhausted. Waiting ${waitSeconds} seconds.`);
      await new Promise(r => setTimeout(r, waitSeconds * 1000));
      return makeRequest(url, headers);
    }
  }
  return response;
}

Automated scripts must use response headers for validation instead of repeatedly calling the GET /rate_limit endpoint. While calling the rate limit endpoint does not consume primary rate limit points, it does count against secondary limits, meaning polling it can worsen a rate limit block.

How to Avoid Rate Limits with Conditional Requests

The most effective way to preserve your API budget is to avoid requesting data that has not changed. GitHub supports HTTP conditional requests, which allow clients to query resources and receive a lightweight response if the server-side data remains identical to the client's cached copy.

When a resource is requested for the first time, the GitHub API returns headers that identify the version of the data:

  • ETag: A unique hash representing the current state of the resource.
  • Last-Modified: A timestamp indicating when the resource was last updated.

On subsequent requests for the same resource, the client should send these values back in the request headers:

  • If-None-Match: Pass the cached ETag value.
  • If-Modified-Since: Pass the cached Last-Modified timestamp.

If the resource has not changed, the API returns an HTTP 304 Not Modified response. This response has an empty body, saving bandwidth and processing time. More importantly, an HTTP 304 response does not count against your primary rate limit. It costs 1 point against the secondary limit, but preserves the main 5,000 or 15,000 hourly budget, allowing agents to monitor repositories without exhausting their quotas.

Here is a JavaScript example of implementing a simple conditional request cache:

const fetch = require('node-fetch');
const cache = new Map();
async function fetchWithCache(url, headers) {
  const cached = cache.get(url);
  const reqHeaders = { ...headers };
  if (cached) {
    reqHeaders['If-None-Match'] = cached.etag;
  }
  const response = await fetch(url, { headers: reqHeaders });
  if (response.status === 304 && cached) {
    console.log('304 Not Modified. Returning cached version.');
    return cached.body;
  }
  if (response.status === 200) {
    const etag = response.headers.get('ETag');
    const body = await response.text();
    cache.set(url, { etag, body });
    return body;
  }
  return response.text();
}

Using conditional requests is highly recommended for agents that regularly scan configuration files, repository structures, or issue descriptions. Details on standard agent onboarding can be reviewed on the fast.io/llms.txt configuration page.

Fastio features

Offload GitHub API overhead with persistent agent workspaces

Deploy a collaborative workspace with a pre-configured MCP endpoint for your agent's file operations, complete with automated versioning and built-in semantic search. Starts with a 14-day free trial.

Replacing Polling with Webhooks and a Client-Side Queue

Recursive polling is a primary cause of rate limit exhaustion. When an agent queries an endpoint every few seconds to check for new commits or pull requests, it quickly depletes its quota.

To eliminate polling overhead, developers should implement webhook architectures. Webhooks are event-driven, meaning GitHub pushes data payloads to a designated listener URL only when specific events occur. Because webhook deliveries are inbound POST requests handled by your server, they consume zero API rate limit points. This shifts the compute load from polling loops to event-driven processing, keeping the API budget clean for actions that require active writes.

For scenarios where active API queries are unavoidable, agents must use client-side rate limiting algorithms to prevent bursting. The Token Bucket algorithm is a reliable pattern:

  • A token bucket has a maximum capacity and is refilled with tokens at a constant rate.
  • Each API call requires consuming one or more tokens from the bucket.
  • If the bucket is empty, the call is queued or delayed until tokens are refilled.

Enforcing serial request execution also helps prevent triggering secondary limits. If an agent performs write operations, adding a delay of at least 1 second between consecutive writes ensures compliance with secondary limits.

When retrying failed requests after a rate limit block, developers must implement exponential backoff with random jitter. If multiple agents retry their requests at the exact millisecond a rate limit resets, they will trigger a secondary rate limit again. Adding a random delay, or jitter, spreads the request load over time:

function calculateDelay(attempt, baseDelay = 2000, maxDelay = 60000) {
  const temp = Math.min(maxDelay, baseDelay * Math.pow(2, attempt));
  const sleepTime = temp * (0.5 + Math.random() * 0.5);
  return sleepTime;
}

This jitter calculation ensures that retries are distributed, reducing pressure on the GitHub API endpoints.

How Persistent Workspaces Offload GitHub API Demand

When coordinating multi-agent workflows, developers typically write files to local directories, spin up dedicated database servers like PostgreSQL, or store documents in Google Drive or Dropbox. However, local files cannot span server instances, while generic cloud drives lack native versioning and unified agent tooling, forcing developers to build custom synchronization code.

To simplify this coordination, developers can offload file sharing and document search tasks to Fast.io. Fast.io provides shared org-owned workspaces that serve as a collaborative substrate for humans and AI agents.

By moving document indexing and file operations out of local scripts and repository directories into a Fast.io workspace, developers gain several technical advantages:

  • URL Import: Instead of pulling datasets or repository documents to local storage via the GitHub API, developers can pull files directly into Fast.io workspaces using URL import. Fast.io imports files directly from sources via OAuth, bypassing local disk I/O.
  • Version History: Every file in a Fast.io workspace retains a complete version history. If an agent writes an incorrect file version, team members can inspect the changes and restore prior versions, keeping agent modifications auditable.
  • Intelligence Mode and Built-in RAG: Enabling Intelligence Mode on a workspace indexes all files on arrival for keyword and semantic search. Agents can query this workspace through the Fast.io developer storage workspace, which is accessible via Streamable HTTP at /mcp or legacy SSE at /sse. This allows agents to perform citation-backed search queries across documentation and data without repeatedly hitting GitHub APIs or managing a separate vector database.
  • Metadata Views: Turn raw documents into a live, queryable database spreadsheet. Users define the fields they want extracted in natural language, and Fast.io designs a typed schema (Text, Integer, Decimal, Boolean, URL, JSON, Date & Time) to extract structured data from files without manual OCR rules.

When an agent completes a task, it can transfer ownership of the organization or workspace to a human supervisor via a claim link, keeping security permissions clean.

Fast.io has three paid plans: Starter at $29/mo, Business at $99/mo, and Growth at $299/mo. Every organization starts with a 14-day free trial that requires a credit card, allowing teams to test MCP integrations and shared workspaces before committing to a subscription. For teams designing custom agent pipelines, the Fast.io developer storage workspace page outlines workspace setups, while pricing plans and billing limits are available on the Fast.io Pricing page. By using Fast.io as the persistent storage layer, developers can restrict GitHub API usage to code integration tasks, offloading general file storage and document retrieval to a dedicated, agent-ready workspace.

Frequently Asked Questions

What is the rate limit for GitHub API?

For unauthenticated requests, the primary rate limit is 60 requests per hour per IP address. For authenticated requests made with personal access tokens or OAuth tokens, the limit is 5,000 requests per hour. Organizations using GitHub Enterprise Cloud receive a higher rate limit of 15,000 requests per hour.

How do I check my GitHub API rate limit?

You can check your rate limit by inspecting the HTTP headers returned with every API response, including `x-ratelimit-remaining` and `x-ratelimit-reset`. Alternatively, you can query the `GET /rate_limit` endpoint, though using the response headers is preferred to avoid consuming secondary rate limits.

How do I increase my GitHub API rate limit?

You can increase your rate limit by authenticating your requests instead of making unauthenticated calls. If you need limits beyond the standard 5,000 requests per hour, you can build a GitHub App (which scales up to 12,500 requests per hour based on repositories and users) or upgrade your organization to GitHub Enterprise Cloud to receive 15,000 requests per hour.

What is the difference between primary and secondary rate limits on GitHub?

Primary rate limits are hourly budgets based on authentication (e.g., 5,000 requests per hour for authenticated users). Secondary rate limits are short-term safety caps designed to prevent abuse. They restrict things like concurrent connections (max 100), point-based consumption per minute (max 900 points for REST), and rapid content creation (max 80 content-generating requests per minute).

Related Resources

Fastio features

Offload GitHub API overhead with persistent agent workspaces

Deploy a collaborative workspace with a pre-configured MCP endpoint for your agent's file operations, complete with automated versioning and built-in semantic search. Starts with a 14-day free trial.