Reference
Rate limits and quotas
Credits, requests per minute and monthly logo and search allowances for each plan, the headers that report them, and what happens at a limit.
Limits by plan
Three things limit the API: your credit balance, which each successful brand lookup spends one of; a per-minute request limit shared by every endpoint and every key on your account; and a monthly allowance of searches and of logo requests sent with a key.
| Plan | Brand fetches | Requests a minute | Domains per batch |
|---|---|---|---|
| Free | 50 once | 60 | 25 |
| Starter | 10,000 a month | 300 | 50 |
| Growth | 30,000 a month | 600 | 100 |
| Custom | Custom | 3,000 | 100 |
Prices are on the pricing page. Every account starts with free credits; each successful subscription payment adds the plan's credits, and a top-up pack adds more. Credits never expire: what a month does not use rolls over, through plan changes and after a cancellation.
Monthly limits
Search and the logo CDN never spend a credit. Instead, each plan includes a number of each per calendar month (UTC), counted across every key on your account. The count starts over at midnight UTC on the 1st, and an upgrade raises the allowance at once.
| Plan | Logo renders a month | Searches a month |
|---|---|---|
| Free | 500,000 | 250,000 |
| Starter | 3,000,000 | 1,000,000 |
| Growth | Unlimited | Unlimited |
| Custom | Unlimited | Unlimited |
- Searches count once each when they answer
200, from a secret or a publishable key, on/v1/search,/v2/searchand the MCP server'ssearch_brands. Past the allowance, search answers429with quota_exceeded and aRetry-Afterthat runs to the 1st. - Logo renders count logo CDN requests sent with one of your keys. Requests without a key never count, and neither do the ones our CDN's cache answers. Past the allowance, logos keep loading: a request with your key is served as if it had none (brands already indexed, at the per-visitor limits) and says so in an
X-Api-Key-Status: quota-exceededheader. GET /v1/mereturns this month's counts and your plan's allowances, and the usage page in the dashboard shows them.
What costs a credit
- A Brand API request that returns a brand, on
/v1or the/v2alias. - Each brand found by a batch request. Duplicate domains in one batch count once.
- A
get_brandcall through the MCP server that finds a brand.
Nothing else costs a credit: lookups that fail or find nothing, search, /v1/me, the logo CDN and asset URLs. A failed lookup's credit is handed back the moment it fails. Search and logo requests with a key count toward the monthly limits instead.
Headers
| Header | Description |
|---|---|
| X-RateLimit-Limit | Requests allowed per minute on your plan. |
| X-RateLimit-Remaining | Requests left in the current minute. |
| X-RateLimit-Reset | When the current minute ends, in Unix seconds. |
| X-Credits-Remaining | Credits left after this request. On brand lookups, batches and /v1/me. |
| Retry-After | On a 429 or 503: how many seconds to wait before retrying. |
All of them are readable from browser code: the API lists them in Access-Control-Expose-Headers.
At the limit
Over the per-minute limit, requests answer 429 with the code rate_limited and a Retry-After header: wait and retry. With no credits left, brand lookups answer 402 with insufficient_credits until credits are added. Do not retry that one on a timer. Past the monthly search allowance, search answers 429 with quota_exceeded, whose Retry-After runs to the 1st (UTC): check the code before you wait on it. There are no overage charges: we stop, we do not bill.
A lookup of a domain we have not indexed yet crawls it live. Besides your plan's crawl limit, the whole service has a ceiling on live crawls per minute. At that ceiling such a lookup answers 503 with a Retry-After header and is not counted; brands already indexed are served as usual.
async function getBrand(domain, attempt = 0) {
const res = await fetch(`https://brandidentityapi.com/v1/brands/${domain}`, {
headers: { Authorization: `Bearer ${process.env.BRAND_IDENTITY_API_KEY}` },
});
if (res.status === 402) {
// Out of credits: retrying will not help until someone adds credits.
const { error } = await res.json();
throw new Error(`${error.message} (balance ${error.details?.balance})`);
}
if (res.status === 429) {
if (attempt >= 3) throw new Error("Still rate limited after 3 retries");
const wait = Number(res.headers.get("Retry-After") ?? "1");
await new Promise((resolve) => setTimeout(resolve, wait * 1000));
return getBrand(domain, attempt + 1);
}
if (!res.ok) {
const { error } = await res.json();
throw new Error(`${error.code}: ${error.message}`);
}
return res.json();
}GET /v1/me returns your plan, your credit balance and this month's usage, and costs nothing. Check it before a large import.Logo CDN limits
The logo CDN has its own burst limits and never touches your credits:
| Caller | Limit |
|---|---|
| No key, per visitor address | 300 a minute |
| With a key, per account | 3,000 a minute |
| Live crawls of new domains, with a key, per account | 30 a minute |
| Live crawls of new domains, with a key, per caller address | 30 a minute |
Only requests that miss our CDN's cache reach these counters, so a page of popular logos rarely comes close. Requests with a key also count toward your plan's monthly logo renders. Past a crawl limit, a domain we have not indexed gets the fallback image until the minute ends.