Skip to content

Agents

This content is not available in your language yet.

An agent is the persona a session talks to: its name, its persona prompt, its voice settings and the workflow that decides what it does on each turn. Creating and changing agents takes a dashboard JWT. An agent runs a workflow only after you attach one with updateAgent (field workflowId) and that workflow is published.

Every operation is a POST of { "query", "variables" } to https://api.wetel.dev/graphql (sandbox) with the x-huat-platform: customer header and the credential shown. New here? Start with the Quickstart and the Authentication cheat sheet. Errors are listed in Errors; Postman and OpenAPI files are on Downloads.

OperationKindCredentialWhat it does
agentsqueryDashboard JWTList every agent in your workspace (a plain list, not paginated).
agentqueryDashboard JWTRead one agent by id.
createAgentmutationDashboard JWTCreate an agent. It has no workflow until you attach one with updateAgent.
updateAgentmutationDashboard JWTChange an agent. Send only the fields that change; attach a workflow with workflowId.

List every agent in your workspace (a plain list, not paginated).

  • Kind: query
  • Credential: Dashboard JWT: Authorization: Bearer <jwt>, from login (a person or a one-off script)
  • Available in: sandbox and production

Request

query ListAgents {
agents {
id
name
status
useCase
workflowId
}
}
variables
{}

Allowed values

  • AgentStatus: ACTIVE, INACTIVE
  • AgentUseCase: CUSTOM, EDUCATION, INTERVIEW, ONBOARDING, SALES, SUPPORT

Code samples

agents.sh
#!/usr/bin/env bash
# agents: List every agent in your workspace (a plain list, not paginated).
# Credential: Dashboard JWT (WETEL_JWT).
API_URL="${WETEL_API_URL:-https://api.wetel.dev/graphql}"
curl -sS "$API_URL" \
-H "Content-Type: application/json" \
-H "x-huat-platform: customer" \
-H "Authorization: Bearer $WETEL_JWT" \
--data-binary @- <<'JSON'
{
"query": "query ListAgents{agents{id name status useCase workflowId}}",
"variables": {}
}
JSON

Responses

Success (HTTP 200)

{
"data": {
"agents": [
{
"id": 7,
"name": "Helpdesk triage",
"status": "ACTIVE",
"useCase": "SUPPORT",
"workflowId": 12
},
{
"id": 9,
"name": "Onboarding guide",
"status": "INACTIVE",
"useCase": "ONBOARDING",
"workflowId": null
}
]
}
}
UNAUTHENTICATED: Called with an API key instead of a JWT (HTTP 200)
{
"errors": [
{
"message": "Unauthorized",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"agents"
],
"extensions": {
"code": "UNAUTHENTICATED",
"originalError": {
"message": "Unauthorized",
"statusCode": 401
}
}
}
],
"data": null
}

Read one agent by id.

  • Kind: query
  • Credential: Dashboard JWT: Authorization: Bearer <jwt>, from login (a person or a one-off script)
  • Available in: sandbox and production
  • Returns null (not an error) when the id does not exist in your workspace.

Request

query OneAgent($id: ID!) {
agent(id: $id) {
id
name
position
personaPrompt
openingGreeting
status
useCase
voiceTier
timezone
workflowId
}
}
variables
{
"id": "7"
}

Allowed values

  • AgentStatus: ACTIVE, INACTIVE
  • AgentUseCase: CUSTOM, EDUCATION, INTERVIEW, ONBOARDING, SALES, SUPPORT
  • VoiceTier: CHIRP3_HD, NEURAL2, STANDARD, STUDIO, WAVENET

Code samples

agent.sh
#!/usr/bin/env bash
# agent: Read one agent by id.
# Credential: Dashboard JWT (WETEL_JWT).
API_URL="${WETEL_API_URL:-https://api.wetel.dev/graphql}"
curl -sS "$API_URL" \
-H "Content-Type: application/json" \
-H "x-huat-platform: customer" \
-H "Authorization: Bearer $WETEL_JWT" \
--data-binary @- <<'JSON'
{
"query": "query OneAgent($id:ID!){agent(id:$id){id name position personaPrompt openingGreeting status useCase voiceTier timezone workflowId}}",
"variables": {
"id": "7"
}
}
JSON

