Skip to main content

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).
Budgets are stored in your browser, not on the API. The threshold you set is held per-browser, per-workspace, and is never sent to the API or shared with your team. Two operators looking at the same key see only their own threshold. For an alert the whole team sees, pair this with the API-level usage-alert threshold from Per-API-key usage limits and spend alerts. The failure modes this implies are expanded in Known limitations below.

Walkthrough: the Usage budget card element by element

No screenshots needed — here is exactly what the drawer shows, in the order you meet it:
  1. 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.
  2. At the bottom of the Key details column, under the created / expires / requests-today / last-used stats, a Usage budget heading opens the card.
  3. 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.
  4. 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.
  5. 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”.
  6. 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%.
  7. 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.
None of these are blocking defects — they are the shape of a per-operator tripwire. Pair a browser budget with an API-level control whenever the alert must be shared, as the pairing example below shows.

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:
Now every key with a monthly quota flags 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 with PUT /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, or GET /api/v1/developer/budgets first) and push the ceiling:
Request body — the cURL payload above is the exact shape: Response (200):
Clear it with limit_minor: null.

Read the current 30-day usage

The badge and headroom text on the card are computed from GET /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:
Response (200, one row shown):
Notes on the response envelope:
  • Every response returns data plus meta.request_id / meta.timestamp; the data shape above is what a PUT write confirms and what a GET row reports.
  • Rows keyed __none__ are unattributed (dashboard session traffic not attached to an API key); __deleted__:<id> are rotated-away keys kept when includeRevoked=true. Ignore them when computing per-key headroom.
  • count_30d is always present regardless of the window/sort params; sort only orders the returned rows.
  • cost_month_minor is null on 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.
Budgets set in your browser are a useful tripwire for your own checks, but always pair them with the API-level usage-alert threshold from Per-API-key usage limits and spend alerts when alerting must be shared across the team. The recipes above give the working pattern for each of these failure modes.

Headroom maths

The badge tiers are computed from the same 30-day totals the API analytics page shows. Worked example — a key with usage of 81234 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
Add 18,767 more requests and the badge flips to 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.

Troubleshooting

Badge never fires. Check each of these three causes in order: the budget is genuinely set in your current browser (a cleared field means no budget); browser storage is available (a private window or storage-denied browser silently discards it on reload); and usage totals have finished loading (a still-loading total never fabricates a badge). Badge fires for one operator only. Expected — thresholds are per-browser. To live-monitor the key for the whole team, use the API-level usage-alert threshold in Per-API-key usage limits and spend alerts. The budget was cleared but the old warning still shows. Rarely this is a storage sync lag — force-reload the page. If it persists, your browser is denying storage access, so the “cleared” budget never persisted in the first place. The “N keys budgeted” pill reads lower than it should. One or more stored budgets were wiped — usually by clearing site storage or switching browser profiles. Re-enter the ceilings from your team note (see the storage-clearing recipe above), or move the watchlist to the API-level threshold so a wipe cannot touch it.

Recommendation

Use browser budgets as a quick tripwire within your own session, and keep a team note of what you set so a storage wipe is a re-entry, not a loss. For alerting that the whole team sees, set the org-wide usage-alert threshold. For actual blocking, set a monthly request quota. Both cross-operator controls live in Per-API-key usage limits and spend alerts — pair this guide’s per-browser badges with that guide’s shared thresholds, using the decision table above to choose per situation.