Per-API-key usage budgets and threshold alerts
Every API key’s analytics drawer now carries a “Usage budget” card. Set a monthly request ceiling for that key and Devotel Orbit grades the key’s live 30-day usage against it — a caution badge once consumption crosses 80% of the ceiling, a “budget exceeded” badge once it reaches 100% — with a progress bar and “N of M remaining” headroom text. A runaway integration, or a leaked key, shows as a warning inside the dashboard instead of on the invoice. This works alongside the per-key rate limits and monthly request quotas documented in Per-API-key usage limits and spend alerts: that guide covers the org-wide and per-key hard limits; this one covers the lightweight per-operator dashboard alert you can set on any key without touching the org default.When to use a budget
Use it as an early-warning tripwire inside the dashboard — a budget does not block traffic (the hard quota in the usage-limits guide does that). Set it on keys where you want a badge at a known percentage of expected usage (a staging environment, a partner integration, a single high-volume sender).Walkthrough: the Usage budget card element by element
No screenshots needed — here is exactly what the drawer shows, in the order you meet it:- Open Settings → API keys in the dashboard and expand a key’s row. The analytic drawer that opens has three columns: Key details on the left, a seven-day usage chart plus top endpoints in the middle, and the key’s scopes on the right.
- At the bottom of the Key details column, under the created / expires / requests-today / last-used stats, a Usage budget heading opens the card.
- The card holds one numeric field with a gauge icon and the placeholder “Monthly requests (blank = off)”. Type a ceiling and leave the field — the value commits on blur, in whole requests.
- Type a zero, negative, or non-numeric value and an inline error appears: “Enter a positive whole number, or leave blank to clear.” The previous value is unchanged until you enter something valid.
- With a budget set, the card renders three readings and updates them immediately: a badge zone (a caution “Warning threshold reached” badge at 80% of the budget, a red “Budget exceeded” badge at 100%, or the “N of M remaining” headroom text below the warning band), a progress bar filled to the consumed share, and a caption reading “N% of budget used in the last 30 days”.
- If the 30-day spend data for the key is still loading (or the key’s row fell outside the analytics page’s ranked window), the caption instead reads “Spending data unavailable in this window.” and the bar renders as indeterminate — the badge never fabricates a 0%.
- To remove the budget, clear the field — blank commits as “off”. The page’s “N keys budgeted” summary pill scans your browser’s stored budgets, so it counts down as soon as you clear.
Known limitations
Budgets are opt-in operator preferences with a deliberately small blast radius: nothing is sent to the API, and a key with no budget behaves exactly as before. The trade-offs that design implies, in one place:- Browser-local storage. A budget is scoped to the browser profile that set it. It does not follow you to a second browser, a second machine, or a second operator’s session.
- No team visibility. Two operators looking at the same key see only their own threshold — your badge cannot fire in a colleague’s session, and theirs cannot fire in yours. There is no server-side view of “all configured budgets”.
- Advisory only. Crossed tiers flag the key in the dashboard; they never block traffic. Blocking belongs to the rate limit and monthly request quota in Per-API-key usage limits and spend alerts.
- Storage-dependent persistence. Clearing site storage, switching browser profiles, or running the dashboard where storage is denied (private/incognito window, storage-sandboxed iframe) removes or disables every budget you set; the dashboard then treats the key as unbudgeted.
- One denominator. The 30-day request count is the only signal. If you want an alert on delivery rate, outbound volume spikes, or spend in currency, use the threshold rules in Usage anomaly alert rules instead.
Failure-mode recipes
Each failure mode above has a usable workaround. Treat these as standard practice, not edge-case trivia. Recipe 1 — demoing the feature from a private window. Budgets commit on blur and hydrate from storage on mount, so a private/incognito window is a clean sandbox for showing the badge tiers to a colleague without disturbing your real thresholds. Expect the budget to vanish when the window closes; set the real budget back in your regular profile afterwards. Demoing the tiers in your regular profile instead only costs one re-entry of the original value, because blanking a field is the unset path. Recipe 2 — surviving storage clearing. If your team clears browser storage on a schedule (managed-browser policy, shared machine, privacy tooling), keep a one-line note of the keys you budget and their ceilings — a pinned team doc or a comment in your runbook is enough — and re-enter them after a wipe. The drawer’s “N keys budgeted” pill is your canary: when it reads lower than you expect, some budgets were wiped. For anything more durable, move the threshold to the API level (recipe 3 and the pairing example below), where storage clearing cannot touch it. Recipe 3 — standardizing thresholds across the team. Because budgets never sync, “everyone watches the same number” has to be done deliberately: publish the agreed ceiling for each watched key in your team docs, and have each operator set the same value in their own browser. That works while the set of watched keys is small and stable. The moment the watchlist grows — or a badge must reach people who never open the dashboard — move the threshold to the API-level usage-alert in Per-API-key usage limits and spend alerts, which every operator reading the governance endpoint sees identically. Keep the browser budget only as a personal early-warning layer on keys you alone care about.Worked example: pairing a browser budget with the API-level usage alert
The safest setup uses both layers at once: the API threshold is the team-visible tripwire, and your browser budget is a second, personal tripwire you can tune tighter without changing anything shared. Set the org alert threshold once:alerting: true in GET /api/v1/developer/governance once its quota usage crosses 80% — a fact any operator on the team can poll, independent of anyone’s browser state.
Layer the browser budget on top for earlier warning on the keys you personally watch. For example, a key with a quota of 500000 per month: the API threshold flags it at 400000 requests (80%). Set a personal budget of 100000 in the drawer and your own dashboard fires the caution badge at 80000 — five times earlier — while the team’s shared signal stays untouched. If the badge starts bothering you, clear the field; the API-level alert keeps running either way.
The two layers never conflict: the browser badge and the API alerting flag are computed independently, both floored to whole percents, and both advisory. Neither blocks traffic; reach for the monthly request quota when you want a hard stop.
Automate it: reading usage and setting a budget from the API
The drawer’s budget and badges are browser ergonomics. Underneath, everything you need to drive the same check from your own tooling — CI nightly checks, an internal usage page, a pager hook — comes from two endpoints the dashboard itself calls. Set a persisted per-key ceiling withPUT /api/v1/developer/budgets/{keyId} and read back the same usage rows the dashboard renders with GET /api/v1/developers/api-analytics/by-key.
Set a monthly request budget on a key
Pick the key’s id (from the drawer’s Key details column, orGET /api/v1/developer/budgets first) and push the ceiling:
- cURL
- Node.js (TypeScript)
Response (
200):
limit_minor: null.
Read the current 30-day usage
The badge and headroom text on the card are computed fromGET /api/v1/developers/api-analytics/by-key — the same endpoint the Developer → API analytics page and the drawer’s Requests-today row fetch. Each row carries count_today, count_7d, and count_30d, so getting the 30-day total the budget is graded against costs one call:
- cURL
- Node.js (TypeScript)
200, one row shown):
- Every response returns
dataplusmeta.request_id/meta.timestamp; thedatashape above is what aPUTwrite confirms and what aGETrow reports. - Rows keyed
__none__are unattributed (dashboard session traffic not attached to an API key);__deleted__:<id>are rotated-away keys kept whenincludeRevoked=true. Ignore them when computing per-key headroom. count_30dis always present regardless of thewindow/sortparams; sort only orders the returned rows.cost_month_minorisnullon the sentinel (unattributed/deleted) rows; never treat it as zero for headroom maths.
Browser budget vs API-level usage alert: when each suffices
Rule of thumb: a browser budget answers “am I about to blow through what I expected?”, the API-level threshold answers “are we?”, and the quota answers “should this stop?”.
Risk: browser-local storage
Because the budget lives in the browser, three failure modes matter for teams:- Threshold drift across the team. Two operators looking at the same key can have — and usually do have — different warning thresholds. Do not assume a colleague sees the same badge you do; they see only the budget set in their own browser.
- The budget does not survive the browser. Switching browser profiles, clearing site storage, or the dashboard being denied local storage (private/incognito window, storage-sandboxed iframe) wipes or disables the budget; the dashboard then treats the key as unbudgeted.
- A badge cannot fire for someone else’s session. When another operator’s browser session drives the traffic, your badge stays silent — the threshold in your browser does not travel.
Headroom maths
The badge tiers are computed from the same 30-day totals the API analytics page shows. Worked example — a key with usage of81234 against a budget of 100000:
- 30-day usage:
81234 usage_percent:81- Badge:
warning(at least 80% consumed) - Headroom text:
18,766 of 100,000 remaining
exceeded; the percentage is floored, so 79.9% still reports 79 and stays below the warning band.
What happens at the ceiling
The badge flips to “Budget exceeded” but traffic is not blocked — clear the budget to silence it, or raise it if the ceiling was genuinely too tight. If you want blocking, set the monthly request quota documented in Per-API-key usage limits and spend alerts.Edge behaviour
- A blank input clears the budget; a non-positive entry (zero, negative, or non-numeric) is rejected at input time.
- Fractional budgets round to whole requests (the 30-day count is a whole number, so a fractional ceiling would never map cleanly to a percentage).
- If browser storage is unavailable (private/incognito mode, a storage-sandboxed iframe), the budget still applies for the page lifetime but will not survive a reload; the dashboard falls back to treating it as unset.
- A key with no configured budget never emits a warning/exceeded badge — budgets are strictly opt-in.