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 have to fetch from a bank. 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 verifications count. A receipt we have already fetched is served from cache, costs us nothing, and never counts however many times you ask for it. 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:
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 with your key prefix and what you are building. Request rate and Enterprise caps are set per key; plan caps move by changing plan.