Skip to content

Tenant API

This page documents every tenant-level operation: fetching your tenant, creating one, updating settings, deleting it, and generating an API key. See Multi-Tenancy for the conceptual model (what a tenant is, how row-level isolation works) and Authentication for the full JWT/API-key auth model — this page cross-links there rather than repeating it.

Every request must include the x-huat-platform: customer header.

Returns the tenant belonging to the authenticated caller.

Auth required: JWT (AuthJwtGuard).

Arguments: None.

Returns: TenantDto (nullable — returns null for a user not yet assigned to a tenant, e.g. immediately after register)

FieldTypeNotes
idInt!
nameString!
planTenantPlanEnum!DEV, PRO, or ENTERPRISE
isSuspendedBoolean!
llmProviderOverrideLlmProviderTypePilot — tenant-wide default LLM provider for every agent that has no agent-level override of its own. See Agents: LLM provider override.
llmModelOverrideStringPilot — only meaningful when llmProviderOverride is BEDROCK_MANTLE. Same section.
allowedLlmModels[String!]Read-only. null means no restriction (the default). Otherwise the model ids this tenant may use, optionally provider:<PROVIDER> entries. Set by a Wetel administrator. See Restricting which models a tenant can use.
primaryBillingAccountPrimaryBillingAccountEnum!WEBBYX_ONE or WETEL — which system bills this tenant’s usage. Set via setPrimaryBillingAccount.
createdAtDateTime!
updatedAtDateTime!
deletedAtDateTimeSet once the tenant has been soft-deleted

Example request:

query MyTenant {
myTenant {
id
name
plan
isSuspended
}
}
Terminal window
curl https://api.wetel.dev/graphql \
-H "Content-Type: application/json" \
-H "x-huat-platform: customer" \
-H "Authorization: Bearer <YOUR_API_KEY>" \
-d '{"query":"query { myTenant { id name plan isSuspended } }"}'

Example response:

{
"data": {
"myTenant": {
"id": 7,
"name": "Acme Support",
"plan": "PRO",
"isSuspended": false
}
}
}

Creates a new tenant.

Auth required: JWT (AuthJwtGuard).

Arguments:

ArgumentTypeRequired
inputCreateTenantInput!Yes

CreateTenantInput:

FieldTypeNotes
nameString!Required
planTenantPlanEnumOptional — DEV, PRO, or ENTERPRISE
regionStringOptional
llmProviderOverrideLlmProviderTypeOptional, pilot — see Agents: LLM provider override.
llmModelOverrideStringOptional, pilot — same section.

Returns: TenantDto! (see shape above)

Example:

mutation CreateTenant($input: CreateTenantInput!) {
createTenant(input: $input) {
id
name
plan
}
}
{ "input": { "name": "Acme Support", "plan": "DEV" } }

Updates the caller’s own tenant.

Auth required: JWT (AuthJwtGuard).

Arguments:

ArgumentTypeRequired
inputUpdateTenantInput!Yes

UpdateTenantInput (every field optional — send only what is changing):

FieldTypeNotes
nameString
planTenantPlanEnum
regionString
isSuspendedBoolean
llmProviderOverrideLlmProviderTypePilot — supports detach-to-default: omit to leave unchanged, send null to clear. See Agents: LLM provider override.
llmModelOverrideStringPilot — same detach-to-default behavior.

Returns: TenantDto!

Example:

mutation UpdateTenant($input: UpdateTenantInput!) {
updateTenant(input: $input) {
id
name
plan
}
}
{ "input": { "name": "Acme Support Inc." } }

Soft-deletes the caller’s own tenant.

Auth required: JWT (AuthJwtGuard).

Arguments: None.

Returns: Boolean!

Example:

mutation DeleteTenant {
deleteTenant
}
Terminal window
curl https://api.wetel.dev/graphql \
-H "Content-Type: application/json" \
-H "x-huat-platform: customer" \
-H "Authorization: Bearer <YOUR_API_KEY>" \
-d '{"query":"mutation { deleteTenant }"}'

Generates a new API key for the current tenant, for authenticating server-to-server operations that don’t use a JWT (for example, the embed SDK’s sdkStart entry point, or the embed query).

For the full picture of how API keys fit into the overall auth model (JWT vs. API key vs. avatar token), see Authentication.

Auth required: JWT (AuthJwtGuard).

Arguments: None.

Returns: GenerateApiKeyResult!

FieldTypeNotes
keyString!The raw API key — shown only this once
warningString!A human-readable reminder about one-time visibility and invalidation of the previous key

Example request:

mutation GenerateApiKey {
generateApiKey {
key
warning
}
}
Terminal window
curl https://api.wetel.dev/graphql \
-H "Content-Type: application/json" \
-H "x-huat-platform: customer" \
-H "Authorization: Bearer <YOUR_API_KEY>" \
-d '{"query":"mutation { generateApiKey { key warning } }"}'

Example response:

{
"data": {
"generateApiKey": {
"key": "<YOUR_API_KEY>",
"warning": "Store this key now — it will not be shown again, and generating a new key invalidates this one immediately."
}
}
}

