gh-proxy is a GitHub API proxy that provides rate limiting, caching, and token pooling for GitHub API requests.
https://gh-proxy.hackclub.com
Include your API key in the X-API-Key header:
curl -H "X-API-Key: your_api_key_here" https://gh-proxy.hackclub.com/gh/user
Description: Proxy any GitHub REST API endpoint
Example:
# Get current user
curl -H "X-API-Key: your_key" https://gh-proxy.hackclub.com/gh/user
# Get repository information
curl -H "X-API-Key: your_key" https://gh-proxy.hackclub.com/gh/repos/octocat/Hello-World
# List user repositories
curl -H "X-API-Key: your_key" https://gh-proxy.hackclub.com/gh/users/octocat/repos
# Search repositories
curl -H "X-API-Key: your_key" "https://gh-proxy.hackclub.com/gh/search/repositories?q=javascript"
Description: Proxy GitHub GraphQL API
Content-Type: application/json
Example:
# GraphQL query
curl -X POST \
-H "X-API-Key: your_key" \
-H "Content-Type: application/json" \
-d '{"query": "query { viewer { login name } }"}' \
https://gh-proxy.hackclub.com/gh/graphql
Each API key has its own rate limit (configurable per key, default: 10 requests/second) over a one-second window.
Rate Limit Exceeded: Returns 429 Too Many Requests when limit is exceeded, with a Retry-After header.
Every /gh/ response reports your live quota so you can self-throttle without waiting for a 429:
RateLimit-Limit: requests allowed per window (e.g. 10)RateLimit-Remaining: requests still available right now (e.g. 9)RateLimit-Reset: seconds until the quota is fully replenished (e.g. 1)RateLimit: the same state in IETF draft syntax — "default";r=9;t=1RateLimit-Policy: the policy in force — "default";q=10;w=1 (quota 10, window 1s). Sent on every response.Retry-After: seconds to wait, sent with 429 responsesGitHub's own upstream quota is passed through unchanged as X-RateLimit-*. Those headers describe GitHub's limit on the donated token that served your request; the RateLimit-* headers above describe this proxy's limit on your key.
curl -sD- -o /dev/null -H "X-API-Key: your_key" https://gh-proxy.hackclub.com/gh/rate_limit
RateLimit-Limit: 10
RateLimit-Remaining: 9
RateLimit-Reset: 1
RateLimit-Policy: "default";q=10;w=1
RateLimit: "default";r=9;t=1
Responses are automatically cached to improve performance:
X-Gh-Proxy-Cache header for hit/miss statusCache Hit: X-Gh-Proxy-Cache: hit means the response came from cache
Cache Miss: X-Gh-Proxy-Cache: miss means a fresh request was made to GitHub
The proxy adds helpful debug headers to responses:
X-Gh-Proxy-Cache: hit/miss - Whether response came from cacheX-Gh-Proxy-Category: core/search/graphql - API category usedX-Gh-Proxy-Client: Your API key identifierX-Gh-Proxy-Donor: GitHub user who donated the token used (when applicable)const response = await fetch('https://gh-proxy.hackclub.com/gh/user', {
headers: {
'X-API-Key': 'your_api_key_here'
}
});
const user = await response.json();
console.log(user);
const axios = require('axios');
const api = axios.create({
baseURL: 'https://gh-proxy.hackclub.com/gh',
headers: {
'X-API-Key': 'your_api_key_here'
}
});
// Get user info
const user = await api.get('/user');
// GraphQL query
const graphql = await api.post('/graphql', {
query: 'query { viewer { login repositories(first: 10) { nodes { name } } } }'
});
import requests
headers = {'X-API-Key': 'your_api_key_here'}
# REST API
response = requests.get('https://gh-proxy.hackclub.com/gh/user', headers=headers)
user = response.json()
# GraphQL
graphql_query = {
"query": "query { viewer { login name } }"
}
response = requests.post('https://gh-proxy.hackclub.com/gh/graphql',
headers=headers,
json=graphql_query)
data = response.json()
Every error this proxy generates is JSON, never an HTML page. The envelope is stable:
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded",
"hint": "This key allows 10 requests/second; retry after 1 second(s) and back off exponentially",
"documentation_url": "https://gh-proxy.hackclub.com/docs"
}
}
Branch on error.code — it is stable. message and hint are for humans and logs.
404 and 405 responses also carry an error.links array pointing at the entry points of this service.
401 MISSING_API_KEY: no X-API-Key header was sent401 INVALID_API_KEY: the key is not recognised403 API_KEY_DISABLED: the key exists but was disabled by an administrator404 NOT_FOUND: no such path on this proxy405 METHOD_NOT_ALLOWED: the path exists but does not accept that method413 REQUEST_TOO_LARGE: request body too large (max 1MB)429 RATE_LIMIT_EXCEEDED: rate limit exceeded — see Retry-After503 DB_ERROR: the key could not be verified; transient, retry with backoffAny other status on a /gh/ request is GitHub's own response, forwarded verbatim. A 404 from /gh/repos/does/not-exist is GitHub's 404, with GitHub's body.
/llms.txt: machine-readable site map in the llmstxt.org format/openapi.json: OpenAPI 3.0.3 specification for every endpoint, header and error shape/sitemap.xml and /robots.txt404. Send Accept: application/json for the JSON envelope; anything else gets a short markdown document listing where to go next.For API keys or technical support, contact your system administrator.