Rate Limiting

Understanding TessRadar's tier-based rate limiting, soft caps, and burn protection

Rate Limiting

TessRadar uses a multi-layered rate limiting system to ensure fair usage and prevent abuse while maintaining excellent UX for legitimate users.

Rate Limit Tiers

Your API rate limits are determined by your subscription tier:

TierPriceCreditsRequests/SecondResearch/DayExplain/Day
DeveloperCurrent25,00010 rps100500
BusinessCurrent50,00020 rps3001,500
ProfessionalCurrent75,00050 rps8005,000

How Rate Limiting Works

1. Base Rate Limits (Hard Caps)

All endpoints enforce tier-based requests-per-second limits using a sliding window algorithm.

Behavior:

  • Developer: Maximum 10 requests per second
  • Business: Maximum 20 requests per second
  • Professional: Maximum 50 requests per second

When Exceeded:

  • Returns 429 Too Many Requests
  • Blocks the request immediately
  • Includes Retry-After header

Response Headers:

X-RateLimit-Limit: 10
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1736455268
Retry-After: 1

2. Endpoint Soft Caps (Graceful Throttling)

AI-powered endpoints (/research and /explain) have daily soft caps to prevent LLM cost abuse.

Research Endpoint Soft Caps

TierDaily LimitThrottle Rate
Developer100 requests1 per 30s after limit
Business300 requests1 per 30s after limit
Professional800 requests1 per 30s after limit

Explain Endpoint Soft Caps

TierDaily LimitThrottle Rate
Developer500 requests1 per 5s after limit
Business1,500 requests1 per 5s after limit
Professional5,000 requests1 per 5s after limit

Behavior:

  • Requests continue to work after hitting the daily limit
  • Throttled to prevent burst abuse
  • Resets daily at midnight UTC

When Soft Cap is Exceeded:

HTTP/1.1 429 Too Many Requests
X-TessRadar-SoftLimit: research_daily_exceeded
X-RateLimit-Remaining-Research: 0
Retry-After: 30

{
  "error": {
    "code": "SOFT_CAP_EXCEEDED",
    "message": "Daily research limit reached (100). Throttled to 1 request per 30s."
  }
}

Response Headers:

X-RateLimit-Remaining-Research: 95
X-RateLimit-Remaining-Explain: 480
X-TessRadar-SoftLimit: research_daily_exceeded

3. Credit Burn Protection

Prevents runaway credit spending from bugs, automation errors, or malicious usage.

Limits per Tier:

TierMax Credits/Minute
Developer300 credits
Business600 credits
Professional1,200 credits

Behavior:

  • Tracks total credits spent in a rolling 60-second window
  • Blocks requests that would exceed the per-minute limit
  • Prevents credit drain attacks

When Burn Protection Triggers:

HTTP/1.1 429 Too Many Requests
X-TessRadar-BurnProtection: active
Retry-After: 60

{
  "error": {
    "code": "BURN_PROTECTION",
    "message": "Credit limit per minute exceeded (300). Already spent 305 credits this minute."
  }
}

Best Practices

1. Handle 429 Responses Gracefully

async function makeApiRequest(url: string, options: RequestInit) {
  const response = await fetch(url, options);
  
  if (response.status === 429) {
    const retryAfter = response.headers.get('Retry-After');
    const softLimit = response.headers.get('X-TessRadar-SoftLimit');
    const burnProtection = response.headers.get('X-TessRadar-BurnProtection');
    
    if (burnProtection) {
      console.log('Credit burn protection triggered. Pausing for 60s...');
      await new Promise(resolve => setTimeout(resolve, 60000));
      return makeApiRequest(url, options); // Retry
    }
    
    if (softLimit) {
      const waitTime = parseInt(retryAfter || '30', 10) * 1000;
      console.log(`Soft cap hit: ${softLimit}. Waiting ${waitTime}ms...`);
      await new Promise(resolve => setTimeout(resolve, waitTime));
      return makeApiRequest(url, options); // Retry
    }
    
    // Base rate limit
    const waitTime = parseInt(retryAfter || '1', 10) * 1000;
    await new Promise(resolve => setTimeout(resolve, waitTime));
    return makeApiRequest(url, options);
  }
  
  return response;
}