Responses

Success (HTTP 200)

{
"data": {
"agent": {
"id": 7,
"name": "Helpdesk triage",
"position": "IT helpdesk assistant",
"personaPrompt": "You are a calm, precise IT helpdesk assistant. Ask one question at a time and never promise a fix you cannot make.",
"openingGreeting": "Hi, I can log an IT ticket for you. What is the problem?",
"status": "ACTIVE",
"useCase": "SUPPORT",
"voiceTier": "STANDARD",
"timezone": "Asia/Kuala_Lumpur",
"workflowId": 12
}
}
}

Not in your workspace (HTTP 200)

{
"data": {
"agent": null
}
}
UNAUTHENTICATED: Called with an API key instead of a JWT (HTTP 200)
{
"errors": [
{
"message": "Unauthorized",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"agent"
],
"extensions": {
"code": "UNAUTHENTICATED",
"originalError": {
"message": "Unauthorized",
"statusCode": 401
}
}
}
],
"data": {
"agent": null
}
}

Create an agent. It has no workflow until you attach one with updateAgent.

  • Kind: mutation
  • Credential: Dashboard JWT: Authorization: Bearer <jwt>, from login (a person or a one-off script)
  • Available in: sandbox and production
  • [object Object]
  • useCase: CUSTOM also needs evaluationPromptTemplate (with a {transcript} placeholder) and evaluationRecommendationLabels.
  • openingGreeting is a fixed first message; without it the opening line is generated by a model on every session.

Request

mutation CreateAgent($input: CreateAgentInput!) {
createAgent(input: $input) {
id
name
status
workflowId
}
}
variables
{
"input": {
"name": "Helpdesk triage",
"position": "IT helpdesk assistant",
"personaPrompt": "You are a calm, precise IT helpdesk assistant. Ask one question at a time and never promise a fix you cannot make.",
"openingGreeting": "Hi, I can log an IT ticket for you. What is the problem?",
"useCase": "SUPPORT",
"voiceTier": "STANDARD",
"avatarBackend": "CLIENT_3D"
}
}

Input fields

CreateAgentInput

