API governance console
The Developer → API governance page is the only surface in the dashboard that lets you both watch every API key’s live usage and change the limits that gate it — one screen, no separate analytics pane or support ticket. This guide walks the console end to end: what it governs, how enforcement works, the safe view-then-write flow, the pre-flight API check, and the429 shapes your integration can raise back.
You need the owner, admin, or developer role to write. The same roles gate the underlying API (/api/v1/developer/governance), so whoever can open the page can also drive it from a script.
What the console governs
The console reads one org-wide tier plus any per-key overrides and reports live usage per key:- Requests per minute (rate limit). Per-minute throughput. An over-rate key gets
429until the window rolls over — its own window, not the whole org’s. - Monthly request quota. A hard ceiling per UTC month. Cross it and every further call returns
429until the 1st. - Monthly spend limit. A token-level budget in integer cents. Useful for capping a runaway key’s month-to-date spend before it runs into your wallet.
- Usage-alert threshold. An advisory percent of the monthly quota. Crossing it only flags the key in the console — it never blocks traffic.
How the console enforces a tier
The console is a cache-backed read-modify-write overorganizations.settings.api_governance. Enforcement is an explicit three-step resolve on every request:
- Per-key override wins. If the key has a non-
nullfield in its override, that value gates the key for that dimension. - Org-wide default fills the gap. Any dimension the override leaves
nullfalls through to the org tier. - Platform floor. A dimension with no override and no org default resolves to the platform’s built-in bound — generous by design, so a well-behaved key never notices.
GET response separates the three — override (what you wrote), org_default (the org tier), and effective_limits (the actual values gating the key after the resolve). Read effective_limits before you trust what your key is doing.
Why explicit beats inherit-on-default
An unset field means “inherit platform” — convenient for a key you minted before you set governance, dangerous once you have a real ceiling in mind. Platform caps are deliberately generous (up to 60,000 requests/minute and 1,000,000,000 requests/month), so “inherit” practically means “unlimited.” Setting a number explicitly gives you an enforced bound; trusting the default gives you a suggestion.Why the guard wraps before Redis
The rate guard is deliberately fail-open on store errors: if the Redis cache used for the sliding per-minute window has a blip, the guard lets the request through rather than 5xx-ing a paying integration. The guard’s own try/catch also short-circuits disabled configs (DEVOTEL_RATE_LIMIT_API_KEY_PER_MINUTE=0) before any Redis round-trip, so a deliberate “no per-key cap” costs nothing.
View and update flow
Follow this order — the page works the same way:1. Open the page and read the org default
The Org-wide default card is shown first so a baseline is always visible before any per-key work. Values of0 are rejected at write time (a zero cap would hard-block the key; revoke it instead). Leave a field blank to clear that setting back to the platform default.
- Open Developer → API governance.
- In the Org-wide default card, set the fields you want — requests per minute, monthly request quota, and/or the usage-alert threshold.
- Save. Only the fields you touch change; a blank field clears that setting.
2. Pick a key and set a per-key override
- In the per-key table, find the key and click Set override (or Edit override on a key that already has one).
- Enter a requests-per-minute value, a monthly quota, or both. Leave a field blank to inherit the org default for that dimension.
- Save. To remove the override entirely, clear both fields and save — the key goes back to the org default.
3. Read the effective limits back
The table combines what you wrote (override), what the org provides (org_default), and the resulting effective_limits per key. Use Refresh usage to pull the latest counters on demand — the page intentionally skips a busy background poll and relies on a short staleTime plus a manual refetch so the “refresh” call stays cheap.
If your workspace has more than 250 active keys, the table hydrates the newest 250 and the page tells you it was truncated. Drive the same operations through the API (PUT /api/v1/developer/governance/keys/:keyId) or revoke dormant keys to get back under the cap.
Pre-flight with the API
The console’s reads and writes map one-to-one onto the API. Do aGET before any change to confirm what you expect, then write, then GET again to verify the effective limits.
- Is the key listed? The read hydrates at most 250 keys —
keys_truncated: truemeans the page cut the list and you should drive the API or revoke dormant keys. - Is its
effective_limitswhat you expected? If it shows a value you didn’t set, someone else changed the org default — readorg_defaultfirst. - Is
overridenon-null? Writing to a key already carrying an override still overwrites it; the same tier always wins, field by field.
null on a field to clear it (the org tier fills the gap for that key; the platform default fills it for the org). Both writes are audit-logged (developer.api_governance.org_updated, developer.api_governance.key_updated), so the audit log records who changed what.
A rate-limit planning checklist
Before you save the org tier, confirm:- What’s your current usage? Read the This minute and This month counters on the busiest key — the org tier must be at least that, headroom included.
- What’s the noisy-neighbor argument for a tighter per-key lid? A stuck retry loop or a leaked credential should burn through that key’s own window, not the org’s.
- What’s the smallest quota that fits your monthly calendar? The monthly window resets on the 1st (UTC) — pick a quota shaped to months, not to arbitrary rolling windows.
- Which threshold should flag the key? A whole-percent advisory line (1–100) — set it low enough that an alert lands before the quota locks the key.
- Does any key deserve an explicit override? Only if one integration needs room the rest of the org doesn’t. Prefer the org tier; overrides multiply places you have to remember.
429 shapes to expect
Two distinct429 codes come back — read the code, not the HTTP status:
429 RATE_LIMIT_EXCEEDED. Per-minute window exceeded.Retry-After: 60plusdetails.limit,details.used, and thedetails.window: "1 minute"hint tell the client exactly how to back off.429 QUOTA_EXCEEDED. Monthly request quota crossed. Retry when the month resets (UTC) or after raising the quota.
429 — it only sets alerting: true in the console and the API read. If a well-behaved integration is suddenly seeing 429, check whether an over-quota or over-rate verdict is real before assuming a misconfiguration.
Troubleshooting
A key shows Over quota and gets429. Its month-to-date count passed the effective monthly quota. Raise the quota (per-key override, or the org default) and the very next request succeeds — there is no cache TTL to wait out. To stop the key entirely, revoke it on Developer → API keys.
A key is flagged as alerting but nothing is blocked. That is the usage-alert threshold doing its job. Alerting is advisory only; raise the quota or let the month reset.
Save succeeded but the key still hits the old limit. Re-check the per-key table: the effective limits column is what actually gates the key. A row whose override you “cleared” by blanking only one dimension still inherits the org default for the other. If the counter itself looks stale, hit Refresh usage.
The write returned 422. The value was out of range — allowed bounds are listed on the Org-wide default card, and zero is always rejected. Blank the field (inherit) or send a positive integer.
The write returned 404. The /keys/:keyId write only touches keys that belong to your org. Check the api_key_id, not the display name.
The API returned a different org_default than the dashboard shows. Refresh the page — the dashboard reads are cached briefly to keep the page responsive. The API read is source-of-truth because it bypasses the cache for writes and resolves the live config.
Permissions and audit
Reads and writes on this page require the owner, admin, or developer role; the same roles gate the API endpoints. Give the page to whoever owns your API keys — usually one or two admins — and keep rotating viewers on the read-only API analytics dashboard, where the viewer role can watch throughput and error breakdowns without touching a limit. Every change writes an audit entry with the acting user, the new values, and (for per-key writes) whether the override was cleared. Filter the audit log on theapi_governance resource.