Documentation

Rate limits and quotas

Per-endpoint limits, headers, and what happens when you exceed them.

What FlowFinds enforces is a credit meter on AI-backed features, not a requests-per-second limit on the HTTP surface. Reading your dashboard, your store, your orders or your support desk draws nothing. Spawning a model does.

Two things follow that will matter to your client. There is no per-endpoint request rate limit and no X-RateLimit-* response header — the allowance is a JSON endpoint, not a header, and this page does not invent numbers for limits the server does not enforce. Everything below is what the meter actually holds.

How the meter works

  • Credits, with a per-action rate card. Each metered action costs a fixed number of credits. Costs are relative to each other, not to a currency: a website edit spawns a full agentic run and is fifty times a support answer.
  • One bucket per feature. Feature allowances are not pooled. Exhausting the website editor leaves the find engine untouched, so a limit you hit never reads as an account-wide outage.
  • Two nested windows. A rolling five-hour allowance and a weekly cap. A five-hour window alone lets a month of spend go in a weekend; a weekly cap alone gives no back-pressure inside a session.
  • Fixed windows, not sliding. A window is an integer boundary, so a single row records it and nothing has to expire. The cost is that arriving late in a window means it resets sooner — the direction that favours you.
  • The subject is the account, not the cookie. Clearing a cookie does not mint a fresh allowance for an address we already know.
  • Checking never spends. GET /api/usage reads the meter without consuming it. The gate itself is called immediately before the expensive call, never at route entry, so a refusal can never have already paid for a model run.

The rate card

Cost is what one action draws. The limits shown are the Pro tier’s baseline.

BucketFeatureCostPro / 5hPro / weekGates
website_editAI website editor501,00010,000POST /api/ai/edit
growth_editAI Growth ad editor205005,000POST /api/growth/edit
findProduct find engine55005,000GET /api/find, GET /api/feed
adAd generation105005,000the ad artifact build
supportSupport agent15005,000the store's support answers

Tiers

Every tier is a multiplier over Pro, which is 1.0 by definition — there is one set of numbers, and the ladder scales it. What each tier costs is on the pricing page, which is authoritative for money; this page is authoritative for allowances.

TierMultiplierAI website editor / 5hAI Growth ad editor / 5hProduct find engine / 5hAd generation / 5hSupport agent / 5h
freeFree0.1×10050505050
proPro1×1,000500500500500
max5Max 5x5×5,0002,5002,5002,5002,500
max20Max 20x20×20,00010,00010,00010,00010,000

Read those as actions rather than credits and the shape is clearer. On Free, a five-hour window is two website edits, two Growth ad edits, ten finds, five ad generations, or fifty support answers — enough to feel the product work on your own store, not enough to run a business on. An unknown or expired-term account reads as Free; Free is not a trial and has no end date.

The referral multiplier

Qualified referrals scale your limits, on every tier including Free, across every feature at once. Scaling costs instead would make the bonus quietly bucket-specific.

Qualified referralsMultiplier
01.0×
12.0× — it doubles
22.5×
33.0×
43.5×
5 or more4.0× — the cap

After the first, each referral adds 50% of base, additively rather than compounding, and the ladder stops at 4×. Compounding would reach a paid tier’s allowance free at the eighth friend, and uncapped, the cheapest route to unlimited AI would be a referral farm rather than a subscription.

Qualified is not invited and not clicked. The friend has to really join and reach the dashboard — an observed milestone, not an inferred one. See Concepts.

Reading your allowance

curl -b ff.jar https://flowfinds.ai/api/usage

Every bucket is returned every time, never only the exhausted one. Per feature you get cost, used_5h, limit_5h, used_week, limit_week, resets_at_5h and resets_at_week (epoch seconds), allowed, and exhausted_window "5h", "week" or null.

Two multipliers are returned and they are not interchangeable. multiplier is what the limits were actually scaled by (tier × referral). referral_multiplier is the part you earned by inviting people, and it is the only one referral copy may quote. Showing the first under the second’s label once told a Free founder with no referrals that their referral multiplier was 0.1×.

What exceeding a limit looks like

Exhaustion is answered with HTTP 429 and a body that names the feature, the window, and the exits:

HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Cache-Control: private, no-store, must-revalidate

{
  "status": "refused",
  "reason": "usage_limit_reached",
  "explanation": "You have used your AI website editor allowance for now.",
  "feature": "AI website editor",
  "used": 100,
  "limit": 100,
  "resets_at": 1756900800,
  "tier": "free",
  "unaffected": ["AI Growth ad editor", "product find engine", "ad generation", "support agent"],
  "ways_up": [
    { "how": "referral", "detail": "Bring one founder who really joins and your limits double. Every one after that adds 50%.",
      "your_referrals": 0, "your_multiplier": 1.0, "cap": 4.0 },
    { "how": "upgrade", "detail": "Pro is 10x Free. Max is 5x or 20x Pro." }
  ]
}

reason is usage_limit_reached for the five-hour window and weekly_limit_reached for the weekly cap. Branch on that, not on the prose. resets_at is epoch seconds and is the only correct thing to back off until — there is no Retry-After header on this response.

unaffected is not decoration. It names the features you can still use, so a client never tells someone their account is spent when one bucket is. Render it.

Handling it in a client

import time, requests

def call(session, method, url, **kw):
    r = session.request(method, url, **kw)
    if r.status_code != 429:
        return r
    body = r.json()
    if body.get("reason") == "weekly_limit_reached":
        raise RuntimeError(f"{body['feature']}: weekly allowance spent")
    wait = max(0, body["resets_at"] - time.time())   # epoch seconds, not a header
    time.sleep(wait + 1)
    return session.request(method, url, **kw)

Do not blind-retry a 429 on a schedule of your own: the five-hour window can be nearly a full window away, and the weekly cap should be surfaced to a person rather than waited out. Before an expensive call, prefer reading /api/usage and checking allowed.

Limits that are not the meter

A handful of endpoints enforce their own ceilings, and they are not usage credits: product image uploads larger than the editor accepts are refused with 413 and images_too_large; advertising top-ups are bounded by a served min_minor and max_minor; and the number of products you may claim is an allowance, answered as claim_limit_reached rather than as a rate limit, because one action lifts it.

Next: Errors · Troubleshooting · API reference