FieldTypeRequiredDescription
avatarBackendAvatarBackendType!yesHow clients render the avatar (default CLIENT_3D).
avatarBackendConfigJSONnoSettings for a HOSTED_API avatar, a JSON object with the hosted avatar id and model (pass it through variables); no secrets. Not needed for CLIENT_3D.
avatarGenderAvatarGenderCodenoGender of the avatar model (default F).
avatarGlbStringnoFile name of the 3D avatar model: lower-case letters, digits, ”-” or ”_”, ending in .glb (at most 100 characters; default “brunette-t.glb”). agentConfigOptions lists the available models.
evaluationPromptTemplateStringnoYour own evaluation prompt (at most 10000 characters), required when useCase is CUSTOM and then it must contain {transcript}; it may also use {subject} and {recommendationLabels}.
evaluationRecommendationLabels[String!]noRecommendation labels a CUSTOM evaluation may return (at most 20, each at most 50 characters), required when useCase is CUSTOM.
externalSyncOwnerIdIntnoOwner id your endpoint expects when the mirrored conversation is created (a positive integer of your system).
externalSyncSchemaConfigJSONnoOptional overrides for how mirrored turns are written to externalSyncUrl: a JSON object with any of conversationInputTypeName, messageInputTypeName, userRoleValue, assistantRoleValue.
externalSyncSecretRefStringnoReference to a secret stored for your workspace whose value is sent as the bearer token to externalSyncUrl (at most 200 characters; never the secret itself). A reference belonging to another workspace is refused.
externalSyncUrlStringnoURL of your own GraphQL endpoint that receives a best-effort copy of each turn the workflow answers (at most 2000 characters). Private and internal addresses are refused.
lipsyncLangStringnoShort language code for 3D avatar lip-sync, such as “en” (at most 10 characters; default “en”).
llmModelOverrideStringnoSpecific model id from llmModelCatalog (at most 100 characters). Set alone, the provider that serves it is used; a model no enabled provider serves, a llmProviderOverride that does not serve it, or a model outside the workspace allowlist is refused. Omit for the provider default.
llmProviderOverrideLlmProviderTypenoModel provider for this agent; omit to use the workspace setting or the platform default.
nameString!yesDisplay name (at most 100 characters).
openingGreetingStringnoFixed opening line, a template that may use {{clientExternalId}} (at most 2000 characters). Sent when a session starts on an agent without a workflow; without it the model writes a greeting.
personaPromptString!yesSystem prompt: identity, tone and boundaries of the agent (at most 10000 characters).
positionString!yesRole title, for example “Support Specialist” (at most 200 characters); also the evaluation subject when subject is empty.
speakingRateFloatnoText-to-speech speaking rate, 0.25 to 4.0 where 1.0 is normal (default 1.0).
sttAlternativeLanguageCodes[String!]noSpeech-to-text fallback languages besides the primary (BCP-47). null/omitted = the platform default: English (“en-US”) and Malay (“ms-MY”), minus the primary. [] = recognise in the primary only. A list = exactly those languages, at most 3: Google silently ignores the ENTIRE list past 3, so more is rejected rather than truncated. Mandarin and Cantonese are NOT in the default, so list “cmn-Hans-CN” / “yue-Hant-HK” explicitly when Chinese speech is expected. Duplicates, and an entry equal to the effective primary (sttLanguageCode, else ttsLang), are rejected.
sttLanguageCodeStringnoSpeech-to-text PRIMARY language (BCP-47, e.g. “en-US”, “ms-MY”, “cmn-Hans-CN”): the language most callers speak. null/omitted means “use ttsLang”. Separate from ttsLang so an agent can reply in one language but mostly hear another. The primary biases recognition much more than the alternatives, so never set a secondary language here.
subjectStringnoWhat sessions are about (the job, product or course), used by the evaluation prompt; position is used when empty (at most 200 characters).
timezoneStringnoIANA timezone of this agent (e.g. “Asia/Kuala_Lumpur”, “America/New_York”). Used by the {{today}} and {{now}} workflow template helpers. Defaults to Asia/Kuala_Lumpur.
ttsLangStringnoLanguage the agent speaks, a BCP-47 code such as “en-US” (at most 20 characters; default “en-US”).
ttsVoiceStringnoText-to-speech voice name, for example “en-US-Neural2-F” (at most 100 characters; default “en-US-Standard-C”). See agentConfigOptions for recommended voices.
useCaseAgentUseCase!yesKind of conversation; selects how finished sessions are evaluated (default INTERVIEW). CUSTOM requires evaluationPromptTemplate and evaluationRecommendationLabels.
vadThresholdFloatnoVoice-activity detection threshold for the microphone, 0.1 to 1.0 (default 0.8).
voiceTierVoiceTier!yesVoice quality tier label (default STANDARD).

Allowed values

  • AvatarBackendType: CLIENT_3D, HOSTED_API, SELF_HOSTED_VIDEO_STREAM
  • AvatarGenderCode: F, M
  • LlmProviderType: BEDROCK_MANTLE, GEMINI_DIRECT (plus 1 internal value, not listed)
  • AgentUseCase: CUSTOM, EDUCATION, INTERVIEW, ONBOARDING, SALES, SUPPORT
  • VoiceTier: CHIRP3_HD, NEURAL2, STANDARD, STUDIO, WAVENET
  • AgentStatus: ACTIVE, INACTIVE

Code samples

