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:
| Tier | Price | Credits | Requests/Second | Research/Day | Explain/Day |
|---|---|---|---|---|---|
| Developer | Current | 25,000 | 10 rps | 100 | 500 |
| Business | Current | 50,000 | 20 rps | 300 | 1,500 |
| Professional | Current | 75,000 | 50 rps | 800 | 5,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-Afterheader
Response Headers:
X-RateLimit-Limit: 10
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1736455268
Retry-After: 12. Endpoint Soft Caps (Graceful Throttling)
AI-powered endpoints (/research and /explain) have daily soft caps to prevent LLM cost abuse.
Research Endpoint Soft Caps
| Tier | Daily Limit | Throttle Rate |
|---|---|---|
| Developer | 100 requests | 1 per 30s after limit |
| Business | 300 requests | 1 per 30s after limit |
| Professional | 800 requests | 1 per 30s after limit |
Explain Endpoint Soft Caps
| Tier | Daily Limit | Throttle Rate |
|---|---|---|
| Developer | 500 requests | 1 per 5s after limit |
| Business | 1,500 requests | 1 per 5s after limit |
| Professional | 5,000 requests | 1 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_exceeded3. Credit Burn Protection
Prevents runaway credit spending from bugs, automation errors, or malicious usage.
Limits per Tier:
| Tier | Max Credits/Minute |
|---|---|
| Developer | 300 credits |
| Business | 600 credits |
| Professional | 1,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
| Header | Description | Example |
|---|---|---|
X-RateLimit-Limit | Total requests allowed per second | 10 |
X-RateLimit-Remaining | Requests remaining in current window | 7 |
X-RateLimit-Reset | Unix timestamp when limit resets | 1736455268 |
Retry-After | Seconds to wait before retry | 1 |
Soft Cap Headers
| Header | Description | Example |
|---|---|---|
X-RateLimit-Remaining-Research | Research requests remaining today | 95 |
X-RateLimit-Remaining-Explain | Explain requests remaining today | 480 |
X-TessRadar-SoftLimit | Soft cap status if exceeded | research_daily_exceeded |
Burn Protection Headers
| Header | Description | Example |
|---|---|---|
X-TessRadar-BurnProtection | Burn protection status | active |
FAQ
Why am I seeing 429 errors?
Possible reasons:
- Base rate limit: You're exceeding your tier's requests-per-second limit
- Soft cap: You've hit your daily research/explain limit
- 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.