Read the quota
https://api.granska.cloud/v1/quotasReads this tenant's run limit, what it has spent this period, and when the period resets.
Reading the counter without touching it
limits is what your tenant is allowed per period; usage is where it currently stands.
resetAt is a Unix timestamp in seconds — the instant the period turns over — and periodKey
names the current period, so a client can tell "the counter went up" from "the period rolled".
This call spends nothing. Poll it as often as you find useful.
Only POST /v1/analyze and POST /v1/action spend runs.
Everything else in the API is free, including this endpoint, listing sources and reading a finished
job.
The three configuration limits
profiles is how many profiles your organisation holds and how many it may hold. Creating one past
the ceiling is a 409; editing the ones you have is never affected, so an organisation that is at
or above its ceiling keeps working on everything it already built.
snippets is the same pair for the legal sources your organisation authored — the ones you wrote,
never the ones you inherit from us, which are uncounted and unlimited. It behaves exactly like
profiles: past the ceiling, POST /v1/snippets is a 409, and
editing what you already hold is never refused. Sources are deleted in the admin panel, so this is
the number to watch before a bulk import.
configWrites is a floor against runaway clients, not a plan allowance — do not design against
it and do not price against it. Five calls tick it, per hour:
POST /v1/profiles,
PATCH /v1/profiles/:id,
POST /v1/snippets,
PATCH /v1/snippets/:id, and
GET /v1/laws/:jurisdiction/:work — that last one only when it has to fetch a
law the library did not already hold, never when it answers from the library. The floor is set where
no human and no scheduled integration reaches it, and it spends no runs: reorganising your
profiles never costs you an analysis you paid for. If you have a legitimate reason to write more,
tell us and we raise the number for your organisation.
curl https://api.granska.cloud/v1/quotas \
-H "Authorization: Bearer $TOKEN"{
"limits": {
"maxRunsPerPeriod": 500,
"periodType": "MONTH"
},
"usage": {
"usedRuns": 13,
"remainingRuns": 487,
"resetAt": 1786838400,
"periodKey": "MONTH_2026-8"
},
"profiles": {
"stored": 6,
"max": 50
},
"snippets": {
"stored": 34,
"max": 400
},
"configWrites": {
"used": 2,
"max": 60,
"remaining": 58,
"resetAt": 1786838400
}
}The rate-limit headers are not here
This is the endpoint integrators most expect to find X-RateLimit-Limit and its two siblings on, and
it is the one endpoint that does not set them. They appear on the seven calls that are metered:
POST /v1/analyze and POST /v1/action, which spend runs; POST /v1/profiles,
PATCH /v1/profiles/:id, POST /v1/snippets and PATCH /v1/snippets/:id, which tick the hourly
write floor; and
GET /v1/laws/:jurisdiction/:work, which ticks that same floor when it has to
fetch a law the library did not hold. Nowhere else.
Read the limits from this body, and read the headers off those seven. On a write route the headers describe the write floor, not your run quota: the two counters never touch.
A rejected request on one of the first six has already been charged, so the headers on a 400 are
telling you the truth about what it cost. The law route is the exception in both directions — it
reports the floor even when the call is free, and a request it refuses on its way in carries no
headers at all. See Errors.
Errors
| Error | When |
|---|---|
401UNAUTHORIZED | The Authorization header is missing, is not a readable bearer token, or names no tenant. |
401TOKEN_EXPIRED | The access token was issued by this gateway and has since expired. Not probed: it needs a token older than its own lifetime. |
500INTERNAL_ERROR | An unexpected server-side failure. Not probable from outside — reaching it means something is wrong. |
Send it without writing a client
If your organisation already has an account, an administrator can read the current quota from the API
tester at /admin/api-tester.