createAgent.sh
#!/usr/bin/env bash
# createAgent: Create an agent. It has no workflow until you attach one with updateAgent.
# Credential: Dashboard JWT (WETEL_JWT).
API_URL="${WETEL_API_URL:-https://api.wetel.dev/graphql}"
curl -sS "$API_URL" \
-H "Content-Type: application/json" \
-H "x-huat-platform: customer" \
-H "Authorization: Bearer $WETEL_JWT" \
--data-binary @- <<'JSON'
{
"query": "mutation CreateAgent($input:CreateAgentInput!){createAgent(input:$input){id name status workflowId}}",
"variables": {
"input": {
"name": "Helpdesk triage",
"position": "IT helpdesk assistant",
"personaPrompt": "You are a calm, precise IT helpdesk assistant. Ask one question at a time and never promise a fix you cannot make.",
"openingGreeting": "Hi, I can log an IT ticket for you. What is the problem?",
"useCase": "SUPPORT",
"voiceTier": "STANDARD",
"avatarBackend": "CLIENT_3D"
}
}
}
JSON

Responses

Success (HTTP 200)

{
"data": {
"createAgent": {
"id": 7,
"name": "Helpdesk triage",
"status": "ACTIVE",
"workflowId": null
}
}
}
BAD_REQUEST: CUSTOM use case without an evaluation prompt (HTTP 200)
{
"errors": [
{
"message": "CUSTOM use case requires evaluationPromptTemplate",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"createAgent"
],
"extensions": {
"code": "BAD_REQUEST",
"originalError": {
"message": "CUSTOM use case requires evaluationPromptTemplate",
"error": "Bad Request",
"statusCode": 400
}
}
}
],
"data": null
}
BAD_USER_INPUT: A required field is missing (HTTP 400)

Sent with variables:

{
"input": {
"name": "Helpdesk triage",
"personaPrompt": "You are a calm, precise IT helpdesk assistant.",
"useCase": "SUPPORT",
"voiceTier": "STANDARD",
"avatarBackend": "CLIENT_3D"
}
}
{
"errors": [
{
"message": "Variable \"$input\" got invalid value { name: \"Helpdesk triage\", personaPrompt: \"You are a calm, precise IT helpdesk assistant.\", useCase: \"SUPPORT\", voiceTier: \"STANDARD\", avatarBackend: \"CLIENT_3D\" }; Field \"position\" of required type \"String!\" was not provided.",
"locations": [
{
"line": 1,
"column": 22
}
],
"extensions": {
"code": "BAD_USER_INPUT"
}
}
]
}
BAD_USER_INPUT: Unknown enum value (HTTP 400)

Sent with variables:

{
"input": {
"name": "Helpdesk triage",
"position": "IT helpdesk assistant",
"personaPrompt": "You are a calm, precise IT helpdesk assistant.",
"useCase": "HELPDESK",
"voiceTier": "STANDARD",
"avatarBackend": "CLIENT_3D"
}
}
{
"errors": [
{
"message": "Variable \"$input\" got invalid value \"HELPDESK\" at \"input.useCase\"; Value \"HELPDESK\" does not exist in \"AgentUseCase\" enum.",
"locations": [
{
"line": 1,
"column": 22
}
],
"extensions": {
"code": "BAD_USER_INPUT"
}
}
]
}

Change an agent. Send only the fields that change; attach a workflow with workflowId.

  • Kind: mutation
  • Credential: Dashboard JWT: Authorization: Bearer <jwt>, from login (a person or a one-off script)
  • Available in: sandbox and production
  • id is a separate argument, not a field of input.
  • The workflow you attach must belong to your workspace. Sessions run its **published** version, so publish it first (see Workflows).
  • Set status to INACTIVE to stop new tasks from running against the agent.

Request

mutation UpdateAgent($id: ID!, $input: UpdateAgentInput!) {
updateAgent(id: $id, input: $input) {
id
workflowId
status
updatedAt
}
}
variables
{
"id": "7",
"input": {
"workflowId": 12
}
}

Input fields

UpdateAgentInput

