Usage metering

View as Markdown

Telltale records units of completed work that your backend reports, and separately measures agent tool executions and agent session-minutes per account and category. It meters; it does not create charges or process payments. Pass the numbers to your own billing system.

Report completed work

After the protected work has actually completed, report it from your backend with the server key:

Shell
curl -sS -X POST https://app.trytelltale.dev/api/v1/usage \
  -H "Authorization: Bearer $TELLTALE_SERVER_KEY" \
  -H 'Content-Type: application/json' \
  --data '{"sessionToken":"TOKEN","eventId":"export_000001","actionId":"export_report","units":1}'

With the server adapter: await telltale.recordUsage({ sessionToken, eventId, actionId, units }).

Optionally include executionId, the stored execution ID, when your backend has an explicit correlation to a tool execution. The reviewed runner exposes this ID as the third beforeRequest(request, action, context) argument’s context.executionId; your application can deliberately forward it to its own backend. Treat it as correlation only, never authorization or proof of success. Do not guess from the nearest timestamp. The collector requires the same site, session, trusted account and action name. The same eventId must always repeat the same execution link. Existing callers can omit it.

For a multi-step execution, the matching name is the workflow’s tool name, not the individual step action name. Configure the allowed operation-to-tool mapping in your backend; do not blindly trust a browser-supplied name. A successful last-step request alone is not proof that the whole workflow’s business outcome completed. If your backend can confirm only that individual operation, report it without the workflow execution link rather than claiming completion of the entire workflow.

A linked receipt records outcomeBasis: application-server-reported and updates the execution’s application outcome summary. It is your authenticated server’s attestation, not independent proof by Telltale. A browser-reported successful request remains a separate result; browser completion cannot create this receipt. The usage event retains the receipt and link, while the execution keeps its latest receipt and aggregate units. Report only after your application confirms its business action succeeded.

Each recorded unit also emits a signed usage.recorded webhook (Webhooks guide).

Recover after receipt delivery fails

Keep the business result separate from receipt delivery. If an export was saved but recordUsage failed, show “Report saved; usage reporting pending” rather than “Export failed.” Retry only the receipt with the same eventId and facts; do not repeat the export. A 409 conflict is not a transient delivery failure: show “Work completed; usage reporting needs review” and reconcile the action name, execution link and original event facts before retrying. Keep it out of automatic delivery retries. Persist the completion and pending receipt in your own backend so recovery does not depend on an open browser or an in-memory queue. A timeout can mean the collector accepted the receipt but its response was lost, so use the same ID even when the outcome is uncertain. The 24-hour live-session requirement still applies to a receipt the collector has not accepted yet; an expired-session rejection needs reconciliation, not a new event ID or an invented session.

Each row also records via, how the work reached your application, derived when it arrives: tool when a reviewed tool or workflow with the same name as actionId ran in that session within the 15 minutes before; ui when no tool ran in that window and the session sent UI interactions; unknown otherwise (another tool ran, or no interaction was observed). unknown is never counted as ui, and via says nothing about who drove it; the verdict does. Control › Tool access › Reviewed shows, per tool, agent-completed work through the tool versus agents driving the UI (tool coverage), plus tool runs by agent and by account. Charge › Usage groups reports by week, action and account.

What counts as chargeable

Only high-confidence agent usage is chargeable: verified identity (a valid Web Bot Auth signature, agentEvidence: "verified"), an automation trace ("automation-trace"), input injected by software ("injected-input"), sustained behaviour ("sustained-behaviour"), a behaviour change after a person ("behaviour-change"), two or more independent behaviour families agreeing on one page with no physical-device input on the session ("behaviour-corroborated", "Strong evidence: several behaviour signals agree"; ledger evidence class behaviour-corroborated) or Claude in Chrome's cursor driving the clicks (agentEvidence: "cursor-driven"; ledger evidence class cursor-driven). High confidence is chargeable from the minute it qualifies; earlier medium-confidence minutes of the same session are not charged. Agent minutes and completed work at medium confidence (one behaviour pattern alone, agentEvidence: "behaviour") are recorded and shown, marked billable: false (billable is shown as chargeable in the dashboard), and never metered, included or priced, whatever the Site's blocking setting. Agent tool executions come through the agent tool surface and always count.

