Api ReferenceRate Limiting

Rate Limiting

API rate limits, headers, and best practices for staying within bounds.

All Drok API endpoints are rate-limited to ensure fair usage and platform stability. Rate limits are per-user for authenticated requests and per-IP for unauthenticated requests.

Rate Limits

CategoryLimitWindow
Authenticated API5,000 requestsPer hour
Unauthenticated API60 requestsPer hour
Authentication endpoints10 requestsPer minute
Search API30 requestsPer minute
Git operations (clone/push/pull)1,000 operationsPer hour
GraphQL API5,000 pointsPer hour
Package registry1,000 requestsPer hour
Webhook delivery10,000 deliveriesPer hour per endpoint

Enterprise Limits

Enterprise organizations can request custom rate limits based on their usage patterns. Contact your account representative or email enterprise@drok.us.

Rate Limit Headers

Every API response includes rate limit headers:

X-RateLimit-Limit: 5000
X-RateLimit-Remaining: 4997
X-RateLimit-Reset: 1710523200
X-RateLimit-Resource: core
HeaderDescription
X-RateLimit-LimitMaximum requests allowed in the current window
X-RateLimit-RemainingRequests remaining in the current window
X-RateLimit-ResetUnix timestamp when the window resets
X-RateLimit-ResourceThe rate limit category (core, search, graphql)

Exceeding the Limit

When you exceed the rate limit, the API returns 429 Too Many Requests:

{
  "error": "rate_limit_exceeded",
  "message": "API rate limit exceeded. Try again at 2024-03-15T15:00:00Z.",
  "reset_at": "2024-03-15T15:00:00Z",
  "documentation_url": "https://docs.drok.us/api-reference/rate-limiting"
}

The response includes a Retry-After header indicating how many seconds to wait:

Retry-After: 120

GraphQL Rate Limiting

GraphQL requests are rate-limited by query complexity, not request count. Each field in a GraphQL query costs points:

Field TypeCost
Scalar field1 point
Object field2 points
Connection (list)2 points + (first/last * node cost)
Mutation10 points base

The query cost is returned in the response extensions:

{
  "data": { ... },
  "extensions": {
    "rateLimit": {
      "limit": 5000,
      "remaining": 4950,
      "cost": 50,
      "resetAt": "2024-03-15T15:00:00Z"
    }
  }
}

Best Practices

Use Conditional Requests

Use If-None-Match with ETags to avoid consuming rate limit for unchanged resources:

# First request — returns ETag
curl -I https://drok.us/api/v1/repos/my-org/my-repo \
  -H "Authorization: Bearer $Drok_TOKEN"
# Response: ETag: "abc123"
 
# Subsequent request — returns 304 if unchanged (does not count against rate limit)
curl https://drok.us/api/v1/repos/my-org/my-repo \
  -H "Authorization: Bearer $Drok_TOKEN" \
  -H "If-None-Match: \"abc123\""

Use Webhooks Instead of Polling

Instead of polling for changes, configure webhooks to receive push notifications:

drok webhook create my-org/my-repo \
  --url https://your-service.com/webhook \
  --events push,merge_request

Use GraphQL for Complex Queries

A single GraphQL query can retrieve data that would require multiple REST requests:

query {
  repository(owner: "my-org", name: "my-repo") {
    mergeRequests(state: OPEN, first: 10) {
      nodes {
        title
        author { username }
        reviews { nodes { state } }
        pipeline { status }
      }
    }
  }
}

Implement Exponential Backoff

When rate-limited, implement exponential backoff:

import time
import requests
 
def api_request(url, headers, max_retries=5):
    for attempt in range(max_retries):
        response = requests.get(url, headers=headers)
        if response.status_code != 429:
            return response
        retry_after = int(response.headers.get("Retry-After", 60))
        wait_time = min(retry_after, 2 ** attempt * 10)
        time.sleep(wait_time)
    raise Exception("Rate limit exceeded after max retries")