# Rate limits

> Two different ceilings, the request rate and the plan's verification cap, plus the screenshot read allowance.

Two separate ceilings apply to every call, and they fail with different codes:

- **Request rate**, per key, per minute. Protects the service from a hot loop.
- **Verification cap**, per plan, per window. Counts only receipts we fetched
 from a bank and delivered to you. This is the one tied to what you pay.

A third, the **screenshot read allowance**, applies to `POST /api/verify-image`
only.

## Request rate

Every key has a per-minute budget, **60 requests/minute** by default. Each
request increments a bucket keyed on the current minute. Go over it and the
rest of that minute returns `429 rate_limited` with a `Retry-After` header
holding the seconds until the next minute boundary.

The limit is stored per key, so it can be raised on one key without touching
the others. Ask if 60 is not enough.

## Verification cap

Only **uncached, successful** verifications count. Two things are always free:

- **A receipt we have already fetched.** It is served from cache, costs us
 nothing, and never counts however many times you ask for it.
- **A verification that failed.** A timeout, a bank that is down, a receipt we
 could not parse — none of it touches your cap. You are charged for receipts
 delivered, not for attempts, and never for our own bad days.

That is why these numbers can be stated plainly rather than hidden behind a
fair-use asterisk.

| Plan | Uncached receipts | Window | Over the cap |
| ---------- | ----------------- | -------------- | --------------------- |
| Free | 200 | calendar month | Hard stop |
| Shop | 2,000 | day | Hard stop |
| Developer | 30,000 | calendar month | 0.05 ETB each, opt-in |
| Scale | 150,000 | calendar month | 0.03 ETB each, opt-in |
| Enterprise | Per contract | calendar month | 0.03 ETB each, opt-in |

Overage is **off by default on every plan that offers it**. Until you turn it
on from the dashboard, passing the cap stops the call rather than billing you
for it. Free and Shop have no overage path at all.

Passing the cap returns `429 quota_exceeded`, not `rate_limited`. The body
carries `used` and `cap`, and `Retry-After` holds the seconds until the window
rolls over:

```json
{
	"ok": false,
	"error": {
		"code": "quota_exceeded",
		"message": "Plan 'Free' allows 200 new (uncached) verifications per month. Cache hits and failed lookups are always free. Upgrade or enable overage to continue.",
		"used": 200,
		"cap": 200
	}
}
```

Waiting out a `rate_limited` takes seconds. Waiting out a `quota_exceeded` can
take until the end of the month, so treat them differently in your retry code.

## Screenshot reads

`POST /api/verify-image` runs the image through an AI extractor before it can
verify anything, and that call costs us money whether or not the receipt turns
out to be cached. It gets its own allowance, counted **per calendar month on
every plan**, whatever window that plan's verification cap uses:

| Plan | Screenshot reads / month |
| ---------- | ------------------------ |
| Free | 200 |
| Shop | 1,000 |
| Developer | 2,000 |
| Scale | 6,000 |
| Enterprise | Per contract |

There is no overage path here: reaching the allowance returns
`429 image_cap_reached` until the month rolls over. Reading a screenshot is
independent of verifying the receipt it contains, so a read that resolves to
an already-cached receipt still spends one read and no verification.

## Priority

When a bank is saturated and calls have to queue, the plan decides who is
served first: Scale and Enterprise, then Developer, then Shop and Free. Priority
changes your position in the queue, never your cap.

## Anonymous demo

The landing page demo takes no API key and is metered per IP, not per account:
**10 verifications and 3 screenshot reads per hour**. It exists so you can try
the thing before signing up. Anything built against it will stop working.

## Raising a limit

Email [robelmezemir@gmail.com](mailto:robelmezemir@gmail.com) with your key
prefix and what you are building. Request rate and Enterprise caps are set per
key; plan caps move by changing plan.