Agent usage by category

GET /api/v1/agent-usage.json returns seven days of retained agent tool executions and agent session-minutes per account and category: computer_use, browser_use, coding_agent, crawler or unattributed. Pass from and to for another period. Periods are half-open, [from, to): a unit exactly at to belongs to the next period, so consecutive periods add up without double counting.

Agent-usage ledger

Every completed-work unit also lands in the agent-usage ledger: chargeable, behaviour-only, human and unknown units per account, user and day, with the evidence for each unit, corrections, a Stripe meters export and account alerts.

Reconcile

Use eventId (completed work) and usageId (agent units) as idempotency keys in the system you charge your customers with, and webhook-id to deduplicate deliveries. Periodically compare your ledger with GET /api/v1/agent-usage.json for the retained window, using consecutive half-open periods. Usage, agent minutes and agent tool executions are retained for 90 days; record caps never remove them early, only age or erasure does. Import continuously rather than relying on the API as the record of truth.

Charge › Usage shows the same data and exports CSV (GET /api/admin/export?site=SITE_ID, owner session):

Pricing estimate

Charge › Pricing simulator has a pricing estimate (POST /api/admin/pricing-preview): unit prices per agent category minute, per agent tool run and per agent-completed action unit, plus an included allowance per account, applied to a past period. It shows what each account would have paid, labelled Estimate, no charges. Nothing is charged, invoiced or stored. Unnamed agents (unattributed) have their own price and their own line (and its share of agent minutes), signed-out traffic and accounts from the page (unconfirmed) are shown but excluded from the total, completed work is priced only when its verdict was agent, and by default only categories set to metered are priced.

Goals and alerts

Settings › Alert rules (GET and POST /api/admin/goals) watches agent share of activity minutes for the site or one account, a named agent seen for the first time, a tool failure rate, or an account whose agent calls keep failing (an account's MCP server and API calls failing at or above your share in one UTC day, with at least your minimum of calls; once per account per day, naming the account in the bell, the account.agent_calls_failing webhook event and, if you choose, Slack). A crossing raises a dashboard banner until dismissed and sends a signed alert.threshold_crossed webhook. Goals use observed counts: the agent share denominator includes unknown and mixed minutes, and unknown never counts toward human.

Activation and session volume

Each site records when it was activated: the moment its first session arrived. Sessions are counted when the SDK starts a new one (a page that resumes a stored session is not counted again), in one counter per site and UTC day that is kept for 90 days. Session records themselves are kept for only 8 days, so the counter is what makes a 30-day total possible.

Settings › Channels shows the activation time, the sessions in the last 30 UTC days (today included) and the first counted day. Sites that had traffic before activation was recorded show their earliest retained session instead, labelled as such. The same numbers are in GET /api/admin/state under siteUsage, keyed by site ID: activated, activatedAt, activationSource (recorded or earliest-retained-session), windowDays, since, sessions30d, countingSince, quota, quotaState, quotaUsedPercent and enforcement.

An owner or admin can set an optional soft quota in sessions per 30 days (POST /api/admin/session-quota with siteId and quota, a whole number from 1 to 1,000,000,000, or null to remove it). The dashboard asks for confirmation, and each change is written to the audit log. quotaState is none, ok, near (80% or more) or over. The quota only warns: enforcement is always none, and collection, verification and metering continue past it.

Erasure

Owners and admins can delete one user's or account's local records from Settings › Data & privacy (POST /api/admin/erase with siteId and userId, accountId or both; values are trimmed). It removes the matching sessions, executions, usage, agent minutes and interaction minutes, including rows recorded before identity was associated and rows whose session has already expired. Erasing an accountId also clears that account's response setting, its name and plan (accountTraits) and goals or alerts scoped to it, and removes its ID from seat-change audit entries. Daily session totals hold counts only and keep a count already rolled into a day. Completed-work usage leaves an identity-free tombstone (record ID and a hash of the facts) until the row would have expired, so a retried eventId is still answered as a replay and is never recorded or charged twice.