FieldTypeRequiredDescription
avatarBackendAvatarBackendTypenoHow clients render the avatar. Omit to leave unchanged; null is refused.
avatarBackendConfigJSONnoSettings for a HOSTED_API avatar, a JSON object with the hosted avatar id and model (pass it through variables); no secrets. Not needed for CLIENT_3D. Omit to leave unchanged; null is refused.
avatarGenderAvatarGenderCodenoGender of the avatar model (default F). Omit to leave unchanged; null is refused.
avatarGlbStringnoFile name of the 3D avatar model: lower-case letters, digits, ”-” or ”_”, ending in .glb (at most 100 characters; default “brunette-t.glb”). agentConfigOptions lists the available models. Omit to leave unchanged; null is refused.
evaluationPromptTemplateStringnoYour own evaluation prompt (at most 10000 characters), required when useCase is CUSTOM and then it must contain {transcript}; it may also use {subject} and {recommendationLabels}. Omit to leave unchanged; null is refused.
evaluationRecommendationLabels[String!]noRecommendation labels a CUSTOM evaluation may return (at most 20, each at most 50 characters), required when useCase is CUSTOM. Omit to leave unchanged; null is refused.
externalSyncOwnerIdIntnoOwner id your endpoint expects when the mirrored conversation is created (a positive integer of your system). Omit to leave unchanged; null is refused.
externalSyncSchemaConfigJSONnoOptional overrides for how mirrored turns are written to externalSyncUrl: a JSON object with any of conversationInputTypeName, messageInputTypeName, userRoleValue, assistantRoleValue. Omit to leave unchanged; null is refused.
externalSyncSecretRefStringnoReference to a secret stored for your workspace whose value is sent as the bearer token to externalSyncUrl (at most 200 characters; never the secret itself). A reference belonging to another workspace is refused. Omit to leave unchanged; null is refused.
externalSyncUrlStringnoURL of your own GraphQL endpoint that receives a best-effort copy of each turn the workflow answers (at most 2000 characters). Private and internal addresses are refused. Omit to leave unchanged; null is refused.
lipsyncLangStringnoShort language code for 3D avatar lip-sync, such as “en” (at most 10 characters; default “en”). Omit to leave unchanged; null is refused.
llmModelOverrideStringnoSpecific model id from llmModelCatalog (at most 100 characters); send null to clear it. Set alone, the provider that serves it is used; an unknown model, a provider mismatch or a model outside the workspace allowlist is refused.
llmProviderOverrideLlmProviderTypenoModel provider for this agent; send null to clear the override (back to the workspace setting or platform default).
nameStringnoDisplay name (at most 100 characters). Omit to leave unchanged; null is refused.
openingGreetingStringnoFixed opening line, a template that may use {{clientExternalId}} (at most 2000 characters). Sent when a session starts on an agent without a workflow; without it the model writes a greeting. Omit to leave unchanged; null is refused.
personaPromptStringnoSystem prompt: identity, tone and boundaries of the agent (at most 10000 characters). Omit to leave unchanged; null is refused.
positionStringnoRole title, for example “Support Specialist” (at most 200 characters); also the evaluation subject when subject is empty. Omit to leave unchanged; null is refused.
speakingRateFloatnoText-to-speech speaking rate, 0.25 to 4.0 where 1.0 is normal (default 1.0). Omit to leave unchanged; null is refused.
statusAgentStatusnoACTIVE or INACTIVE. An INACTIVE agent is not picked as the default by sdkStart and is refused by runWorkflowTask. Omit to leave unchanged; null is refused.
sttAlternativeLanguageCodes[String!]noSpeech-to-text fallback languages besides the primary (BCP-47). null/omitted = the platform default: English (“en-US”) and Malay (“ms-MY”), minus the primary. [] = recognise in the primary only. A list = exactly those languages, at most 3: Google silently ignores the ENTIRE list past 3, so more is rejected rather than truncated. Mandarin and Cantonese are NOT in the default, so list “cmn-Hans-CN” / “yue-Hant-HK” explicitly when Chinese speech is expected. Duplicates, and an entry equal to the effective primary (sttLanguageCode, else ttsLang), are rejected.
sttLanguageCodeStringnoSpeech-to-text PRIMARY language (BCP-47, e.g. “en-US”, “ms-MY”, “cmn-Hans-CN”): the language most callers speak. null/omitted means “use ttsLang”. Separate from ttsLang so an agent can reply in one language but mostly hear another. The primary biases recognition much more than the alternatives, so never set a secondary language here.
subjectStringnoWhat sessions are about (the job, product or course), used by the evaluation prompt; position is used when empty (at most 200 characters). Omit to leave unchanged; null is refused.
timezoneStringnoIANA timezone of this agent (e.g. “Asia/Kuala_Lumpur”, “America/New_York”). Used by the {{today}} and {{now}} workflow template helpers. Defaults to Asia/Kuala_Lumpur.
ttsLangStringnoLanguage the agent speaks, a BCP-47 code such as “en-US” (at most 20 characters; default “en-US”). Omit to leave unchanged; null is refused.
ttsVoiceStringnoText-to-speech voice name, for example “en-US-Neural2-F” (at most 100 characters; default “en-US-Standard-C”). See agentConfigOptions for recommended voices. Omit to leave unchanged; null is refused.
useCaseAgentUseCasenoKind of conversation. Switching to CUSTOM requires evaluationPromptTemplate and evaluationRecommendationLabels in the same call. Omit to leave unchanged; null is refused.
vadThresholdFloatnoVoice-activity detection threshold for the microphone, 0.1 to 1.0 (default 0.8). Omit to leave unchanged; null is refused.
voiceTierVoiceTiernoVoice quality tier label. Omit to leave unchanged; null is refused.
workflowIdIntnoAttach a workflow of your workspace (its published version drives every turn; publish it first). An unknown id is refused. It cannot be detached by sending null. Omit to leave unchanged.

