Rate Limits

Understand API rate limiting and how to handle limits effectively.

Rate Limits

LoomAPI implements rate limiting to ensure fair usage and system stability. Understanding and properly handling rate limits is crucial for building reliable integrations.

Rate Limit Overview

Rate limits are enforced per API key and help prevent abuse while ensuring all users have fair access to our services.

Current Limits

Rate limits are per tenant API key. Exact limits depend on your plan; typical v1 endpoints:

EndpointTypical limitWindow
/verify/start, /verify/complete, /verify/submit60 requests (default)per minute, per tenant key
Other endpointsGenerous — not the bottleneck for normal use

Rate Limit Headers

Responses from rate-limited endpoints include rate limit headers:

HTTP/1.1 200 OK
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 57
X-RateLimit-Reset: 1740995200

Header Explanations

  • X-RateLimit-Limit: Maximum requests allowed in the current window
  • X-RateLimit-Remaining: Number of requests remaining in the current window
  • X-RateLimit-Reset: Unix timestamp when the rate limit resets
  • Retry-After: Seconds to wait before retrying — sent on 429 responses

Handling Rate Limits

Exponential Backoff

Implement exponential backoff when you hit rate limits:

async function makeRequestWithBackoff(requestFn, maxRetries = 3) {
  let retryCount = 0

  while (retryCount < maxRetries) {
    try {
      const response = await requestFn()

      // Check for rate limit headers
      const remaining = response.headers.get('X-RateLimit-Remaining')
      const resetTime = response.headers.get('X-RateLimit-Reset')

      if (remaining && parseInt(remaining) === 0) {
        const waitTime = calculateBackoffTime(retryCount, resetTime)
        await new Promise(resolve => setTimeout(resolve, waitTime))
        retryCount++
        continue
      }

      return response
    } catch (error) {
      if (error.status === 429) {
        const retryAfter = error.headers.get('Retry-After')
        const waitTime = retryAfter ? parseInt(retryAfter) * 1000 : calculateBackoffTime(retryCount)
        await new Promise(resolve => setTimeout(resolve, waitTime))
        retryCount++
        continue
      }
      throw error
    }
  }

  throw new Error('Max retries exceeded')
}

function calculateBackoffTime(retryCount, resetTime = null) {
  if (resetTime) {
    const reset = new Date(parseInt(resetTime) * 1000)
    const now = new Date()
    return Math.max(0, reset.getTime() - now.getTime())
  }

  // Exponential backoff: 1s, 2s, 4s, 8s...
  return Math.pow(2, retryCount) * 1000
}

Rate Limit Response

When you exceed rate limits, you'll receive a 429 Too Many Requests response:

{
  "error": "RATE_LIMIT_EXCEEDED",
  "message": "Rate limit exceeded",
  "details": { "retryAfterSeconds": 30 },
  "requestId": "550e8400-e29b-41d4-a716-446655440000"
}

The Retry-After response header carries the same delay. See Errors for the full error format.

Best Practices

📊 Monitor Usage

  • Track your API usage in the dashboard
  • Set up alerts for approaching rate limits
  • Log rate limit headers for debugging

⚡ Optimize Requests

  • Batch requests when possible
  • Cache results appropriately
  • Use webhooks for asynchronous processing

🏗️ Architecture Considerations

  • Implement request queuing
  • Use multiple API keys for different services
  • Consider upgrading your plan for higher limits

Rate Limit Increases

Rate limits depend on your plan. If you expect sustained high volume and need higher limits, contact us to discuss your requirements.

Email hello@loomapi.com.

Troubleshooting

Common Issues

  • Bursty Traffic: Implement request smoothing or queuing
  • Background Jobs: Schedule intensive operations during off-peak hours
  • Client-side Limits: Don't rely solely on client-side rate limiting

Testing rate limits

Make repeated calls to a v1 endpoint to observe rate limit headers and 429 responses:

# Use your tenant API key
for i in $(seq 1 150); do
  curl -s -o /dev/null -w "%{http_code}\n" \
    -X POST https://api.loomapi.com/verify/start \
    -H "x-tenant-api-key: $LOOM_TENANT_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{}'
done

Responses include rate limit headers; after exceeding the limit you receive 429 with retryAfterSeconds in the details object. See Billing & Usage for quotas vs rate limits.