Platform
Governance and alerts
Control which keys, models, providers and data reach your AI providers, cap monthly spend, and get told when spend, policy or shadow AI needs attention: Governance, Monitors, notification channels and the Inbox.
Blocked or detected
A request that goes through the Router, or through governance preflight, is checked before the provider is called and can be blocked. Usage that reaches Token Meter any other way (the SDK, OpenTelemetry, provider usage feeds) has already happened, so a violation is only detected: Token Meter alerts, opens a ticket and, if you opt in, revokes the credential.Who can use it
| Area | Where | Who |
|---|---|---|
| Overview, Access, Guardrails | Governance | Owners and admins, team workspaces |
| Keys | Governance › Keys | Team leads, admins and owners. A team lead sees and manages only keys assigned to a team they lead. Read API keys are owners and admins only. |
| Budgets | Governance › Budgets | Team leads can view. Only owners and admins can create, change or delete budgets and channels. |
| Data, Audit log | Governance › Data, Governance › Audit log | Owners and admins, team workspaces |
| Shadow AI | Governance › Shadow AI | Owners and admins, team workspaces |
| Monitors, notification channels | Monitors, Settings › Notifications | Owners and admins |
| Inbox | Inbox | Anyone who can open at least one of Monitors, Guardrails or Shadow AI; each sees only the items from the pages they can open |
The Governance tabs you cannot open are hidden. A team lead who opens Governance lands on the first tab they can use.
Governance › Overview has one row per control (API keys, Model access, Guardrails, Data retention) with its current state, and a Monthly budget line. Each row links to the tab where it is changed.
Ingest keys
Ingest keys authenticate the SDK, OpenTelemetry and the Router. Each key can carry a default environment and, in team workspaces, a default team, which are applied to the usage it reports.
Create a key
- Open Governance › Keys and choose Create key.
- Enter a Name (for example
prod-api), and optionally an Environment and a Team. - Choose Create key and copy the key. It is shown once; only its prefix and a hash are kept.
The table shows each key's prefix, environment and team, Created, Last seen, Expires and status (live, revoked or expired).
Rotate without downtime
Choose Actions › Rotate on a live key. Token Meter mints a second live key under the same name, with the same environment and team. Both keys work until you revoke the old one, so you can roll the new key out first. A name can have at most two live keys; to rotate again, revoke the older one first.
Revoke
Choose Actions › Revoke and type the key's name to confirm. The key stops working straight away and cannot be restored: the SDK gets 401, and Router and preflight calls made with it are refused.
Read API keys
Owners and admins can also create read keys with Create read key. A read key can only read daily usage summaries from /api/v1/usage/daily; it cannot send or change usage. Keep read keys separate from ingest keys. See the Read API reference.
Access policies
Access policies decide which models and providers may be called, which data classes may be sent, and how large or expensive a single request may be. Manage them in Governance › Access.
Create a policy
- Choose Add policy.
- Enter a Policy Name.
- Choose a Team Scope (Global (All Teams), or one team) and an Environment (All Environments, Production, Staging or Development).
- Pick any of:
- Allowed Models: only these models may be used. Leave empty to allow all.
- Blocked Models: these models may not be used.
- Providers: click a provider once to allow only the providers marked green, twice to block it (red), a third time to clear it.
- Blocked Data Classes: requests that carry any of these classes are refused.
- Max Tokens / Request and Max Cost / Request (USD).
- Set the Violation Severity (low, medium, high or critical; high by default) and an optional Owner Email, which are copied onto every violation of this policy.
- Optionally tick Revoke credentials on detected violations (see Automatic credential revocation).
- Choose Create Policy.
Each policy is listed with its scope, models, guardrails, violations in the last 30 days and status. Click the status to switch a policy between Active and Disabled, or delete it with Delete.
How policies apply
- Every active policy whose scope matches a request applies to it. When several set a token or cost cap, the tightest one wins.
- A team-scoped policy matches the request's
teamtag against the team's slug. A request without a team tag never matches a team-scoped policy, and the same goes for environment. - Model rules match a model and its dated snapshots, never a substring.
- Data classes: a family name covers its members, so blocking
piialso blockspii.email,pii.phoneandpii.us_ssn. The Router and preflight detect email addresses, phone numbers, US social security numbers, card numbers, API keys, AWS access keys and private keys in the prompt. A caller can also declare a class (public,internal,confidential,restricted,pii,phiorpci) withdata_classification; that is the only way business labels such asrestrictedorphiare known. Only the class labels are kept, never the matched text. - Separately from policies, ingest scans event metadata (feature, customer reference and tag values) for things like email addresses, phone numbers, card numbers and API keys, and redacts them before storage. Governance › Guardrails links to what was redacted, under Analytics › Use cases.
Where policies are enforced
| Where | When | What happens on a violation |
|---|---|---|
| Router | Before the provider is called | The call is refused with HTTP 400 and request_blocked_by_governance_policy (or model_blocked_by_governance_policy), with the violations listed. Recorded as Blocked. |
| Governance preflight | Before a direct call your code makes to a provider | The SDK refuses the call (or only records it, in advisory mode). Recorded as Blocked. |
| Ingest (SDK, OpenTelemetry) | After the call already happened | Recorded as Detected: alert, ticket webhook and optional revocation. |
| Provider usage feed | Every 15 minutes, for provider controls | Recorded as Detected. |
Before a call, the Router checks the final provider and model (after tiering and any fallback), the data classes in the prompt plus any declared ones, the worst-case token count (input plus the output limit) and its estimated cost. After a call, ingest checks the provider, model, actual tokens, reported cost and any class declared on the event in tags.data_classification; it never sees the prompt.
If the Router cannot read your policies, it refuses the call with 503 and governance_policies_unavailable rather than letting it through.
For calls your code makes directly to a provider, governance preflight asks the Router before the call under the same policies. It adds one round trip and can stop the call.
Provider controls
Provider controls list the provider projects, API keys and service accounts you have approved. Token Meter compares them with the usage your provider reports and records a Detected violation for usage from anything not on the list. They are on Governance › Access, below the policies.
- Connect the provider's admin key under Settings so its usage is reported. Without one, the control shows "no usage feed connected" and checks nothing.
- Choose Add provider control and pick the Provider and a Severity.
- Fill in at least one of Approved projects / workspaces / accounts, Approved API key ids and Approved service accounts (key owners), comma separated. An empty control is refused because it would restrict nothing.
- Add an optional Owner email, and tick Revoke the offending key automatically if you want that (OpenAI and Anthropic only, and it also needs the workspace-wide switch).
- Choose Save control.
Saving a provider that already has a control replaces it. Each control shows when it was last checked through. Delete stops it immediately.
Violations and remediation
Governance › Guardrails shows what policy can catch and what it caught.
Enforcement coverage
The share of your AI requests over a recent window, per provider:
- Routed: enforced before the call by the Router.
- Preflight-protected: a direct call cleared by preflight first.
- Detected after the fact: reported by the SDK, OpenTelemetry or connectors, checked only after the provider was called.
- Unknown: usage the provider reported that never appeared in metered events. This is only measurable for providers with a connected admin key.
Policy violations
Each violation shows where it was caught, the policy (or provider control), its scope, team and environment, project and key, owner, how many times and when it was seen, the remediation done and its status. Repeats of the same block within the same hour, or of the same detection on the same day, add to one violation's count instead of creating new ones.
Open a violation to Resolve, Acknowledge or Dismiss it, or Reopen a closed one. The list shows Open & acknowledged by default; switch to All for the history.
Blocked violations notify nobody
A blocked request needs no remediation, so it gets no alert, webhook or revocation. It is listed on Guardrails and in the Inbox under Automated.What happens on a detected violation
A job runs every minute and, for each new detected violation:
- Alert. If its severity is at or above Alert at severity (medium until you change it), an alert is raised and delivered to the channels on your workspace-wide Governance violation (detected) rule. A critical violation becomes a Critical alert, low becomes Info, and medium and high become Warning. Without that rule the alert shows on Monitors and in the Inbox but is sent nowhere.
- Ticket webhook. If you set one, a signed JSON POST is sent (see below).
- Revocation. Only if both the policy or provider control and the workspace allow it.
The violation's Remediation field shows each result: Alert sent or "below threshold / pending", the webhook status, and the revocation status with its target.
Set up detection and remediation
- On Governance › Guardrails, choose Detection & remediation.
- Pick Alert at severity.
- Optionally enter a Ticket / incident webhook URL. It must be a public
https://address. - Optionally tick Allow automatic credential revocation.
- Choose Save. When you saved a webhook URL, copy the signing secret now; it is shown once. Saving a new URL issues a new secret.
- If the dialog says there is no alert channel yet, create a Governance violation (detected) rule on Monitors (see Monitors and alert rules).
Ticket webhook
Each detected violation is sent once as a POST with a JSON body, for Jira or ServiceNow automation, PagerDuty, or anything that accepts JSON:
{
"type": "governance.violation.detected",
"violation": {
"id": "<violation id>",
"org_id": 123,
"policy_id": "<policy id or null>",
"control_id": "<provider control id or null>",
"enforcement_point": "ingest",
"kind": "model_not_allowed",
"severity": "high",
"owner_email": "team-lead@company.com",
"team": "core-platform",
"environment": "production",
"provider": "openai",
"model": "<model id>",
"provider_key_id": null,
"provider_project_id": null,
"event_id": "<event id>",
"reason": "<why it was flagged>",
"occurrences": 1,
"first_seen_at": "<ISO 8601 time>",
"last_seen_at": "<ISO 8601 time>",
"auto_revoke": false
}
}kind is one of model_blocked, model_not_allowed, provider_blocked, provider_not_allowed, data_classification, token_cap, cost_cap, unapproved_provider_project, unapproved_provider_key or unapproved_service_account. The body never contains prompt content or credentials.
Every request carries X-TokenMeter-Timestamp (Unix seconds) and X-TokenMeter-Signature: v1=<hex>, where the hex is HMAC-SHA256 of <timestamp>.<raw body> with your signing secret. Verify it before trusting the body:
import { createHmac, timingSafeEqual } from "node:crypto";
export function verifySignature(rawBody: string, timestamp: string, signature: string, secret: string): boolean {
const expected = "v1=" + createHmac("sha256", secret).update(`${timestamp}.${rawBody}`).digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(signature);
return a.length === b.length && timingSafeEqual(a, b);
}Any 2xx response counts as delivered. Redirects are not followed, the URL is checked again before every send, each attempt times out after 5 seconds, and a failed delivery is retried up to three attempts in all. To stop sending, tick Remove the configured webhook and save.
Automatic credential revocation
Revocation only runs on detected violations, and only when Allow automatic credential revocation is on for the workspace and the policy or provider control that raised the violation also opted in. What gets revoked depends on where the usage was seen:
- Ingest (SDK, OpenTelemetry): the Token Meter ingest key that reported the usage. It is revoked immediately, which also stops that integration's Router and preflight calls.
- Provider usage feed: the provider API key that made the call, through your connected admin key. OpenAI keys are deleted from their project; Anthropic keys are set to inactive. Keys of other providers are reported as unsupported; use their IAM, or the provider-side policies below.
Revocation cannot be undone
A revoked ingest key cannot be restored. Create or rotate a key on Governance › Keys and roll it out to bring the integration back.Provider-side enforcement
Traffic that never reaches Token Meter cannot be blocked by it. Provider-side enforcement on Guardrails generates an AWS Organizations SCP for Bedrock and an Azure Policy for Azure OpenAI from your workspace-wide policies (those with no team or environment scope). Review them before you apply them: wildcard ARNs and Azure aliases can match more than the exact model names.
Budgets
A budget is a monthly spend cap on the whole workspace or on one customer, feature, action, team, environment, provider, model, product or plan. Manage them in Governance › Budgets.
Create a budget
- Choose New policy.
- Enter a Policy name.
- Pick Applies to (scope) and, unless it is
org, a Scope target value exactly as it appears in your usage tags (for example a team slug or customer reference). Leave the value blank to cover the whole scope. - Enter the Budget / month (USD).
- Pick the Enforcement mode: Advisory, or Enforced on router traffic (workspace-wide budgets only).
- Set Trigger thresholds as percentages of the budget, comma separated (
50,80,100by default; left empty, 80 and 100). - Leave Also alert on projected overrun (linear burn) ticked to be warned early.
- Tick the channels under Notify via. A budget without a channel still tracks spend but notifies nobody.
- Choose Create policy.
What happens as spend grows
Budgets are checked every 60 seconds against month-to-date spend for the UTC calendar month, from every connected usage source.
- Each threshold fires once per month: a Critical alert at 100% or more, a Warning below that.
- The projection alert is a Warning raised when month-to-date spend, divided by the days elapsed and multiplied by the days in the month, is over the budget.
- Each budget card shows spend against the cap, its channels and a status: Over cap at 100% or more, At risk from its lowest threshold under 100% (80% if it has none), On track below that, or Silenced. For an enforced budget the status follows the Router's count (see below). Triggered now lists the budgets that are At risk or Over cap.
- From a card's menu: Silence stops checking it (and enforcing it) until you choose Enable; Enforce on router or Make advisory switches the mode of a workspace-wide budget; Delete removes it.
Enforced budgets
An enforced budget caps traffic that goes through the router. The Router keeps its own count of router spend against the cap (shown on the card as "Router: ... incl. reserved"). Before each routed call it reserves the call's estimated cost:
- If the call fits in what is left, it goes ahead.
- If not, the Router tries the fallback model set in Routing settings, but only when a current model-downgrade recommendation for that model pair has passed its quality gate and the fallback is allowed by your policies.
- Otherwise the call is refused with HTTP
402andmonthly_budget_exceeded.
Only router traffic can be stopped
Direct provider traffic, SDK-reported usage and imported bills are still counted and alerted on, but cannot be blocked this way. If you enforce more than one budget, the Router uses only the oldest, so keep one.Monitors and alert rules
Monitors has two tabs: Active alerts, everything rules and budgets have raised, and Rules.
Create a rule
- Open Monitors › Rules and choose New rule.
- Enter a Name and pick a Kind (below).
- Fill in the fields that kind uses.
- Tick the channels under Notify via.
- Choose Create rule.
Rules are evaluated every 60 seconds. Each rule's row has Edit, Silence or Enable, and Delete.
| Kind | Fires when | Severity |
|---|---|---|
| Threshold | Spend in the Scope and Scope value, optionally limited to a Provider and Model ID, reaches Threshold amount USD within the UTC day or month (Window). | Warning |
| Provider spike | Today's spend so far, for one provider or all, reaches Spike ratio times yesterday's total scaled to the part of today that has passed (UTC). Days under Spike floor USD are ignored; with no spend yesterday, any spend above the floor fires. Scope and model are ignored. | Critical |
| Anomaly (runaway trace) | One trace makes far more calls or costs far more than usual for its action. Runs without a rule; the rule picks the channels and can override MAD multiplier (6), Median floor multiplier (2) and Min calls (5). An action needs 30 traces of history before it can fire. | Critical |
| AIScale key quiet | An AIScale key has sent nothing for 3 days. | Warning |
| Renewal coming up (60/30 days) | A licence or contract renews in 60 days or in 30 days. | Info at 60 days, Warning at 30 |
| Governance violation (detected) | A detected violation meets Alert at severity. | From the violation |
| Shadow AI signal detected | A Shadow AI finding is open. | From the finding |
The last four kinds only choose where those alerts go. Create them with Scope org, keep one rule per kind (with several, only one is used), and leave the amounts empty.
Threshold, budget and provider-spike alerts close by themselves when the condition clears; a Shadow AI alert closes when its finding is triaged. An alert never fires twice while it is open. Dedup window (minutes) (60 by default) is how long after an alert closes the same condition must wait before it can fire again.
Active alerts
The table lists status, severity, subject, the rule or budget, when it fired and, for anomalies, a link to the trace. Filter by severity, status, rule and provider over 7, 30 or 90 days; your plan may keep less history.
Notification channels
Channels are where rules and budgets deliver. Manage them in Settings › Notifications.
- Choose Add channel and enter a Name.
- Pick the Kind and fill in its field:
email: Email addresses, comma separated.slack_webhook: a Slack incoming-webhook URL starting withhttps://hooks.slack.com/.discord_webhook: a Discord webhook URL starting withhttps://discord.com/api/webhooks/.
- Choose Add channel, then tick the channel on a rule or budget.
Webhook URLs are stored encrypted and never shown again. Governance › Budgets also has an Add channel shortcut for email and Slack. There is no generic webhook channel; for governance violations use the ticket webhook.
Delivery
- Every 60 seconds, each open alert raised in the last 24 hours is sent to every channel on its rule or budget that has not had it yet.
- Slack and Discord receive the alert's one-line subject. Email arrives with the subject "Token Meter alert: ..." and the same line as its body. Shadow AI alerts add a link to review the finding.
- A failed channel is retried after one minute and again after two, three attempts in all. An alert that closes before it is delivered is not sent.
- A silenced channel receives nothing. Use Silence and Enable to pause a channel without deleting it.
The Last delivery column shows "never attempted", "Delivered" with the time, or "Failed" with the time and the error (an HTTP status or network error; never the URL). Monitors and Settings both warn when a channel's last delivery failed.
Inbox
Inbox gathers fired alerts, governance violations and Shadow AI findings in one list. It is read-only: each item links to the page where you handle it.
| Tab | Holds |
|---|---|
| Needs you | Open Warning and Critical alerts, open detected violations, open Shadow AI findings that are confirmed or probable |
| Noticed | Open Info alerts, acknowledged violations and findings, open self-declared findings |
| Automated | Open blocked violations |
| Archive | Closed alerts, resolved or dismissed violations, sanctioned or dismissed findings |
The Inbox reads the latest 100 items from each source, and alerts from the last 30 days; it says when a source hit that limit or failed to load.
Shadow AI
Governance › Shadow AI finds AI use that bypasses your metered paths. It has four tabs.
- Signals: findings derived hourly from invoices, identity, governance policy and the sources below. For example: provider spend with no metered usage, usage by someone outside the workspace, a model in use that no policy allows, self-declared personal use, SSO app sign-ins, vendor-reported activity, uninstrumented AI calls in your traces and CASB traffic. Open a finding to assign it and Acknowledge, Sanction or Dismiss it. Export findings (CSV) downloads them.
- Egress: traffic to known AI hosts seen by OpenTelemetry client spans, Netskope or a Zscaler NSS feed. Only hostnames and counts are stored, never URLs or content.
- Connections: connect Okta, Microsoft Entra ID, Cursor, Claude Enterprise, Netskope and Microsoft Defender for Cloud Apps with their read credentials, or create a Zscaler feed token (shown once). Each panel says which permission it needs. Sync now queues a refresh; sources otherwise refresh hourly.
- Directories: sync your people, departments and job titles from Okta or Microsoft Entra ID.
A finding is evidence to review, not a verdict: a sign-in, seat or corporate account does not by itself prove unsanctioned use. To be notified of new findings, choose Configure alert recipients and create a Shadow AI signal detected rule.
Data retention and audit log
Governance › Audit log is an append-only, hash-chained record of model calls, policy changes and key events.
- Search by actor, model, action or resource, filter by action type, provider, model and date range, and open an entry for its details.
- Export CSV and Export JSONL download the matching records.
- Verify chain recomputes every record's hash now. The chain is also checked in the background every 5 minutes; a break raises an alert on Monitors and in the Inbox.
Changes to workspace settings are recorded separately, in the Settings audit.
Governance › Data sets how long audit records are kept:
- Enter Retention days, between 90 and 36,500. The default is 2,555 days (seven years).
- Tick Place on legal hold to stop all purging; a Hold reason is then required.
- Choose Save policy.
Expired records are only deleted after an external checkpoint confirms them. Until external anchoring is enabled for your workspace, records are kept and never purged; the page says so.
Troubleshooting
| Symptom | What to check |
|---|---|
| A budget or rule fires but nobody hears about it | The card or rule has no channels ("No alert channels"), the channel is silenced, or its Last delivery failed. |
| A detected violation shows "Alert: below threshold / pending" | Its severity is below Alert at severity, or the minute-by-minute job has not reached it yet. |
| Detected violations alert but reach no one | There is no enabled workspace-wide Governance violation (detected) rule with channels. |
| Webhook status failed or "webhook URL refused" | The URL must be public https:// and answer 2xx without a redirect within 5 seconds. |
| Revocation shows disabled | Allow automatic credential revocation is off for the workspace. |
| Revocation shows unsupported or failed | Only OpenAI and Anthropic provider keys can be revoked, and only with their admin key connected; the violation must name a key. |
| A team-scoped policy never matches | The requests carry no team tag, or the tag differs from the team's slug. |
Router returns 402 monthly_budget_exceeded | An enforced budget has no room left for this call's estimated cost. Raise it, make it advisory, or approve a cheaper fallback. |
Router returns 503 governance_policies_unavailable | The Router could not read your policies, so it refused the call. Retry; it does not fail open. |
| "Router enforcement is available only for workspace-wide budgets" | Only budgets with scope org can be enforced. |
| "already has 2 live keys" | Revoke the older key with that name before rotating or creating another. |
| A provider control says "no usage feed connected" | Connect that provider's admin key so its usage is reported. |