Tether
DocsGitHub

API reference

Providers

A software provider, such as a booking or shop platform, serves many businesses. Each business is its own tenant with its own keys, approvers, policy and audit. The provider creates them, starts them from its own configuration and looks after their keys. It never reads their conversations, actions or audit, and it can never reach a tenant it did not create.

Becoming a provider

Provider authority is granted by Tether, not taken. Your platform is first an ordinary tenant with a secret key. When Tether grants it provider authority, you receive a provider key, prefix tpv_, shown once.

The grant is an operator call, made with the deployment's operator key:

curl -X POST https://api.trytether.ge/v1/tenants/$PROVIDER_TENANT_ID/provider \
  -H "X-Api-Key: $TETHER_OPERATOR_KEY"
{ "tenantId": 7, "provider": true, "providerKey": "tpv_…", "prefix": "tpv_3f9a" }

Calling it again issues another provider key and leaves the grant as it is. DELETE on the same route withdraws the grant and answers revokedKeys. A business a provider created cannot itself be made a provider (409 provisioned_tenant).

KeyReaches
Your secret key, tth_Your own tenant: the configuration your businesses start from
Your provider key, tpv_/v1/provider, and /v1/user-sessions to sign your businesses' own users in to an approval app
Your inbox key, tib_Signing your businesses' users in and, in their sessions, their approval routes. Nothing else. Issue it with POST /v1/provider/keys for the host that runs the approval inbox
Your CI key, tci_Publishing your repository's contract draft, docs and vocabulary suggestions to your own tenant, the template, from your CI runner. Issue it with POST /v1/provider/keys {"kind": "ci"}; see Repository

The two are kept apart on purpose. Your secret key cannot create a business (403 insufficient_scope), and your provider key cannot chat, register tools, read an audit or reach any operator route. No other credential reaches /v1/provider. Tether can withdraw provider authority. Your provider keys and inbox keys then stop at once, and your businesses keep running with their own keys. Your secret key cannot rotate or revoke a provider or inbox key either; only the operator issues provider keys, and only your provider key manages your inbox keys.

The configuration your businesses start from

Configure your own tenant with your secret key, exactly as a single business would: import your API or register your catalog, then set the domain pack and the approval policy. You can try it on your own tenant before any business uses it.

When you create a business, it gets a copy of what your tenant currently has:

PartCopied
CatalogThe current version
Domain packThe current version
Approval policyThe current version
Upstream connectionsThe imported API or MCP server, with its credential (still encrypted at rest)
Tool endpoint, events webhook and allowed originsWhen set. Events for every business then reach your one receiver, each signed with that business's own signing secret
Knowledge documentsEach one, with its embeddings, as part knowledge:<name>. It replaces the business's document of the same name and leaves its others; the business sees copiedFrom on it and may delete it
Users (approvers)Never. A business registers its own staff

A business does not follow your later changes on its own. Editing your catalog cannot change what a business's agent may do in the middle of its conversations. To bring a business up to date, apply your configuration again. Each part you have configured becomes a new version in that business, and its earlier versions stay readable. A part you have not configured is left as the business has it.

Create a business

curl -X POST "$TETHER_URL/v1/provider/tenants" \
  -H "X-Api-Key: $TETHER_PROVIDER_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Venue One" }'
{
  "tenantId": 31,
  "name": "Venue One",
  "plan": "use_tether_ai",
  "providerTenantId": 12,
  "apiKey": "tth_5b1e…",
  "keyPrefix": "tth_5b1e2c4f",
  "signingSecret": "9d0a…",
  "customerTokenKey": "tck_77c3…",
  "customerToken": { "algorithm": "HS256", "header": "X-Tether-Customer-Token", "maxLifetimeSeconds": 3600 },
  "configuration": [
    { "part": "catalog", "providerVersion": 3, "tenantVersion": 1 },
    { "part": "domain_pack", "providerVersion": 2, "tenantVersion": 1 },
    { "part": "policy", "providerVersion": 1, "tenantVersion": 1 },
    { "part": "upstream:api", "providerVersion": null, "tenantVersion": null }
  ]
}

