Rate Limits
Understand the rate limits for the Trakkr API and how to handle them gracefully in your application.
Code example
# A 429 names the limit you hit. No rate limit headers are sent.
curl -i -H "Authorization: Bearer $TRAKKR_API_KEY" \
'https://api.trakkr.ai/get-brands'
# HTTP/2 429
# Content-Type: application/json
# {"error": "Rate limit exceeded: 60 per 1 minute"}{
"error": "Rate limit exceeded: 60 per 1 minute"
}Synthetic example. Values are made up.
Overview
The Trakkr API limits how many requests it accepts per minute, so one busy caller cannot slow the service down for everyone else.
How the limit works
The main limit is a per-minute count on each endpoint, listed in the table below. It is the same on every plan. There is no burst allowance and no higher tier that lifts these numbers. API access requires the Scale plan ($500/mo) or higher, but the plan does not change the per-minute figures.
Limits are counted per account. Every request made with your API key shares one budget, whichever servers or IP addresses it comes from, and other customers on the same network never use yours.
Creating brands has one more limit, shared with the app: each account can add up to twice its brand slots in new brands every 30 days, or its slots plus five on smaller plans. Brands you later delete still count, and restoring a deleted brand does not. A create past the limit returns 429 with brand_creation_limit_reached and the date the next one fits. See Brands and client portals.
Per-Endpoint Limits
Different endpoints have different rate limits based on their computational cost. Write operations and resource-intensive endpoints have stricter limits.
| Endpoint | Method | Rate Limit | Notes |
|---|---|---|---|
/get-brands | GET | 60/min | |
/get-brands/markets | POST | 30/min | Market limit per plan |
/get-brands/markets | DELETE | 30/min | |
/get-brands/aliases | PUT | 30/min | |
/manage-brand | POST | 20/min | New brands also capped per 30 days |
/manage-client | POST | 20/min | Team owner or admin |
/get-scores | GET | 60/min | |
/get-prompts | GET | 60/min | |
/get-prompts | POST | 30/min | |
/get-prompts | PUT | 30/min | |
/get-prompts | DELETE | 30/min | |
/get-citations | GET | 60/min | |
/get-competitor-data | GET | 60/min | |
/get-rankings | GET | 60/min | |
/get-models | GET | 60/min | |
/get-opportunities | GET | 60/min | |
/get-perception | GET | 60/min | |
/get-perception | POST | 10/min | Triggers new analysis |
/get-content-ideas | GET | 60/min | |
/get-content-ideas | POST | 10/min | Triggers refresh |
/get-reports | GET | 60/min | |
/get-reports | POST | 5/min | Generates PDF report |
/crawler/overview | GET | 60/min | |
/crawler/live | GET | 60/min | |
/crawler/pages | GET | 60/min | |
/crawler/access | GET | 60/min | |
/crawler/access/preview-fix | POST | 30/min | Preview only |
/crawler/verification-ping | POST | 30/min | Editor access required |
/crawler/submit-to-search | POST | 30/min | Editor access required |
/crawler/submit-to-search/status | GET | 60/min | |
/narratives | GET | 60/min | |
/narratives | POST | 10/min | |
/narratives | PATCH | 30/min | |
/narratives | DELETE | 30/min | |
/diagnose | POST | 10/min | 200/mo quota (Scale) |
/diagnose | GET | 60/min | |
/get-actions | GET | 60/min | |
/get-action-stats | GET | 60/min | |
/manage-action | POST | 30/min | Editor access required |
/get-audits | GET | 60/min | |
/get-audit-findings | GET | 60/min | |
/get-opportunity-pool | GET | 60/min | |
/commit-opportunity | POST | 30/min | Editor access required |
/get-results | GET | 60/min | |
/get-pages | GET | 60/min | |
/get-page-analyses | GET | 60/min | |
/prism | GET | 60/min | |
/export | GET | 10/min |
Handling Rate Limits
When you go over, the API returns 429 Too Many Requests. The body holds one error string naming the limit you hit, for example Rate limit exceeded: 60 per 1 minute. Note that this is the one error that does not use the usual detail field.
Responses carry no rate limit headers. There is no X-RateLimit-Remaining, X-RateLimit-Limit, X-RateLimit-Reset or Retry-After to read, on any response including the 429. Plan around the published limits instead of measuring what is left.
Wait a fixed minute
Windows are one minute long. On a 429, sleep 60 seconds and try once more, rather than retrying straight away.
Back off if it keeps happening
If the retry is limited too, grow the wait and add jitter, so a fleet of workers does not all come back at the same moment.
Count your own requests
With no remaining counter to read, track your call rate on your side and throttle before you reach the limit. Remember the budget is counted per account, so every request made with your key shares it.
Exponential Backoff
Exponential backoff means each retry waits longer than the last. Start above the one-minute window, then double, and add random jitter so clients do not all retry at exactly the same time:
# Implement exponential backoff in shell
attempt=1
max_attempts=5
while [ $attempt -le $max_attempts ]; do
response=$(curl -s -w "%{http_code}" \
-H "Authorization: Bearer $TRAKKR_API_KEY" \
'https://api.trakkr.ai/get-brands')
status=$(echo "$response" | tail -c 4)
if [ "$status" -eq 200 ]; then
echo "Success!"
break
elif [ "$status" -eq 429 ]; then
sleep_time=$((2 ** $attempt))
echo "Rate limited. Retrying in ${sleep_time}s..."
sleep $sleep_time
attempt=$((attempt + 1))
else
echo "Error: $status"
break
fi
doneBest Practices
Batch operations when possible
Use bulk endpoints to create or update multiple resources in a single request.
Cache responses locally
Avoid redundant API calls by caching frequently accessed data that doesn't change often.
Use webhooks for real-time updates
Instead of polling, subscribe to webhooks to receive push notifications for events.
Queue and throttle requests
Implement a request queue with throttling to smooth out bursts and stay within rate limits.
