Agents
An Agent is a persona — a persona prompt, voice/avatar configuration, and (optionally) an attached conversation Workflow — that a caller starts Sessions against. This page is the exhaustive field-by-field reference for every Agent operation. For a conceptual walkthrough of what an Agent is and how it fits into the platform, see Agents and Core API Flow.
All operations on this page require a valid JWT (Authorization: Bearer <token>) issued to a user belonging to the tenant that owns the Agent — see Authentication. Every Agent is scoped to the caller’s tenant: you can never read, update, or delete another tenant’s Agent, even by guessing its id.
Every request in this reference must include the x-huat-platform: customer header in addition to standard GraphQL headers.
The AgentDto type
Section titled “The AgentDto type”All Agent queries and mutations return this shape (mutations return the full, freshly-updated object):
| Field | Type | Notes |
|---|---|---|
id | Int! | |
name | String! | |
personaPrompt | String! | The system prompt defining the agent’s persona/behavior. |
position | String! | Free-text role/title label (e.g. “Support Assistant”). |
subject | String | Free-text subject/domain label. |
openingGreeting | String | Spoken/typed opening line when a session starts, if set. Ignored for any agent with a workflowId attached — see the callout below. |
useCase | AgentUseCase! | Enum — see below. |
status | AgentStatus! | ACTIVE | INACTIVE. |
workflowId | Int | Attached Workflow id, if any. See the workflow-publish gotcha in Workflows — an agent’s workflow must be published, not just saved, to actually run. |
voiceTier | VoiceTier! | STANDARD | WAVENET | NEURAL2. |
ttsVoice | String | TTS voice name — see agentConfigOptions below for valid values. |
ttsLang | String | TTS language code. |
speakingRate | Float | |
vadThreshold | Float! | Voice-activity-detection sensitivity. |
avatarGlb | String | Avatar 3D model filename — see agentConfigOptions. |
avatarGender | AvatarGenderCode | F | M. |
lipsyncLang | String | |
evaluationPromptTemplate | String | Custom prompt used by the async post-session Evaluation. |
evaluationRecommendationLabels | [String!] | Custom label set for Evaluation recommendations. |
externalSyncUrl | String | |
externalSyncSecretRef | String | |
externalSyncOwnerId | Int | |
externalSyncSchemaConfig | JSON | |
llmProviderOverride | LlmProviderType | Pilot — which model provider answers this agent’s turns. See Agents: LLM provider override. null means “use the platform default.” |
llmModelOverride | String | Pilot — which specific model, only meaningful when llmProviderOverride is BEDROCK_MANTLE. See the same section. |
createdAt | DateTime! | |
updatedAt | DateTime! |
openingGreeting does nothing once you attach a workflow
Section titled “openingGreeting does nothing once you attach a workflow”openingGreeting only fires for agents with no workflowId set. The moment an agent has a published workflow attached, the workflow’s own graph is entirely responsible for producing the first reply — including the greeting for a bare “Hi.” — and openingGreeting is silently never read. This is intentional, not a bug to design around: a separate, statically-configured greeting racing against the workflow’s own first response used to produce a double-greeting on session start, which is why the static greeting is skipped entirely for workflow-driven agents rather than trying to sequence the two. If you need a specific greeting behavior for a workflow-driven agent, build it into the workflow graph itself (e.g. a dedicated branch or node for the first turn), not openingGreeting.
enum AgentUseCase { CUSTOM EDUCATION INTERVIEW ONBOARDING SALES SUPPORT}
enum AgentStatus { ACTIVE INACTIVE}voiceTier, useCase, status, and avatarGender are real GraphQL enums — introspect them directly if you need the canonical list ({ __type(name: "AvatarGenderCode") { enumValues { name } } }) rather than hardcoding values from this page.
Queries
Section titled “Queries”Fetches a single Agent by id, scoped to the caller’s tenant. Returns null if not found or not owned by this tenant (never an error — don’t rely on a thrown exception to detect a missing agent).
Auth: JWT
agent(id: ID!): AgentDtoRequest
query GetAgent($id: ID!) { agent(id: $id) { id name personaPrompt useCase status voiceTier workflowId }}{ "id": "42" }POST /graphqlContent-Type: application/jsonAuthorization: Bearer <jwt>x-huat-platform: customerResponse
{ "data": { "agent": { "id": 42, "name": "Support Assistant", "personaPrompt": "You are a helpful support agent for Acme's product line...", "useCase": "SUPPORT", "status": "ACTIVE", "voiceTier": "STANDARD", "workflowId": 7 } }}agents
Section titled “agents”Lists every Agent belonging to the caller’s tenant. Returns a plain array, not a Relay connection — there is no cursor pagination or filtering on this field.
Auth: JWT
agents: [AgentDto!]!Request
query ListAgents { agents { id name status useCase }}Response
{ "data": { "agents": [ { "id": 42, "name": "Support Assistant", "status": "ACTIVE", "useCase": "SUPPORT" }, { "id": 43, "name": "Onboarding Guide", "status": "ACTIVE", "useCase": "ONBOARDING" } ] }}agentCount
Section titled “agentCount”Total number of Agents belonging to the caller’s tenant (includes only non-soft-deleted agents).
Auth: JWT
agentCount: Int!Request
query { agentCount}Response
{ "data": { "agentCount": 2 } }agentConfigOptions
Section titled “agentConfigOptions”Returns every valid option/source for the Agent config fields that are not plain GraphQL enums: the avatar GLB catalog (proxied live from the avatar service, so this list is always current), a curated subset of recommended TTS voices, and doc URLs for the full external catalogs (Google TTS voices, Google STT languages, TalkingHead lipsync modules) that are too large to mirror inline.
Use this query to discover valid values for avatarGlb, ttsVoice, ttsLang, and lipsyncLang — don’t guess or hardcode these strings. voiceTier, useCase, status, and avatarGender are real enums; introspect them directly instead (see above).
Auth: JWT
agentConfigOptions: AgentConfigOptionsDto!AgentConfigOptionsDto fields
| Field | Type | Notes |
|---|---|---|
avatarModels | [AvatarModelDto!]! | Each: { id, filename, label, gender }. |
recommendedTtsVoices | [RecommendedTtsVoiceDto!]! | Each: { name, languageCode, gender, tier }. |
ttsVoiceCatalogUrl | String! | Link to the full external Google TTS voice catalog. |
sttLanguageCatalogUrl | String! | Link to the full external Google STT language catalog. |
lipsyncModuleDocsUrl | String! | Link to TalkingHead lipsync module docs. |
Request
query GetAgentConfigOptions { agentConfigOptions { avatarModels { id filename label gender } recommendedTtsVoices { name languageCode gender tier } ttsVoiceCatalogUrl sttLanguageCatalogUrl lipsyncModuleDocsUrl }}Response
{ "data": { "agentConfigOptions": { "avatarModels": [ { "id": "avatar-01", "filename": "avatar-01.glb", "label": "Avatar 1", "gender": "female" } ], "recommendedTtsVoices": [ { "name": "en-US-Neural2-F", "languageCode": "en-US", "gender": "female", "tier": "NEURAL2" } ], "ttsVoiceCatalogUrl": "https://cloud.google.com/text-to-speech/docs/voices", "sttLanguageCatalogUrl": "https://cloud.google.com/speech-to-text/docs/languages", "lipsyncModuleDocsUrl": "https://docs.talkinghead.example/lipsync-modules" } }}agentAuditLogs
Section titled “agentAuditLogs”This agent’s change history — who changed what, when. Only fields that were actually part of an updateAgent call are recorded; a field set to the value it already had is not recorded. Newest first.
Auth: JWT
agentAuditLogs(id: ID!): [AuditLogDto!]!AuditLogDto fields
| Field | Type | Notes |
|---|---|---|
id | Int! | |
auditableType | String! | Always "Agent" for this query. |
auditableId | Float! | The agent’s own id. |
action | AuditActionEnum! | CREATE, UPDATE, or DELETE — only UPDATE is ever produced by this query today. |
userId | Float | The acting user’s id at write time — a snapshot, not a live reference. |
username | String | The acting user’s name at write time — same snapshot caveat. |
changes | JSONObject | { [field]: { from, to } } — only the fields that actually changed. |
createdAt | DateTime! |
Request
query AgentAuditLogs($id: ID!) { agentAuditLogs(id: $id) { id action userId username changes createdAt }}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 AgentAuditLogs($id: ID!) { agentAuditLogs(id: $id) { id action userId username changes createdAt } }","variables":{"id":"1"}}'Response
{ "data": { "agentAuditLogs": [ { "id": 7, "action": "UPDATE", "userId": 42, "username": "Jane Doe", "changes": { "personaPrompt": { "from": "Old prompt", "to": "New prompt" } }, "createdAt": "2026-09-05T10:00:00.000Z" } ] }}Mutations
Section titled “Mutations”createAgent
Section titled “createAgent”Creates a new Agent (persona) for the caller’s tenant. Does not create a Session — call startSession with the returned id to begin a conversation (see Sessions).
Auth: JWT
createAgent(input: CreateAgentInput!): AgentDto!CreateAgentInput fields
| Field | Type | Required | Notes |
|---|---|---|---|
name | String! | yes | |
personaPrompt | String! | yes | |
position | String! | yes | |
subject | String | no | |
openingGreeting | String | no | |
useCase | AgentUseCase! | no | Defaults to INTERVIEW if omitted. |
voiceTier | VoiceTier! | no | Defaults to STANDARD if omitted. |
ttsVoice | String | no | |
ttsLang | String | no | |
speakingRate | Float | no | |
vadThreshold | Float | no | |
avatarGlb | String | no | |
avatarGender | AvatarGenderCode | no | |
lipsyncLang | String | no | |
evaluationPromptTemplate | String | no | |
evaluationRecommendationLabels | [String!] | no | |
externalSyncUrl | String | no | |
externalSyncSecretRef | String | no | |
externalSyncOwnerId | Int | no | |
externalSyncSchemaConfig | JSON | no | |
llmProviderOverride | LlmProviderType | no | Pilot — see Agents: LLM provider override. |
llmModelOverride | String | no | Pilot — same section. |
Request
mutation CreateAgent($input: CreateAgentInput!) { createAgent(input: $input) { id name status useCase voiceTier }}{ "input": { "name": "Support Assistant", "personaPrompt": "You are a helpful support agent for Acme's product line. Keep answers short and friendly.", "position": "Support Assistant", "useCase": "SUPPORT", "voiceTier": "STANDARD", "ttsVoice": "en-US-Standard-C", "ttsLang": "en-US" }}POST /graphqlContent-Type: application/jsonAuthorization: Bearer <jwt>x-huat-platform: customerResponse
{ "data": { "createAgent": { "id": 42, "name": "Support Assistant", "status": "ACTIVE", "useCase": "SUPPORT", "voiceTier": "STANDARD" } }}updateAgent
Section titled “updateAgent”Updates an existing Agent owned by the caller’s tenant. id is a separate argument, not a field inside input. Every field on UpdateAgentInput is optional — send only what is changing; omitted fields are left untouched (this is a partial update, not a full replace).
Auth: JWT
updateAgent(id: ID!, input: UpdateAgentInput!): AgentDto!UpdateAgentInput fields (all optional)
| Field | Type |
|---|---|
name | String |
personaPrompt | String |
position | String |
subject | String |
openingGreeting | String |
useCase | AgentUseCase |
status | AgentStatus |
voiceTier | VoiceTier |
ttsVoice | String |
ttsLang | String |
speakingRate | Float |
vadThreshold | Float |
avatarGlb | String |
avatarGender | AvatarGenderCode |
lipsyncLang | String |
evaluationPromptTemplate | String |
evaluationRecommendationLabels | [String!] |
externalSyncUrl | String |
externalSyncSecretRef | String |
externalSyncOwnerId | Int |
externalSyncSchemaConfig | JSON |
workflowId | Int |
llmProviderOverride | LlmProviderType |
llmModelOverride | String |
Note that workflowId is only settable via updateAgent, not createAgent — create the Workflow first (see Workflows), then attach it here. Remember a Workflow must be published for a session to actually execute it.
llmProviderOverride/llmModelOverride (pilot — see Agents: LLM provider override) both support detach-to-default: omit the field to leave it unchanged, or send an explicit null to clear it back to “no override.”
Request
mutation UpdateAgent($id: ID!, $input: UpdateAgentInput!) { updateAgent(id: $id, input: $input) { id status workflowId }}{ "id": "42", "input": { "status": "INACTIVE", "workflowId": 7 }}Response
{ "data": { "updateAgent": { "id": 42, "status": "INACTIVE", "workflowId": 7 } }}deleteAgent
Section titled “deleteAgent”Soft-deletes an Agent owned by the caller’s tenant — the row is marked deleted, not removed. Sessions already run against the Agent are unaffected: their history, messages, and Evaluations remain fully readable. A soft-deleted Agent no longer appears in agents/agent(id) results and cannot be used to startSession again.
Auth: JWT
deleteAgent(id: ID!): Boolean!Request
mutation DeleteAgent($id: ID!) { deleteAgent(id: $id)}{ "id": "42" }Response
{ "data": { "deleteAgent": true } }See also
Section titled “See also”- Agents — conceptual guide to what an Agent is and how personas map to conversations
- Sessions — starting and running conversations against an Agent
- Workflows — attaching a visual conversation graph via
workflowId - Core API Flow — the end-to-end narrative from Agent creation to a live session
- Authentication — obtaining the JWT used on every operation on this page
- API Reference: Overview