2. Monitor Your Usage

Track rate limit headers in every response:

const response = await fetch('https://api.tessradar.com/v1/markets', {
  headers: { 'X-API-Key': 'your-key' }
});

const rateLimit = {
  limit: response.headers.get('X-RateLimit-Limit'),
  remaining: response.headers.get('X-RateLimit-Remaining'),
  reset: response.headers.get('X-RateLimit-Reset'),
  researchRemaining: response.headers.get('X-RateLimit-Remaining-Research'),
  explainRemaining: response.headers.get('X-RateLimit-Remaining-Explain'),
};

console.log('Rate limits:', rateLimit);

3. Implement Exponential Backoff

For production systems, use exponential backoff for retries:

async function fetchWithBackoff(
  url: string,
  options: RequestInit,
  maxRetries = 3
): Promise<Response> {
  for (let i = 0; i < maxRetries; i++) {
    const response = await fetch(url, options);
    
    if (response.status !== 429) {
      return response;
    }
    
    const retryAfter = response.headers.get('Retry-After');
    const baseDelay = parseInt(retryAfter || '1', 10) * 1000;
    const exponentialDelay = baseDelay * Math.pow(2, i);
    
    console.log(`Retry ${i + 1}/${maxRetries} after ${exponentialDelay}ms`);
    await new Promise(resolve => setTimeout(resolve, exponentialDelay));
  }
  
  throw new Error('Max retries exceeded');
}

4. Use Appropriate Endpoints

Choose the right endpoint for your use case to optimize credit usage:

  • Markets endpoint (1 credit): Use for listing and filtering markets
  • Explain endpoint (5 credits): Quick market summaries with structured data
  • Research endpoint (10 credits): Deep analysis with multiple data sources

5. Cache Responses When Possible

Reduce API calls by caching responses on your end:

const cache = new Map<string, { data: any; timestamp: number }>();
const CACHE_TTL = 60000; // 60 seconds

async function getCachedMarkets() {
  const now = Date.now();
  const cached = cache.get('markets');
  
  if (cached && (now - cached.timestamp) < CACHE_TTL) {
    return cached.data;
  }
  
  const response = await fetch('https://api.tessradar.com/v1/markets', {
    headers: { 'X-API-Key': process.env.TESS_API_KEY }
  });
  
  const data = await response.json();
  cache.set('markets', { data, timestamp: now });
  
  return data;
}

Response Headers Reference

Standard Rate Limit Headers

HeaderDescriptionExample
X-RateLimit-LimitTotal requests allowed per second10
X-RateLimit-RemainingRequests remaining in current window7
X-RateLimit-ResetUnix timestamp when limit resets1736455268
Retry-AfterSeconds to wait before retry1

Soft Cap Headers

HeaderDescriptionExample
X-RateLimit-Remaining-ResearchResearch requests remaining today95
X-RateLimit-Remaining-ExplainExplain requests remaining today480
X-TessRadar-SoftLimitSoft cap status if exceededresearch_daily_exceeded

Burn Protection Headers

HeaderDescriptionExample
X-TessRadar-BurnProtectionBurn protection statusactive

FAQ

Why am I seeing 429 errors?

Possible reasons:

  1. Base rate limit: You're exceeding your tier's requests-per-second limit
  2. Soft cap: You've hit your daily research/explain limit
  3. Burn protection: You're spending credits too quickly

Solution: Check the response headers to identify which limit was hit, then implement appropriate retry logic.

Do soft caps block my requests?

No! Soft caps don't block requests - they only throttle them. You can still make requests, just at a slower rate (1 per 30s for research, 1 per 5s for explain).

Will I ever hit the soft cap with normal usage?

Unlikely. The soft caps are designed to only catch abuse patterns:

  • Developer tier: 100 research/day = 3,000/month (but you only get 25,000 total credits)
  • The caps are higher than what your credits allow for normal usage

How do I increase my rate limits?

Upgrade to a higher tier:

  • Business tier: 20 rps, 300 research/day, 1,500 explain/day
  • Professional tier: 50 rps, 800 research/day, 5,000 explain/day

Can I request higher limits?

For enterprise usage beyond Professional tier limits, contact us at support@tessradar.com.

On this page