Skip to main content
Each plan has a per-minute request cap. If you exceed it, the API returns 429 Too Many Requests. To make your app production-ready, use these four patterns to prevent this or handle errors when it happens:
  • Client-side caching for hot domains.
  • Backoff on 429, honoring the Retry-After header.
  • Prefetch to shift slow work ahead of bursts.
  • Tier-aware fallbacks when the limit holds.

Rate limits per plan

Rate limits apply per API key, are measured per minute, and are visible on your dashboard. The current tiers:
PlanCredits per monthRate limitOverage
Free500 one-time*10 requests/minNone
Starter30,000120 requests/min$19 per 10K credits
Pro200,000300 requests/min$9 per 10K credits
Scale2,500,0001,200 requests/min$6 per 10K credits
EnterpriseCustomCustomContact sales
* Free plan credits are a one-time grant, not a monthly allowance.
Logo Link and Prefetch endpoints do not have any rate limits.

What a 429 looks like

The API returns a JSON envelope:
{
  "status": "error",
  "message": "Rate limit exceeded",
  "code": 429,
  "key_metadata": {
    "credits_consumed": 0,
    "credits_remaining": 29940
  }
}
credits_consumed is always 0 on a 429 — throttled requests are never charged. Every 429 response also includes a Retry-After header with the number of seconds (1–60) until your per-minute window resets:
Retry-After: 23
Through an SDK, the error surfaces as a typed exception with status === 429. The SDK does not retry automatically. You wire that in.

Pattern 1: Client-side cache for hot domains

The cheapest way to stay under the cap is to skip the call. Brand data changes on the order of months, so a 24-hour client cache is safe for most products:
import ContextDev from "context.dev";

const client = new ContextDev({ apiKey: process.env.CONTEXT_DEV_API_KEY });

const CACHE_TTL_MS = 30 * 24 * 60 * 60 * 1000;
const cache = new Map<string, { data: unknown; at: number }>();

async function getBrand(domain: string) {
  const hit = cache.get(domain);
  if (hit && Date.now() - hit.at < CACHE_TTL_MS) return hit.data;

  const { brand } = await client.brand.retrieve({ domain });
  cache.set(domain, { data: brand, at: Date.now() });
  return brand;
}
Reasonable TTL starting points: 30 days for brand responses, 7 days for product extractions, indefinite for industry codes (NAICS / SIC). Adjust per use case.

Pattern 2: Backoff on 429 with Retry-After

When you hit rate limits, you get a 429 status code on the response:
{
  "status": "error",
  "message": "Rate limit exceeded",
  "code": 429
}
The response’s Retry-After header tells you exactly how many seconds until your window resets, so use it as the wait time when it’s present. Fall back to exponential backoff (wait 1 second before the first retry and double the delay on each subsequent attempt) if you can’t read the header. Here’s an example of a retry script that honors Retry-After and falls back to exponential delays:
async function retrieveWithBackoff(domain: string, maxAttempts = 4) {
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
    try {
      return await client.brand.retrieve({ domain });
    } catch (err: any) {
      if (err.status !== 429 || attempt === maxAttempts - 1) throw err;

      const retryAfter = Number(err.headers?.["retry-after"]);
      const delayMs = retryAfter > 0 ? retryAfter * 1000 : Math.pow(2, attempt) * 1000;
      await new Promise((r) => setTimeout(r, delayMs));
    }
  }
}

Pattern 3: Prefetch to shift slow work ahead of bursts

Bursty traffic (like when a marketing email triggers 200 signups in 60 seconds) can get you rate limited. Prefetching doesn’t reduce the number of Brand API calls that count against your limit; every user-facing /brand/retrieve still spends rate-limit budget. What it does is shift the slow crawl work earlier, so each call during the burst completes in under a second instead of stalling for up to a minute and piling up retries on top of an already-saturated window. Here’s how it works:
  • During the burst, your application calls /brand/prefetch (if it has a domain) or /brand/prefetch-by-email (if it has an email) right when it first receives the target domain or email. These prefetch endpoints are rate-limit-free, so 200 calls in a minute is fine.
  • A few seconds later, when the user actually submits and the user-facing client hits the Brand API, the request lands on a warm cache and returns in under a second. That call still counts toward your per-minute limit; it’s just fast.
See Prefetch for Faster Response for the full pattern.

Pattern 4: Degrade gracefully when the limit holds

If exponential backoff has run out of retries and you are still seeing 429s, the user is better served by a missing-data fallback than an error screen. Some examples:
  • Onboarding form. Skip the prefilled fields. Let the user enter them by hand and do not block on the API.
  • Logo wall. Render the customer’s name in a styled box instead of the logo.
  • CRM enrichment. Queue the contact for an offline enrichment job that runs overnight.
Build the fallback once and the end user never sees a rate-limit message.

Prefetch

Warm the cache so burst-time calls return fast.

Best practices

Cache, fallback, and proxy patterns end to end.

Troubleshooting

Other status codes, retry logic, and SDK gotchas.

Pricing

Per-plan credit, rate limit, and overage details.