Rate Limiting

Understand tier-based rate limits and how to handle them in your application.

Rate Limits by Tier

TierRate LimitWindow
FREE
20 requestsper minute
BASIC
40 requestsper minute
PRO
80 requestsper minute
ENTERPRISE
150 requestsper minute

Response Headers

Every API response includes rate limit headers:

X-RateLimit-Limit

The maximum number of requests allowed per minute for your tier.

X-RateLimit-Remaining

The number of requests remaining in the current window.

X-RateLimit-Reset

Unix timestamp (milliseconds) when the rate limit resets.

Handling Rate Limits

Implement exponential backoff when you receive a 429 response:

  1. Check the X-RateLimit-Reset header
  2. Calculate wait time until reset
  3. Wait before retrying the request
  4. Consider implementing a queue for large batches

Best Practices

  • Monitor rate limit headers in responses
  • Implement retry logic with exponential backoff
  • Cache responses when possible to reduce API calls
  • Upgrade your plan if you consistently hit rate limits
  • Use batch operations wisely to stay within limits

Response Examples

429 Error

Request (Exceeds Limit)

curl -X POST https://snagkit.io/api/v1/capture \
  -H "X-API-Key: sk_live_xxx" \
  -d "url=https://example.com"

Response (429 Too Many Requests)

{
  "error": "Rate limit exceeded",
  "code": "RATE_LIMIT_EXCEEDED",
  "limit": 20,
  "remaining": 0,
  "reset": 1695123456789
}

Response Headers

HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 20
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1695123456789

Retry Logic Example (JavaScript)

async function captureWithRetry(url) {
  const response = await fetch('https://snagkit.io/api/v1/capture', {
    method: 'POST',
    headers: { 'X-API-Key': 'sk_live_xxx' },
    body: JSON.stringify({ url, response_type: 'json' })
  })

  if (response.status === 429) {
    const reset = response.headers.get('X-RateLimit-Reset')
    const waitTime = reset - Date.now()
    
    console.log(`Waiting ${waitTime}ms before retry`)
    await new Promise(resolve => setTimeout(resolve, waitTime))
    
    return captureWithRetry(url)
  }

  return response.json()
}