Tether
DocsGitHub

API reference

Outcomes

How many conversations a business had, how many were answered from its live system or ended in a verified action, how many were handed to a person, and what the model cost. Every number is derived from what Tether already recorded about each turn and each action, not from a survey, and reading it writes nothing.

Who reads which report

RouteCredentialReports on
GET /v1/outcomesThe business's secret keyThat business
GET /v1/provider/outcomesA provider keyEach business the provider created, and their total
GET /v1/tenants/outcomesThe operator keyEvery tenant, or one with ?tenantId=

Any other credential gets 403 insufficient_scope: a business cannot read another business's report, a provider cannot read a business it did not create, and a publishable key reaches none of them.

curl "$TETHER_URL/v1/outcomes?from=2026-10-01&to=2026-11-01" \
  -H "X-Api-Key: $TETHER_SECRET_KEY"
ParameterDefaultNotes
fromopenConversations that started, and actions staged, at or after this time. A date such as 2026-10-01 means midnight UTC
toopen... before this time, same formats. A to earlier than from answers 400 invalid_period

The report

{
  "tenantId": 206,
  "name": "Venue One",
  "period": { "from": "2026-10-01T00:00:00Z", "to": "2026-11-01T00:00:00Z", "asOf": "2026-11-02T09:00:00Z" },
  "outcomes": {
    "conversations": {
      "total": 35, "verifiedCustomer": 32, "unverifiedVisitor": 3, "staff": 0, "turns": 36,
      "withLiveToolCall": 15, "withStagedAction": 2, "handedOff": 7,
      "verifiedTaskSuccess": 16, "automated": 28
    },
    "actions": {
      "staged": 8, "stagedInConversation": 2, "executed": 5, "verified": 4, "unverified": 1,
      "executedNotVerified": 0, "rejected": 1, "expired": 1, "preconditionFailed": 1, "providerRefused": 0, "failed": 0
    },
    "handoffs": { "total": 7, "customerRequest": 5, "agent": 1, "unverifiedOutcome": 1 },
    "replyLanguages": [
      { "customer": "ka", "reply": "ka", "turns": 12 },
      { "customer": "ka-Latn", "reply": "ka-Latn", "turns": 6 },
      { "customer": "ru", "reply": "ru", "turns": 3 }
    ],
    "rates": { "verifiedTaskSuccess": 0.4571, "supportAutomation": 0.8 },
    "cost": {
      "currency": "USD", "total": 0.4182, "modelCalls": 41,
      "perConversation": 0.011949, "perResolvedRequest": 0.026138, "invoiceGrade": false
    }
  },
  "milestones": {
    "createdAt": "2026-10-01T08:00:00Z",
    "firstExecutedActionAt": "2026-10-01T08:14:02Z",
    "firstVerifiedActionAt": "2026-10-01T08:14:03Z",
    "secondsToFirstVerifiedAction": 843.0
  },
  "definitions": { "verifiedTaskSuccess": "...", "supportAutomation": "...", "...": "..." },
  "notDerived": ["Integration hours: ...", "..."]
}

definitions and notDerived come with every response, so the numbers never travel without what they mean. The same definitions, in short:

NumberMeans
A conversationA chat session with at least one recorded message, counted in the period in which it started. verifiedCustomer carried a signed customer token, staff a user id and no token, unverifiedVisitor neither
withLiveToolCallAt least one of the business's own read capabilities was called and answered from its system. A staged write, a refused or failed read, a knowledge document and the handoff capability are not live tool calls
handedOffA turn handed to a person (customer_request or agent), or an action the conversation staged whose outcome was unverified
verifiedTaskSuccessAn executed action that outcome verification confirmed, or a live tool call, and no handoff. The rate divides it by conversations
automatedNo handoff of any trigger. rates.supportAutomation divides it by conversations
actionsActions staged in the period, each counted under every outcome it has reached by asOf. executedNotVerified is executed with neither verified nor unverified, which only a crash between the two leaves; it is not an unverified outcome. providerRefused is a write your imported API refused without applying it, counted apart from failed
handoffs.unverifiedOutcomeOne per action staged in the period whose outcome was unverified, including actions staged with POST /v1/actions, which belong to no conversation
replyLanguagesTurns by the form the customer wrote in and the form the turn replied in: ka, ka-Latn, ru, en, other, unknown
costThe usage ledger's estimated USD for model calls in the period, including calls outside a conversation. perResolvedRequest divides it by verifiedTaskSuccess
secondsToFirstVerifiedActionFrom the tenant's creation to its first verified action, at any time

A period's outcomes keep maturing: an action staged on its last day may be approved and verified the next, and the report counts it under the period it was staged in. asOf says when it was read.

What the report cannot know is listed in notDerived: integration hours (record them by hand), writes refused before staging by a precondition (they leave no row), and whether the model's reply was actually in the decided language (graded live only).

For a provider

curl "$TETHER_URL/v1/provider/outcomes?from=2026-10-01" \
  -H "X-Api-Key: $TETHER_PROVIDER_KEY"
{
  "providerTenantId": 205,
  "period": { "from": "2026-10-01T00:00:00Z", "to": null, "asOf": "2026-11-02T09:00:00Z" },
  "visibility": "Counts only, per business and in total. A provider sees none of a business's conversations, messages, actions or audit.",
  "businessCount": 2,
  "businesses": [
    { "tenantId": 206, "name": "Venue One", "outcomes": { "...": "..." }, "milestones": { "...": "..." } },
    { "tenantId": 207, "name": "Venue Two", "outcomes": { "...": "..." }, "milestones": { "...": "..." } }
  ],
  "total": { "conversations": { "total": 36, "...": "..." }, "...": "..." }
}

Each business's outcomes are exactly what that business reads from GET /v1/outcomes. total adds the counts and computes its rates and per-unit costs from the sums, so a large business weighs as much as its conversations do. No session, action, customer or message appears.

The operator's GET /v1/tenants/outcomes has the same shape with tenants and tenantCount in place of businesses and businessCount.

Export as CSV

curl "$TETHER_URL/v1/outcomes?from=2026-10-01" \
  -H "X-Api-Key: $TETHER_SECRET_KEY" \
  -H "Accept: text/csv" > outcomes.csv

Every route answers Accept: text/csv with one metric per row:

tenant_id,tenant_name,metric,value
206,Venue One,period.from,2026-10-01T00:00:00.0000000Z
206,Venue One,conversations.total,35
206,Venue One,reply_language.ka.ka,12
206,Venue One,rates.verified_task_success,0.4571
206,Venue One,cost.total_usd,0.418200

Metrics come in a fixed order, numbers in invariant formatting and times in round-trip UTC, and asOf is left out, so the same data renders to the same bytes. A value that does not apply, such as a rate with no conversations, is empty. The provider and operator exports end with total rows, whose tenant_id is empty.

  • Audit — the trail of each action behind the action counts
  • Handoff to a person — the triggers counted under handoffs
  • Providers — the businesses a provider's report covers