Usage, quotas and rate-limit semantics
GET /v1/account/usage
Reads your account’s current request-unit usage for the active billing period.
This endpoint is Session-authenticated only — an API-key holder
cannot call it directly over REST. If your integration uses an API key
(not a human session), read usage programmatically via the
get_usage MCP tool → instead, which is
API-key-authenticated and returns the byte-identical response shape.
Auth
Authorization: Session <token> — required.
Missing/invalid/expired session → 401 unauthorized:
{ "code": "unauthorized", "message": "Authentication required.", "request_id": "..." }Success — 200
curl https://your-getratesapi-host/v1/account/usage \
-H "Authorization: Session gra_sess_0000000000000000000000000000000000000000000"const res = await fetch("https://your-getratesapi-host/v1/account/usage", {
headers: {
Authorization: "Session gra_sess_0000000000000000000000000000000000000000000",
},
});
const usage = await res.json();{
"plan": "free",
"billing_period": { "start": "2026-10-01T00:00:00Z", "end": "2026-11-01T00:00:00Z" },
"usage": {
"used_units": 123,
"quota_units": 500,
"remaining_units": 377,
"utilization": 0.246
}
}utilization is a pre-rounded ratio (4 decimal places) computed
server-side — never recompute it client-side.
The response always sends Cache-Control: no-store.
Failure
503 temporarily_unavailable on entitlement/storage failure.
Usage history
GET /v1/account/usage/history?days=30 (Session required) powers the
charts in the dashboard. days is 7–90 (default 30). Every day in the
window and every hour of the last 24 hours is present, zero-filled, so a
chart needs no gap handling. Times are UTC.
curl "https://your-getratesapi-host/v1/account/usage/history?days=7" \
-H "Authorization: Session gra_sess_0000000000000000000000000000000000000000000"{
"days": 7,
"from": "2026-10-10T00:00:00Z",
"to": "2026-10-16T18:55:02Z",
"total_units": 44,
"daily": [
{ "date": "2026-10-16", "units": 44, "by_endpoint": { "rate": 26, "rates": 8, "convert": 10 } }
],
"hourly": [
{ "hour": "2026-10-16T18:00:00Z", "units": 44 }
],
"by_endpoint": [
{ "endpoint": "rate", "units": 26 },
{ "endpoint": "rates", "units": 8 },
{ "endpoint": "convert", "units": 10 }
],
"by_key": [
{ "key_id": "e2317be7-c508-4e0c-b620-821e4c722dbe", "name": "Website", "key_prefix": "gra_live_fb7318ed", "revoked": false, "units": 34 },
{ "key_id": null, "name": "", "key_prefix": "", "revoked": false, "units": 8 }
]
}(daily and hourly are shortened here.) endpoint is rate (single
pair), rates (multi-quote), convert, mcp, or other for usage
recorded before endpoint tracking existed. A by_key entry with
key_id: null is usage from a key you have since deleted. by_key lists
the top 10 keys.
Billing periods and long terms
The quota is monthly. On a 3-, 6- or 12-month plan the allowance resets every month from the day the term started, so a yearly Developer plan gets 50,000 requests each month, not 600,000 for the year. A paid upgrade raises the current month’s quota immediately.
Request-unit quota vs. auth rate limiting — two different 429 causes
There are two unrelated mechanisms that can return HTTP 429. Always
distinguish them by code, never by status code alone:
code | Where it happens | Meaning |
|---|---|---|
quota_exceeded | current-rate endpoint, MCP get_rate/convert_currency | Your billing-period request-unit quota is exhausted |
too_many_requests | register, login, password-reset/verification-resend only | A separate, fixed-window IP+email abuse budget on auth endpoints has been exceeded |
The auth-abuse rate limiter has nothing to do with your request-unit quota — hitting one never affects the other.