Returns the LLM spend for the caller’s own tenant for one calendar month (the current month by default, or a past month via yearMonth), the tenant’s monthly spend cap (by plan tier — see LLM API: Monthly spend cap), and a call-count breakdown by model and operation. Backs the dashboard’s Developers page.

Covers all of the tenant’s LLM usage — agent sessions, workflow runs, evaluation, and the LLM API — not just one source. It cannot be broken down by individual named API key; usage is tracked per-tenant only (AiUsageEntity has no apiKeyId column today).

Auth required: JWT (AuthJwtGuard).

Arguments:

ArgumentTypeNotes
yearMonthStringOptional calendar month (UTC) as YYYY-MM, to look at a previous month. Defaults to the current month. A future or malformed value returns 400.

Every figure in the response — cost, credits, buckets and breakdown — covers that one month.

Returns: ApiUsageSummaryDto!

FieldTypeNotes
yearMonthString!The month (YYYY-MM, UTC) every figure covers — your yearMonth argument, or the current month.
costThisMonthUsdFloat!This tenant’s total LLM spend for yearMonth, across all sources (the name predates the yearMonth argument).
monthlySpendCapUsdFloat!The plan-tier cap this tenant is measured against — same limit generateText/startTextGeneration enforce.
breakdown[ApiUsageBreakdownItemDto!]!One row per (model, operation) pair in yearMonth only, most-called first, each with count, costUsd and creditsUsed. model is not always an LLM model — tool, voice and avatar usage appear here too, so label the column “Item”.

Each breakdown row carries creditsUsed: Int!, the credits that item consumed in yearMonth, worked out by the same rule as the bucket the item belongs to. costUsd stays on every row, so existing integrations keep working. Customer-facing dashboards show credits only.

  • Approximate for LLM work. Credits for generate, embed and evaluate rows are an approximation derived from cost.
  • Real charges for everything else. Tool calls (per-action creditsPerCall overrides included), speech (TTS/STT) and avatar rendering are the actual credits charged.
  • Rows add up to their bucket. Within one bucket, the rows’ creditsUsed sum exactly to that bucket’s creditsUsed. Because credits are rounded per operation and then split across that operation’s rows, a single row can differ by at most 1 credit from rounding its own cost alone (two tiny speech rows can read 1 and 0).
  • A row with no bucket reads 0. An operation the pricing model does not charge for has no credits to report.
  • The headline is a different calculation. creditsUsedThisMonthApprox applies one blended rule to the whole month’s cost, so it will not equal the sum of the buckets.

Example request:

query ApiUsageSummary {
apiUsageSummary {
costThisMonthUsd
monthlySpendCapUsd
breakdown {
model
operation
count
costUsd
creditsUsed
}
}
}
# A previous month:
# apiUsageSummary(yearMonth: "2026-08") { ... }
Terminal window
curl https://api.wetel.dev/graphql \
-H "Content-Type: application/json" \
-H "x-huat-platform: customer" \
-H "Authorization: Bearer <YOUR_JWT>" \
-d '{"query":"query { apiUsageSummary { costThisMonthUsd monthlySpendCapUsd breakdown { model operation count costUsd creditsUsed } } }"}'

The signed-in user’s own recorded actions in their workspace: what they created, changed or deleted, newest first. You only ever see your own activity, and only inside your own tenant; there are no userId or tenantId arguments, both come from your token. There is no workspace-wide view for customers yet.

Auth required: JWT (AuthJwtGuard).

Arguments:

ArgumentTypeNotes
firstIntPage size. Default 20, maximum 100.
afterStringThe endCursor of the previous page. A malformed cursor, or one from another query, returns 400.
auditableTypeStringOptional filter on the kind of item, for example Agent or Workflow.
actionAuditActionEnumOptional filter: CREATE, UPDATE or DELETE.

Returns: MyAuditLogConnection! (edges { cursor node }, pageInfo { hasNextPage endCursor }, totalCount).

Node fieldTypeNotes
idInt!
auditableTypeString!Agent, Workflow, ApiKey, CustomAction, McpConnector, ChannelConnector, KnowledgeBase, KnowledgeDocument, ScheduledWorkflow or Tenant (workspace settings).
auditableIdInt!The item’s own id.
actionAuditActionEnum!CREATE, UPDATE or DELETE. Revoking an API key is recorded as DELETE. Publishing a workflow is an UPDATE of its publish fields.
changedFields[String!]!The names of the fields in the request. Never values. Empty for create and delete.
createdAtDateTime!

What is recorded: creating, updating and deleting agents, API keys (create and revoke), workflows (including publish), custom actions, MCP connectors, scheduled workflows and knowledge bases; channel connector create, credential and settings changes, and activate or deactivate; knowledge document deletion; and workspace settings. Not recorded: sessions, messages, workflow runs and usage, knowledge document uploads and re-processing, and reads. Field names come from the request, not from a comparison with the stored value, so an update that sets a field to its current value is still listed. Entries are kept indefinitely.

Example request:

query MyActivity {
myAuditLogs(first: 20, auditableType: "Workflow") {
totalCount
pageInfo {
hasNextPage
endCursor
}
edges {
node {
id
auditableType
auditableId
action
changedFields
createdAt
}
}
}
}

For creating and configuring the agents that live inside a tenant, see Agents. For the full signup-to-first-agent walkthrough, see Getting Started.