Rate Limits & Quotas

Every API key in Otesse is subject to rate limits that protect the platform from abuse and ensure fair resource allocation across all organizations. Rate limits are tiered by organization plan and enforced per-key. This page explains the rate limit tiers, how limits are communicated, and how to handle rate-limited responses.

Rate Limit Tiers

Rate limits vary by organization plan:

TierRequests/MinuteRequests/HourRequests/DayBurst Limit
Free305005,00010
Pro1205,00050,00030
Enterprise60030,000300,000100

What Each Limit Means

  • Requests/Minute — The sustained request rate. Resets every 60 seconds
  • Requests/Hour — Protects against prolonged high-volume usage. Resets every 60 minutes
  • Requests/Day — The daily quota. Resets at midnight UTC
  • Burst Limit — Maximum concurrent requests. Prevents sudden spikes from overwhelming the system

All limits are enforced per API key. If your organization has multiple keys, each key has its own independent limits.

Rate Limit Headers

Every API response includes rate limit headers so your application can track its usage:

HeaderDescriptionExample
X-RateLimit-LimitMaximum requests allowed in the current window120
X-RateLimit-RemainingRequests remaining before hitting the limit87
X-RateLimit-ResetUnix timestamp when the current window resets1709312400

These headers appear on every response, not just rate-limited ones. Your application should monitor X-RateLimit-Remaining and throttle requests as it approaches zero.

Handling 429 Responses

When your application exceeds the rate limit, the API returns:

HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 15
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1709312400

{
  "error": "rate_limited",
  "message": "Rate limit exceeded. Try again in 15 seconds.",
  "retryAfter": 15
}
  1. Read the Retry-After header — This tells you exactly how many seconds to wait before retrying
  2. Implement exponential backoff — If the first retry also fails, double the wait time
  3. Queue requests — Buffer outgoing requests and process them at a sustainable rate
  4. Spread requests over time — Instead of making 100 requests in 1 second, spread them across the minute

Example Retry Logic

async function apiCallWithRetry(url, options, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    const response = await fetch(url, options);

    if (response.status === 429) {
      const retryAfter = parseInt(
        response.headers.get('Retry-After') || '10'
      );
      await new Promise(r => setTimeout(r, retryAfter * 1000));
      continue;
    }

    return response;
  }
  throw new Error('Max retries exceeded');
}

Rate Limit Violations

When a rate limit is exceeded, the system creates a RateLimitViolation record:

FieldDescription
API Key IDWhich key triggered the violation
Violation TypeWhich limit was exceeded (per-minute, per-hour, per-day, or burst)
Request CountNumber of requests in the window at violation time
TimestampWhen the violation occurred
EndpointWhich API endpoint was being called
IP AddressSource IP of the request

Administrators can view rate limit violations in the API key detail view under "Usage Summary." Repeated violations may indicate that:

  • The application needs to be optimized for fewer API calls
  • The organization should upgrade to a higher plan tier
  • The application has a bug causing excessive requests (e.g., an infinite loop)

Usage Monitoring

Every API request creates an ApiUsageLog entry:

FieldDescription
TimestampWhen the request was made
EndpointThe API path that was called
HTTP MethodGET, POST, PUT, PATCH, or DELETE
Status CodeThe response status (200, 401, 429, etc.)
Response TimeHow long the request took (milliseconds)
IP AddressSource IP
Rate LimitedWhether this request was rate limited

The usage log is accessible from the API key detail view and can be filtered by date range, endpoint, status code, and IP address. This helps diagnose performance issues, identify unusual usage patterns, and plan for capacity.

Best Practices

  1. Cache responses — Store API responses locally and serve from cache when possible. This dramatically reduces request count.
  2. Use pagination efficiently — Request the maximum page size to minimize the number of list calls.
  3. Batch operations — Use bulk endpoints (where available) instead of individual record operations.
  4. Monitor the Remaining header — Proactively slow down before hitting the limit, rather than reacting to 429 responses.
  5. Set up alerts — Configure notifications for when API usage approaches your daily quota.