Quota
Requests are metered per endpoint group, not per endpoint. Every response tells you
which group it spent from, in X-Quota-Group.
| Group | Endpoints | Request-metered |
|---|---|---|
current |
GET /stats/current |
yes |
history |
GET /stats/history (not yet shipped) |
yes |
metadata |
/ping, /openapi.yaml, /geo*, /coverage, /meta/filters, /usage |
no — uncounted |
reports |
POST /reports (not yet shipped) |
no — charged against your report allowance instead |
In practice: only the stats endpoints cost requests. Resolving a place, walking the geography, checking coverage, reading the filter vocabulary and asking what you have spent are all free.
Why discovery is free
This is a design decision, not an oversight.
Billing an agent for resolving a place before it can query one teaches it to guess place ids instead of looking them up — and a guessed id produces a confidently wrong answer rather than an error. The same applies to "can I still afford to call anything": a client that learns checking costs something stops checking.
So discovery, self-description and usage reporting are all uncounted. The expensive thing is the answer, not finding out how to ask for it.
Uncounted is not unlimited
A free group still has a per-minute burst limit. Exceed it and you get
429 rate_limited with a Retry-After header. Uncounted means "does not draw down your
cycle allowance", not "call it as fast as you like".
Reading the headers
Every response carries them.
| Header | Meaning |
|---|---|
X-Quota-Group |
which budget this request spent from |
X-Quota-Limit |
requests allowed this cycle — or the literal word uncounted |
X-Quota-Used |
spent this cycle, including this request. Absent on an uncounted group |
X-Quota-Reset |
when the cycle rolls, ISO 8601 UTC |
X-RateLimit-Limit |
requests per minute for this group |
X-RateLimit-Remaining |
requests left in this minute |
Retry-After |
seconds until the burst window rolls. Sent on 429 only |
Two of those are deliberately awkward, and both for the same reason.
X-Quota-Limit is the word uncounted, not a number. A client that parses it as an
integer fails visibly instead of quietly believing a ceiling nobody set.
X-Quota-Used is absent on an uncounted group, not 0. Zero would read as "you have
spent none of a real allowance", which is a different claim from "there is no allowance
here to spend".
X-Quota-Reset is the end of your subscription cycle, not the first of next month. It
is absent on an account whose balance is not anchored yet — absent rather than invented.
Checking your balance
/usage reports the token and one entry per group.
It costs nothing, so call it before a long run and after a burst.
The same figures are on the API tokens page of your InvestViews account — allowance used of limit per group, the reset date, and a 30-day chart of requests and refusals. Use the endpoint from code, the page when you just want to look.
curl -s https://api.investviews.ai/public/v1/usage \
-H "Authorization: Bearer {TOKEN}"
Three things about that response are worth knowing.
used and remaining include usage not yet committed to the billing row. Counting
happens in a fast store and is folded into the account balance periodically. Reading the
balance alone would show an account that just burned 400 requests as having spent none of
them — exactly the moment you are most likely to look. These figures subtract the
uncommitted delta, so they are the ones to trust.
The metadata group reports null limits, not 0. It is uncounted, and 0 would read
as "no allowance left", the opposite of the truth. The honest shape is metered: false with
a real rate_per_min.
degraded: true means the metering store was unreachable. The figures are then the
committed balance alone, missing this cycle's uncommitted usage. The API fails open in
that state — your requests are served, not refused.
When you run out
402 quota_exhausted means this cycle's request allowance for that group is spent. It is
not a credential problem: the token is fine, and Authentication
explains why that is a different code from subscription_inactive.
Uncounted groups keep working. You can still resolve places, check coverage and read
/usage after the metered allowance is gone — which is exactly when you need to.
Spending less
- Ask for the territory, not the cells. One
/stats/current?geo_id=call covers a whole place. Fetching the hex list first and then querying byh3=costs the same metered call plus your context. - Use the free endpoints to aim.
/coveragetells you whether a market has data before you spend a metered call finding out. - Cache the answer, not the question. A period is built monthly, so re-asking for the
same territory within a month returns the same figures.
as_oftells you when it would change.