apiKey, signingSecret and customerTokenKey are shown once. Your server signs this business's customer tokens with its customerTokenKey, with tenant set to its tenantId. Each business has its own customer-token key and signing secret, so a leak at one business cannot be used at another. name is required, up to 120 characters. A business runs on your plan.

Then register the business's own approvers with its secret key, through PUT /v1/users. Only those people can approve its actions. Your own staff cannot, even though your tenant's policy is the business's starting point.

Routes

Method and pathWhat it does
POST /v1/provider/tenantsCreates a business, as above
GET /v1/provider/tenantsYour businesses: tenantId, name, plan, active, catalogVersion, customerTokenKeyIssued, createdAt
GET /v1/provider/tenants/{id}One of them
POST /v1/provider/tenants/{id}/configurationApplies your current configuration to it again. Answers the copied parts
GET /v1/provider/tenants/{id}/keysIts keys by prefix, kind, label and dates. Never the key itself
POST /v1/provider/tenants/{id}/keysIssues a key. Body: { "kind": "secret" | "publishable" | "agent" | "inbox", "label": "..." }
POST /v1/provider/tenants/{id}/keys/{prefix}/rotateIssues a replacement, then revokes the old key
DELETE /v1/provider/tenants/{id}/keys/{prefix}Revokes a key. Its only live secret key cannot be revoked
POST /v1/provider/tenants/{id}/customer-token-keyReplaces its customer-token key. Tokens signed with the old one are refused at once
GET /v1/provider/outcomesEach business's outcome report and their total, as counts only. from, to, Accept: text/csv
GET /v1/provider/keysYour own inbox and CI keys by prefix, kind (provider_inbox, ci, ci_replace), label and dates
POST /v1/provider/keysIssues an inbox key, tib_, shown once, for every business you created. Body: { "kind": "inbox", "label": "..." }. With { "kind": "ci" } (and optionally "allowReplace": true) it issues a CI key, tci_, on your own tenant, which your repository's runner publishes the template with
POST /v1/provider/keys/{prefix}/rotateIssues a replacement inbox or CI key, then revokes the old one
DELETE /v1/provider/keys/{prefix}Revokes an inbox or CI key; it stops on the next request

Key limits are the same as on Account: ten live keys per business. A provider key cannot be issued for a business.

What a provider cannot do

  • Reach a tenant it did not create. Another provider's business, a business that came to Tether directly, your own tenant and an id that does not exist all get the same answer, so the response does not tell you which tenants exist:
{ "error": { "code": "not_a_child_tenant", "message": "No tenant with that id was created by this provider." } }
  • Read a business's conversations, actions, approvers or audit. Those routes need the business's own key, and a provider key gets 403 insufficient_scope there. What a provider does see is the outcome report of each business it created: counts of conversations, actions, handoffs and cost, with no conversation, action or person in them.
  • Approve a business's actions. Approvals come only from users the business registered. An approval app you run for your businesses, such as the approval inbox, signs those users in through user sessions: with one, your key reaches one business's approval routes as that business's signed-in user, and without one, nothing.
  • Make a business into a provider. Tether grants provider authority to a platform, never to a business a provider created.

Errors

StatusCodeMeaning
400invalid_requestname is missing or longer than 120 characters
400unknown_kindkind is not secret, publishable, agent or inbox (on /v1/provider/keys, not inbox)
403insufficient_scopeNot a provider key, or a provider key on a route outside /v1/provider and /v1/user-sessions without a user session
403not_a_providerThe tenant no longer holds provider authority
404not_a_child_tenantThat id is not a business this provider created
404unknown_keyNo live key with that prefix on that business
409key_limit_reachedThat business already has ten live keys
409last_secret_keyThat is the business's only live secret key; rotate it
409provisioned_tenantPOST /v1/tenants/{id}/provider (operator): the tenant was created by a provider