Rate limits and quotas
Two limits apply to your account. Both are shared by all of your account's keys.
| Limit | Applies to | Default | Resets |
|---|---|---|---|
| Rate limit | Every request | Live: set per account, usually 60 a minute. Sandbox: 120 a minute | Every minute |
| Monthly quota | Successful live score lookups | Set per account in your agreement | 1st of each month, 00:00 UTC |
A score lookup counts against the monthly quota only when it returns a score. Errors, GET /v1/usage, GET /v1/health and all sandbox requests are free.
GET /v1/usage returns your current limits and how much of the quota is used.
Headers on every response#
| Header | Description |
|---|---|
X-RateLimit-Limit |
Requests allowed per minute |
X-RateLimit-Remaining |
Requests left in the current minute |
X-RateLimit-Reset |
Unix time when the current minute's window resets |
X-Quota-Limit |
Live only: score lookups allowed this month |
X-Quota-Remaining |
Live only: score lookups left this month |
Watch X-Quota-Remaining to warn your team before the quota runs out, rather than finding out from a refusal.
When you hit a limit#
Both limits answer 429 with a rate_limit_error:
rate_limit_exceeded: wait the number of seconds in theRetry-Afterheader, then retry.monthly_quota_exceeded: do not retry. Lookups are refused until the 1st, or until your quota is raised.
Retrying well#
Retry on 429 rate_limit_exceeded and on 503 or 500. Do not retry other errors; they will fail the same way again.
async function getDtScore(dot, attempt = 0) {
const response = await fetch(
`https://api.dollartraq.com/v1/dt-score?dot_number=${dot}`,
{ headers: { Authorization: `Bearer ${process.env.DT_SCORE_KEY}` } }
);
if (response.ok) return response.json();
const { error } = await response.json();
const retryable = response.status >= 500 || error.code === "rate_limit_exceeded";
if (!retryable || attempt >= 4) throw new Error(`${error.code}: ${error.message}`);
const retryAfter = Number(response.headers.get("Retry-After")) || 1;
const wait = Math.max(retryAfter, 2 ** attempt) * 1000 + Math.random() * 250;
await new Promise((resolve) => setTimeout(resolve, wait));
return getDtScore(dot, attempt + 1);
}
import os, random, time, requests
def get_dt_score(dot, attempts=5):
for attempt in range(attempts):
response = requests.get(
"https://api.dollartraq.com/v1/dt-score",
params={"dot_number": dot},
headers={"Authorization": f"Bearer {os.environ['DT_SCORE_KEY']}"},
timeout=30,
)
if response.ok:
return response.json()
error = response.json()["error"]
retryable = response.status_code >= 500 or error["code"] == "rate_limit_exceeded"
if not retryable or attempt == attempts - 1:
raise RuntimeError(f"{error['code']}: {error['message']}")
retry_after = int(response.headers.get("Retry-After", 1))
time.sleep(max(retry_after, 2 ** attempt) + random.random() / 4)
Keep request volume down#
- Scores change at most daily. If you show the same carrier many times a day, keep its score for a few hours instead of asking again.
- Look a carrier up when it matters, such as at onboarding and before a tender, rather than on every page view.
- If you need a higher limit or quota, ask your DollarTraq contact.