Allowed values

  • AvatarBackendType: CLIENT_3D, HOSTED_API, SELF_HOSTED_VIDEO_STREAM
  • AvatarGenderCode: F, M
  • LlmProviderType: BEDROCK_MANTLE, GEMINI_DIRECT (plus 1 internal value, not listed)
  • AgentStatus: ACTIVE, INACTIVE
  • AgentUseCase: CUSTOM, EDUCATION, INTERVIEW, ONBOARDING, SALES, SUPPORT
  • VoiceTier: CHIRP3_HD, NEURAL2, STANDARD, STUDIO, WAVENET

Code samples

updateAgent.sh
#!/usr/bin/env bash
# updateAgent: Change an agent. Send only the fields that change; attach a workflow with workflowId.
# Credential: Dashboard JWT (WETEL_JWT).
API_URL="${WETEL_API_URL:-https://api.wetel.dev/graphql}"
curl -sS "$API_URL" \
-H "Content-Type: application/json" \
-H "x-huat-platform: customer" \
-H "Authorization: Bearer $WETEL_JWT" \
--data-binary @- <<'JSON'
{
"query": "mutation UpdateAgent($id:ID!$input:UpdateAgentInput!){updateAgent(id:$id input:$input){id workflowId status updatedAt}}",
"variables": {
"id": "7",
"input": {
"workflowId": 12
}
}
}
JSON

Responses

Success (HTTP 200)

{
"data": {
"updateAgent": {
"id": 7,
"workflowId": 12,
"status": "ACTIVE",
"updatedAt": "2026-10-12T04:02:19.311Z"
}
}
}
NOT_FOUND: Agent not in your workspace (HTTP 200)
{
"errors": [
{
"message": "Agent 7 not found",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"updateAgent"
],
"extensions": {
"code": "NOT_FOUND",
"status": 404,
"originalError": {
"message": "Agent 7 not found",
"error": "Not Found",
"statusCode": 404
}
}
}
],
"data": null
}
BAD_REQUEST: Workflow not in your workspace (HTTP 200)
{
"errors": [
{
"message": "Workflow 12 not found for this tenant",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"updateAgent"
],
"extensions": {
"code": "BAD_REQUEST",
"originalError": {
"message": "Workflow 12 not found for this tenant",
"error": "Bad Request",
"statusCode": 400
}
}
}
],
"data": null
}