Instrument usage for UsageTap Guard
Current integration contract, reviewed 2026-11-02. Guard automatically monitors
reported application behavior across organizations. Organization administrators
can inspect live comparisons and findings. The Guard page is visible to workspace
members, but backend assessment reads require active organization ADMIN
membership. The public demo uses fixtures. Only Detector preflight requires
the exact lower-case Cognito admin group; an organization admin is a different role.
Guard finds behavioral changes to investigate, including changes hidden by steady usage totals. It does not establish abuse, complete task cost or task completion. Independent customer/end-user behavioral monitoring is not enabled: an isolated customer change can be hidden by stable application totals. Customer and task drill-down supports investigation.
Change/recovery email and Slack notifications use existing organization opt-ins and shared destinations. Both default off. Guard does not automatically block activity. Configured Meter allowances/limits and SDK-local circuit breaking have their own enforcement contracts. Retired R0 rules, feature dictionaries, history imports and incident feedback are not setup steps.
See the current specification for access, detector connections and remaining qualification work. Superseded recipes and implementation diaries are historical records.
Agent daily summaries
Use MCP get_guard_summary (usage:read) for application behavioral findings and
recorded change/recovery notifications in a daily operational brief, alongside
usage totals and get_customer_signals. It defaults to the last 24 hours; supply
inclusive startTime and exclusive endTime for a prior calendar day (convert its
timezone to UTC). Maximum range: seven days within 56-day retention. Membership
uses saved assessment window starts, rather than call or delivery times.
Follow nextToken until null. Merge finding groups with the same ID across pages;
comparison counts describe overlapping comparisons, not independent incidents.
Keep period findings/support counts separate from current readiness. An empty,
quiet, disabled, stale, pending or unsupported report is not an all clear. Saved
comparison counts do not establish uninterrupted monitoring. Notification delivery
is separate: sent, skipped, or unknown_or_pending for each channel. Reading
does not send alerts or enable opt-ins. These are application findings, not
independent customer detection, confirmed abuse, or anomaly-triggered blocking.
The retired get_usage_monitoring scope read is not the Guard summary tool.
Population comparisons
Applications compare trailing two-hour populations every five minutes after reporting grace. Each detector independently uses supported same-weekday, weekday/weekend or daily clock-matched history, with labelled recent compatible history when seasonal support is sparse. Use the organization timezone, with an explicit UTC default. Customers do not configure comparison policies or schedules.
Genuine calls/reports are the sampling units: a report of 100 consumed calls is one report, not 100 independently timed observations. Missing measurements stay unknown; genuine zero stays zero. Anomalyzer owns numerical decisions. Sampling, per-assessment statistical budgets and overlapping windows do not establish a daily/lifetime false-positive guarantee. Capacity limits, collection gaps and insufficient support remain explicit. Implementation connections do not certify production noise, capacity or deployed notification delivery.
Read the overview
The dedicated Guard Dashboard shows active findings from completed changed checks. Workspace Overview offers organization administrators a compact summary of those same saved checks, linking to the exact application scope and detector in Guard. Viewers get a Guard navigation link without loading restricted assessments. Overview bounds its preview to four loaded scopes and one check page per scope. Additional comparisons remain explicit and open in Guard; an incomplete preview does not establish that the full application has no warnings. Live shows operational activity and customer signals; its former Guard view and existing investigation links redirect to the dedicated Guard page. Findings retains earlier changes and opens saved measurements first, with expandable guidance and evidence. Explanations describe possible implications rather than a proven cause or measured harm. Selecting a connected detector opens its evidence.
Older bursts stop drawing attention when fresh, complete source evidence confirms at least 15 minutes after the latest positive five-minute usage window ended without newer recorded usage. They show No recent activity · earlier change with neutral current styling and leave the active list; earlier findings and their original history stay saved. New activity restores ordinary display on refresh. Stale, failed or incomplete source reads cannot establish inactivity. This is a display state, not recovery or proof of account safety; it does not send a recovery notification or change Guard's two-hour Quiet definition.
Findings and comparison evidence show exact measured current and selected reference counts and a Sample volume level. The smaller population sets the display-only band: Limited 0–31, Moderate 32–255, Substantial 256 or more. These bands describe evidence quantity, not statistical confidence, account safety or abuse probability. A ready 18-call comparison can still support a warning; Limited does not mean Learning and does not suppress findings or notifications. Missing support is Unavailable, never zero. No organization-age label is used.
Counts describe the exact saved detector-selected measurements. Saved full recorded and retained candidate counts, when available, are separate from the selected comparison and disclosed before calendar selection. Sampling can miss rare changes. For API/custom meters, one report is one observation even with many consumed units. Rate history positions are not independent reports. Several detectors or overlapping windows may describe the same calls; their counts are not independent incidents. Saved window bounds and reference dates give observation context where retained; processing time does not establish current activity or recovery.
| Display | Meaning |
|---|---|
| Activity dot and timestamp | Latest loaded positive five-minute usage window per surface. Green means that window began within 15 minutes, not that Guard completed an assessment. |
| Change detected | A supported saved comparison found a change; investigate context. |
| No change detected | No supported change in the assessed population, not a guarantee of account health. |
| No recent activity · earlier change | A fresh source check qualifies an inactive burst; current emphasis is neutral while earlier evidence remains available. This is not alert recovery. |
| Quiet | A completed sliding two-hour source check found no recorded usage. It clears the active display but does not establish alert recovery or an upstream delivery heartbeat. |
| Unknown / awaiting latest result | No current completed result; readiness, missingness, unavailable processing and unconnected checks retain their explanations. |
| Hourly history | Saved findings, including earlier changes. Green means no recorded change in loaded history. Partial coverage and errors stay explicit; Older loads earlier pages and Expand history opens the grid. |
A bounded read can verify Quiet before background work completes. It does not create usage, persist an assessment, recover an alert or send notifications. Reading history does not rerun analysis. Overlapping windows are not independent incidents. Demo icons describe checks without simulating live assessments; platform-only preflight replays saved offline cases without running the engine.
Connected measurements
New cost-per-call comparisons warn only when a supported distribution change also has higher average recorded cost per call. Decreases and distribution changes without a higher average remain neutral information in notes and history; they do not send notifications. Check model choice, pricing, input size and cache reuse to understand the change. Lower cost does not establish safe activity: other behavioral detectors can still warn. Earlier findings retain their original assessment policy.
| Surface | Current connected comparisons |
|---|---|
| LLM | Cache reuse, output/input, output-size distribution, recorded cost per call, token telemetry coverage, end-user attribution coverage, completion reasons and response-code distribution (Errors). |
| API / Agentic Calls | Feature mix by consumed calls and updates, task-type consumption mix, end-user/task attribution coverage, consumed-call rate. |
| Custom meters | Feature mix by consumed units and updates, task-type consumption mix, end-user/task attribution coverage; exact meter identity and units remain separate. |
Task-type mix uses top-level taskType, weighted by consumed calls/units;
supporting update shares explain batching. These are reported usage compositions,
not distinct/completed tasks or cost per task. Missing current labels can prevent
readiness; missing historical labels remain disclosed. Related comparisons are
not independent confirmation. LLM task-type collection is not enabled.
Coverage uses eligible recorded calls/reports as its denominator. Historical rows without the measurement stay unknown, and coverage cannot establish completeness of unreported activity or user authorization. Recorded cost is provider cost, not customer billing. Errors uses recorded response-code categories on eligible finalized successes, failures and timeouts, including shifts among successful codes; missing codes are unknown and do not establish a provider failure rate. API call rate uses genuine consumed quantities over five-minute exposure and its own supported daily UTC reference; batches cannot recreate individual call times. Unconnected icons remain explicit gaps, not inferred healthy checks.
Completion reason
completionReason is an optional top-level call_end / SDK endCall field: a trimmed, non-empty provider-reported string of at most 128 characters, without control characters. Use the primary Chat Completions choice's finish_reason, Anthropic's stop_reason, or Responses incomplete_details.reason (otherwise its terminal status, such as completed). Omit it when unknown; never infer it from HTTP 200, zero tokens, or UsageTap lifecycle status. Call details display missing values as Unknown. This field does not change pricing or lifecycle status. Guard can compare its reported categorical distribution when enough eligible data is available; a stop reason does not establish task completion.
Production and dev/test
Use one environment setting for all UsageTap operations, including customer
creation and pure HTTP/API usage. Set USAGETAP_ENVIRONMENT=test in development,
staging and QA, and USAGETAP_ENVIRONMENT=production in production. The SDK and
observer read it automatically. An explicit SDK/observer
defaultEnvironment: "test" overrides the environment variable.
For direct HTTP in any language, add X-UsageTap-Environment: test to the shared
UsageTap request headers, including reads, POST /customers, call_begin,
call_end and custom_meter. Keep that header on UsageTap requests only.
Do not guess from NODE_ENV, customer names, isTest, tags, or metadata.
Only production / test are valid. Automatic customers without a header stay
unlabelled. In a customer panel, admins can save Traffic group as Production or
Dev / test to override request labels for new usage. Automatic removes this pin.
Existing usage, active calls and retries keep their recorded group.
Use Dashboard, Customers, Usage and Live's Environment filter. One customer ID can carry both labels. Usage totals/exports are filtered by the event's stored label; customer balances and customer signals remain shared. Page-level Environment filters group unlabelled usage with Production and keeps Dev/Test separate; API header filters still match exact recorded labels. Usage Forecast defaults to All traffic, offers Production, and does not offer Dev/Test-only forecasting. Guard behavioral checks always compare Production + unlabelled usage with matching retained history. Dev/Test is excluded from those checks. A separate environment-mix check uses all recorded traffic to detect substantial Dev/Test growth and share increases; it follows existing Guard notification opt-ins. There is no Dev/Test inclusion setting. Viewing filters do not change detection, and eligible retained history is reused without restarting learning.
Test traffic still consumes allowances and can incur charges. This is classification, not a billing sandbox. A call retains its original environment at finalization; conflicting explicit labels or idempotent retries are rejected.
Verify the outgoing header on customer creation, begin/end and API meter reports, then inspect stored labels and filtered totals. An older SDK accepting an option in local types is not proof of delivery; use a supporting release or direct HTTP. See the API contract.
Guard monitors customer usage within Meter. Good attribution and complete usage telemetry make more comparisons useful; they do not guarantee detection. Keep your existing providers and models. Gateway, prompt capture, and compression are not required. Start with the integration guide.
Choose the fields that support your investigation
Send attribution on call_begin for LLM calls and custom_meter for
API/custom usage. In the SDK these are beginCall/withUsage/provider wrapper
context and incrementCustomMeter. Do not wait until call_end to add a task.
| Field | What to send | How it helps |
|---|---|---|
customerId |
Durable account/tenant ID from trusted server context | Customer scope, allowance context, and task lookup. All members of a pooled account use the same ID. |
feature |
Stable product operation, such as api.search or document.summary |
Application feature-mix comparisons and investigation. Avoid unique IDs, raw URLs, or model names here. Missing values become Unspecified. |
customerUserId |
Stable, preferably non-PII application user ID, when known | End-user attribution coverage and investigation. Name/email are optional display fields, not substitutes. |
taskId |
One ID for one business operation, shared across its model calls, tools, API calls, retries, and workers | Indexed retrieval of that customer's recorded task usage. A new operation gets a new ID. |
taskType |
Stable category such as document.import |
API/custom task-type composition and investigation. Keep categories stable across operations. |
tags |
Optional safe categorization; use the environment header for traffic labels | Stored categorization; tags do not define Guard detector scopes. |
metadata |
Optional sanitized operation details on meter events | Live View labels and investigation context; arbitrary keys are not additional detector inputs. |
| Idempotency key | Unique per logical LLM call or meter report, reused for delivery retries | Avoid duplicate usage. It is separate from taskId, which is shared by many events. |
taskId and taskType are optional, case-sensitive, trimmed strings of 1–128
characters without control characters. Task IDs are scoped to organization and
customer. Put these fields at the top level, not in metadata, tags, or
provider request bodies. runId is SDK-local circuit-breaker state; it is not
sent to UsageTap and does not enable task lookup. You may deliberately use the
same application operation ID for runId and taskId, but must set both.
Persist the operation ID with the job and propagate it across queues, child
steps, and process boundaries. Keep the parent taskType stable while feature
identifies each step. Do not use a session ID spanning many operations as the
task ID, or generate a fresh task ID for every model/tool call.
For existing Gateway integrations, send
taskId and taskType at the top level of Chat Completions or Responses
requests, including streams, or in each batch item's body. Gateway validates
and forwards them to call_begin and strips them before provider dispatch.
Do not add a second LLM metering lifecycle around Gateway calls.
Report HTTP API and agent tool calls
Enable API / Agentic Calls on the customer's usage plan, then report each operation once through the existing custom-meter mechanism:
import { UsageTapClient } from "@usagetap/sdk";
const usageTap = new UsageTapClient();
const task = {
customerId: "acme",
customerUserId: "user_42",
taskId: "import_123",
taskType: "document.import",
};
// Report completed usage. eventId identifies this report, not the whole task.
const report = await usageTap.incrementCustomMeter({
...task,
meterSlot: "AGENTIC_API",
amount: 1,
feature: "api.search",
tags: ["production"],
metadata: { kind: "api", method: "POST", endpoint: "/v1/search" },
}, { idempotencyKey: "import_123:search:1" });
if (report.data.blocked) {
// Record the decision and stop admitting further work under your policy.
}
await usageTap.incrementCustomMeter({
...task,
meterSlot: "AGENTIC_API",
amount: 1,
feature: "tool.document_lookup",
metadata: { kind: "mcp", serverName: "documents", toolName: "lookup" },
}, { idempotencyKey: "import_123:lookup:1" });
await usageTap.incrementCustomMeter({
...task, meterSlot: "CUSTOM1", amount: 25, feature: "pages.processed",
}, { idempotencyKey: "import_123:pages:1" });
For HTTP, send metadata.method and a safe route template in
metadata.endpoint, such as /v1/documents/:id. For MCP, send
metadata.toolName and optionally metadata.serverName; metadata.kind is a
useful label. Strip query strings and private identifiers before sending.
Live View removes query strings from endpoint labels, which does not sanitize
the event you submit. Do not send credentials, headers, prompts, tool arguments,
responses, or URLs containing private data. You do not need to send IP addresses
or user-agent strings to enable the implemented detectors.
amount is a positive safe integer of consumed units, not the number of
telemetry requests. For AGENTIC_API, 100 calls reported together use
amount: 100. Guard tracks both consumed calls and reporting events. Prefer
prompt, consistent reporting: changing batching can change units/event and
reporting-rate signals; a bulk report cannot recreate the original call timing.
The public report API does not accept a caller-controlled occurredAt field.
Do not count the same action again merely because it used MCP.
Reports need usage:write and return an accepted envelope even when
data.blocked is true. The application enforces that flag. This reporting API
does not reserve funds or authorize work atomically. Blocked meter reports and
UsageTap internal platform-meter events do not feed customer consumption Guard
comparisons or task meter totals. See meter funding and limits.
Report LLM usage completely
Use a wrapper scoped to the current customer and operation:
import OpenAI from "openai";
import { withMetering } from "@usagetap/sdk/openai";
const provider = new OpenAI();
const metered = withMetering(provider, {
customerId: "acme",
customerUserId: "user_42",
taskId: "import_123",
taskType: "document.import",
feature: "document.summary",
});
// Keep your existing model, input, and stream handling.
const result = await metered.responses.create({ model: existingModel, input });
The same context works with the Anthropic and OpenRouter wrappers. Check the
installed SDK: wrapper task forwarding is fixed in this source tree; older
builds can accept task fields in types but omit them from requests. Until you
use a build containing that fix, use withUsage or explicit beginCall with
task context. Verify the outgoing call_begin, not just TypeScript acceptance.
For wrapFetch, task fields can be supplied in defaultContext; task override
headers are not implemented.
For manual integrations, begin before provider work, respect data.allowed,
and finalize allowed calls on success, provider error, stream completion,
cancellation, or abort. A denied begin is already finalized. Supply actual
provider/model and provider-returned usage on call_end:
| Telemetry | Guard comparison or interpretation |
|---|---|
modelUsed, providerUsed |
Recorded provider/model context explains changes; application-wide comparisons cross these contexts unless a detector-specific comparison control is justified. Eligible completed calls still require a recorded model. |
inputTokens, responseTokens |
Output/input ratio, output-size distribution and token telemetry coverage. |
cachedInputTokens, cacheWriteInputTokens |
Cache-read share and retained cache context. Input is the total including both cache subsets. |
cacheWrite5mInputTokens, cacheWrite1hInputTokens |
Cache-write lifetime detail; monitoring sums these only when total cache writes are absent. |
pricingMode (standard/batch) |
Accurate recorded cost and execution context; set batch only when the workflow actually uses it. |
reasoningEffort, reasoningEffortSource, reasoningMode, reasoningBudgetTokens |
Execution context for interpreting comparisons; omit unknown values rather than infer effort from reasoning tokens. |
| Real token usage plus recognized provider/model pricing | UsageTap calculates recorded cost for cost/call comparisons. Missing cost is not free usage. |
OpenAI input totals already include cached tokens. Anthropic reports ordinary
input, cache reads, and cache writes separately: sum them for inputTokens,
retaining the cache subsets. Reasoning tokens are part of provider output;
do not add them again. Report zero only when it is known. Missing or invalid
input/output totals reduce coverage rather than becoming real zero-token calls.
Guard uses the stored cache count, including zero defaults already recorded by
call finalization, without a separate cache-reporting flag. A zero means no
recorded cache savings; it does not prove that the provider explicitly reported
zero. Truly absent or invalid stored counts remain unavailable, and cache-read
fractions require positive total input.
New cache comparisons warn on supported degradation: at least a 10 percentage
point increase in calls with at most 5% reuse, or a 10 percentage point fall in
average per-call reuse. Improvements alone do not warn. The statistical check
still compares distributions, so growth in low-reuse calls can matter even when
the overall average rises. Saved earlier findings keep their original policy.
Eligible completed LLM calls feed behavioral monitoring; failed, denied,
in-progress and dashboard demo/sample records do not become completed-call
baselines. Explicit test usage feeds environment mix only; all other Guard checks exclude it.
Output tokens consume token allowances; total input and cache details still
matter for provider cost and Guard even though they do not consume output-token
allowances. See call-end contract.
Inspect a recorded task
Use Meter → Guard → Findings’ task lookup with the exact customer and task ID, or:
const url = new URL("https://api.usagetap.com/usage/monitoring");
url.searchParams.set("customerId", "acme");
url.searchParams.set("taskId", "import_123");
// Server-side only. apiKey comes from your existing server configuration.
const response = await fetch(url, {
headers: {
Authorization: `Bearer ${apiKey}`,
Accept: "application/vnd.usagetap.v1+json",
"X-UsageTap-Environment": "production", // Use test in development/staging/QA.
},
});
if (!response.ok) throw new Error(`Task lookup failed: ${response.status}`);
const envelope = await response.json();
const page = envelope.data;
// If page.nextToken is non-null, repeat the same query with that nextToken.
Requires usage:read. MCP offers
get_task_usage({ customerId: "acme", taskId: "import_123" }) with the same
pagination semantics. There is currently no UsageTapClient.getTaskUsage() or
getUsageMonitoring() method; use REST/MCP for reads.
totalsScope: "this_page": sumllmCalls,recordedLlmCostUsd,missingLlmCostCalls, andinProgressCallsacross every page. MergemeterUnitsbymeterKey, summingamount,reportingEvents, andrecordedChargeUsd. Follow opaquenextTokenuntil null, even on empty pages.taskCompletion: "not_reported": results describe recorded usage so far. They do not establish completion, duration, success, complete cost, or ongoing execution. LLM records can include failed, denied, and open calls; inspect each record'sstatus.- Provider LLM cost and commercial meter charges are separate economics. Do not add custom meter units to LLM tokens or call their charges provider cost.
- The index is eventually consistent. Late events can change totals; historical events without a task ID cannot be joined retroactively. Retention follows the underlying call/event records.
taskId enables lookup, not an independent statistical baseline per task.
taskType is a comparable workload category within supported composition checks; it is not a universal partition for every detector. Cost per completed
task and automatic task-completion alerts require a future explicit task lifecycle.
Notifications and read APIs
From Meter - Guard - Settings, open Email / Slack notifications. An organization admin can opt into UsageTap Guard change/recovery alerts using the existing shared recipients and Slack channel. Neither channel is enabled automatically. Each connected detector has two controls: Alert and Notification, both with Off, All, Major. All includes minor and major changes. Organizations without saved detector settings start with the Development preset: behavioral Alert: Major and Notification: Major, with Environment mix Off. Production sets Alert: All and Notification: Major for every connected detector, including Environment mix. Presets populate the existing controls; Save detector settings applies the choices. Individual overrides show Custom. Existing saved preferences keep their behavior. Presets do not change numerical thresholds, traffic labels or channel opt-ins. Smaller or unclassified changes below the alert level remain in evidence/history with neutral styling, without warning icons, active findings or amber timeline emphasis. Alert: Off suppresses all visual alerts independently of notifications. Both Off skips evaluation while preserving Meter recording and saved findings. Both levels are saved together in the existing detector preference. Old settings retain their behavior without a migration. Major describes change magnitude, not proven harm or confidence. Notification: Off stops pending delivery immediately. Visual-only edits do not cancel pending notifications. No history reset or catch-up notification is created by changing settings. Repeated changed windows do not repeat alerts; a smaller change can notify when it first becomes major. Recovery requires a completed no-change comparison and is sent only on a channel that received the change; quiet, pending, unknown or unavailable evidence never establishes recovery. Historical catch-up does not create alerts. Provider-response loss can cause duplicate delivery during retry; exactly-once delivery is not guaranteed.
Open Meter - Guard - Dashboard or Live - Guard for current status and Findings for retained evidence and task lookup. Pausing the display does not pause collection. No configured risk rule, feature dictionary or history import is required. There is no acknowledge/classify/expected-change reset workflow.
REST GET /usage/monitoring and MCP get_usage_monitoring without taskId
return the retired R0 response:
{ "scopes": [], "nextToken": null, "retired": "r0" }
They do not expose current application comparisons. Use the signed-in Guard UI for those reads. Exact REST/MCP task lookup remains available as described above; there is no SDK task-read method.
Verify the integration
- Exercise an authorized existing operation with a known customer, user, task and feature. Preserve streaming consumption and cancellation behavior.
- Inspect emitted
call_beginandcustom_meterpayloads for top-level attribution, distinct retry-stable event keys, real quantities and the environment header. Avoid logging secrets or payload content. - Confirm final LLM status, actual provider/model, token/cache measurements and recorded cost when available. Inspect safe meter labels in Live.
- Retrieve the exact task through REST/MCP and follow every page. Allow for index lag; report missing-cost and open-call counts instead of claiming complete cost.
- Inspect Guard support, timestamps and connected measurements separately from ingestion. Verify notification opt-in and delivery separately. Ingestion does not prove detection efficacy, production capacity or account health.
For agents, read the installed package's AGENTS.md and the maintained
integration skill.