PerformanceBlog
Tempo MCP serverGive agents search and read tools for Tempo docs
Skip to content
LogoLogo

API Rate Limits

The Tempo API enforces rate limits to ensure fair usage and system stability. Limits are counted in fixed one-minute windows, and every response reports your current quota in RateLimit-* headers.

Tempo API quota structure

Each request consumes from one quota bucket, chosen by how the request is authenticated:

CallerBucketDefault limit
API keyPer key, per scope100 requests / minute
AnonymousPer client IP20 requests / minute
  • API key requests are counted per key and per scope. Each endpoint draws from the bucket for the scope it requires (such as data:read), so traffic to one scope does not exhaust another.
  • Anonymous requests — endpoints that allow access without a key — are counted per client IP at a lower limit.

Rate-limit response headers

Every rate-limited response carries your current quota:

RateLimit-Limit: 100
RateLimit-Remaining: 97
RateLimit-Reset: 1735689600
RateLimit-Scope: data:read
HeaderDescription
RateLimit-LimitRequests allowed in the current window.
RateLimit-RemainingRequests remaining in the current window.
RateLimit-ResetUnix timestamp (seconds) when the window resets and the count returns to the full limit.
RateLimit-ScopeThe scope bucket the request was counted against. Present on API-key requests.

Exceeding Tempo API rate limits

When you exceed the limit, the API responds with 429 Too Many Requests and a Retry-After header giving the number of seconds to wait before retrying:

HTTP/1.1 429 Too Many Requests
Retry-After: 12
{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded"
  },
  "requestId": "0a1b2c3d-4e5f-6071-8293-a4b5c6d7e8f9"
}

Rate-limit best practices for Tempo API clients

Respect rate-limit headers

Read RateLimit-Remaining and RateLimit-Reset to pace your requests, and pause until RateLimit-Reset when RateLimit-Remaining reaches 0 rather than retrying blindly.

Retry rate-limited requests with backoff

When you receive a 429, wait for the duration in Retry-After, then retry with exponential backoff and jitter for repeated failures:

async function withRetry<T>(fn: () => Promise<Response>): Promise<Response> {
  let attempt = 0
  while (true) {
    const response = await fn()
    if (response.status !== 429) return response
 
    const retryAfter = Number(response.headers.get('Retry-After') ?? 1)
    const backoff = Math.min(retryAfter, 2 ** attempt) * 1000
    await new Promise((resolve) => setTimeout(resolve, backoff))
    attempt++
  }
}

Cache and paginate API reads

  • Cache responses for read-heavy data that does not need to be real-time.
  • Use pagination with a large limit to fetch more per request instead of issuing many small calls.
  • Request only the fields you need with include, so expensive computations run only when required.

Authenticate for higher API quotas

Anonymous traffic is held to the lower IP-based limit. Send an API key to get a per-key, per-scope quota, and request a higher limit if your workload needs it.

Was this helpful?