Skip to main content
The Black Hair API uses a tiered API key system to control access and rate limits. Every API key belongs to one of four plans: Starter, Growth, Pro, or Enterprise. Your plan determines how many requests you can make per month, how many you can make per minute, and which endpoints are available to you. Rate limits are enforced independently at two levels — per-minute bursts and monthly totals — so you can hit a per-minute limit without affecting your monthly quota, and vice versa.

Plans

PlanMonthly RequestsPer-Minute LimitFeatures
Starter1005Products, Brands, Ingredients lookup
Growth10,00060Everything in Starter + Reformulation Alerts
Pro100,000120Everything in Growth + AI Recommendations
EnterpriseUnlimited1,000Everything in Pro + Priority support

Starter

100 requests / month · 5 req/minThe Starter plan is designed for prototyping and personal projects. You get full access to product search, brand listings, and ingredient lookups. Ideal for validating your integration before committing to a paid tier.

Growth

10,000 requests / month · 60 req/minGrowth is for production applications with moderate traffic. It adds Reformulation Alerts — webhooks that notify your application when a product’s ingredient list changes — helping you keep your users informed about formula changes.

Pro

100,000 requests / month · 120 req/minPro unlocks the AI Recommendation engine (POST /v1/recommend/), which uses vector similarity search and GPT-4o-mini re-ranking to surface personalised product matches based on hair type, porosity, and concerns.

Enterprise

Unlimited requests / month · 1,000 req/minEnterprise is built for high-traffic platforms and marketplaces. Unlimited monthly requests, a 1,000 req/min burst ceiling, and dedicated priority support. Contact us to discuss custom SLAs and data agreements.

Rate limit headers

Every API response includes metadata about your current rate limit state. The two limits operate as independent gates:
  • Per-minute limit — enforced using a sliding 60-second window. If you exceed your plan’s per-minute ceiling, the API returns 429 immediately. The retry_after_seconds field in the error body tells you exactly how many seconds remain until the window resets.
  • Monthly limit — a cumulative counter that increments with every successful request. Once you reach your monthly cap, every subsequent request returns 429 until the counter resets on the 1st of the following month.
A 429 response body looks like this:
{
  "error": "rate_limit_exceeded",
  "message": "Too many requests. Your growth plan allows 60 requests per minute.",
  "retry_after_seconds": 34
}
Monthly request counters reset on the 1st of each calendar month at 00:00 UTC. The reset is automatic — you do not need to take any action.
Once you reach your monthly cap, all requests are rejected until the counter resets, regardless of your per-minute headroom. If your application is approaching its monthly limit, upgrade your plan before the cap is hit to avoid service interruption.

Feature availability by plan

FeatureStarterGrowthProEnterprise
Product search
Brand listing
Ingredient lookup
Reformulation alerts
AI recommendations
Priority support
Calling an endpoint that is not available on your current plan returns a 403 Forbidden response:
{
  "detail": "The recommendation engine requires a Pro or Enterprise plan."
}

Upgrading your plan

1

Open a Stripe Checkout session

Send an authenticated POST request to /v1/stripe/checkout to generate a Stripe Checkout URL for your desired plan. Redirect your user (or yourself) to that URL to complete the upgrade. Your API key’s tier is updated automatically once payment is confirmed.
2

Confirm your new tier

After upgrading, make any authenticated request and check the response. Your new monthly limit and per-minute ceiling take effect immediately — there is no grace period or delay.
3

Enterprise inquiries

For Enterprise plans, custom rate limit configurations, or volume pricing, contact us at support@blackhairapi.com rather than going through the self-serve Stripe flow.

Handling 429 errors

Build retry logic into your integration from day one. The example below shows a simple exponential-backoff strategy in JavaScript and Python.
async function fetchWithRetry(url, options, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    const response = await fetch(url, options);

    if (response.status !== 429) {
      return response;
    }

    const body = await response.json();

    // Respect the retry_after_seconds field for per-minute limits
    const retryAfter = body.retry_after_seconds ?? Math.pow(2, attempt + 1);

    console.warn(
      `Rate limited. Retrying in ${retryAfter}s (attempt ${attempt + 1}/${maxRetries})`
    );

    await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000));
  }

  throw new Error("Max retries exceeded after repeated 429 responses");
}

// Usage
const response = await fetchWithRetry(
  "https://api.blackhairapi.com/v1/recommend/",
  {
    method: "POST",
    headers: {
      "Authorization": "Bearer bha_your_api_key",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      hair_type: "4C",
      porosity: "high",
      concerns: ["dryness", "moisture"],
    }),
  }
);
If your integration makes bursts of requests (for example, enriching a batch of products on import), add a small delay between requests to stay within your per-minute limit. For a Growth plan at 60 req/min, spacing requests 1 second apart keeps you safely under the ceiling.