Agents
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.
| Operation | Kind | Credential | What it does |
|---|---|---|---|
agents | query | Dashboard JWT | List every agent in your workspace (a plain list, not paginated). |
agent | query | Dashboard JWT | Read one agent by id. |
createAgent | mutation | Dashboard JWT | Create an agent. It has no workflow until you attach one with updateAgent. |
updateAgent | mutation | Dashboard JWT | Change an agent. Send only the fields that change; attach a workflow with workflowId. |
agents
Section titled “agents”List every agent in your workspace (a plain list, not paginated).
- Kind: query
- Credential: Dashboard JWT:
Authorization: Bearer <jwt>, fromlogin(a person or a one-off script) - Available in: sandbox and production
Request
query ListAgents { agents { id name status useCase workflowId }}{}Allowed values
AgentStatus:ACTIVE,INACTIVEAgentUseCase:CUSTOM,EDUCATION,INTERVIEW,ONBOARDING,SALES,SUPPORT
Code samples
#!/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// agents: List every agent in your workspace (a plain list, not paginated).// Credential: Dashboard JWT (WETEL_JWT). Node 18+ (built-in fetch).const API_URL = process.env.WETEL_API_URL ?? "https://api.wetel.dev/graphql";
const query = `query ListAgents { agents { id name status useCase workflowId }}`;
const variables = {};
type GraphQLResponse = { data?: Record<string, unknown>; errors?: { message: string; extensions?: { code?: string } }[];};
async function main(): Promise<void> { const res = await fetch(API_URL, { method: "POST", headers: { "Content-Type": "application/json", "x-huat-platform": "customer", Authorization: `Bearer ${process.env.WETEL_JWT ?? ""}`, }, body: JSON.stringify({ query, variables }), }); const body = (await res.json()) as GraphQLResponse; if (body.errors?.length) { const error = body.errors[0]; throw new Error(`${error.extensions?.code}: ${error.message}`); } console.log(JSON.stringify(body.data?.agents, null, 2));}
main().catch(err => { console.error(err); process.exit(1);});
export {};<?php// agents: List every agent in your workspace (a plain list, not paginated).// Credential: Dashboard JWT (WETEL_JWT). PHP 7.3+ with the curl extension.$apiUrl = getenv('WETEL_API_URL') ?: 'https://api.wetel.dev/graphql';
$query = <<<'GRAPHQL'query ListAgents { agents { id name status useCase workflowId }}GRAPHQL;
$variables = json_decode(<<<'JSON'{}JSON);
$ch = curl_init($apiUrl);curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'x-huat-platform: customer', 'Authorization: Bearer ' . getenv('WETEL_JWT'), ], CURLOPT_POSTFIELDS => json_encode(['query' => $query, 'variables' => $variables]),]);$body = json_decode(curl_exec($ch), true);curl_close($ch);
if (!empty($body['errors'])) { $error = $body['errors'][0]; fwrite(STDERR, ($error['extensions']['code'] ?? 'ERROR') . ': ' . $error['message'] . PHP_EOL); exit(1);}echo json_encode($body['data']['agents'], JSON_PRETTY_PRINT), PHP_EOL;// agents: List every agent in your workspace (a plain list, not paginated).// Credential: Dashboard JWT (WETEL_JWT). .NET 8: put this in Program.cs of a console app and run "dotnet run".using System.Net.Http.Headers;using System.Net.Http.Json;using System.Text.Json;using System.Text.Json.Nodes;
var apiUrl = Environment.GetEnvironmentVariable("WETEL_API_URL") ?? "https://api.wetel.dev/graphql";
const string query = """ query ListAgents { agents { id name status useCase workflowId } } """;
var variables = JsonNode.Parse(""" {} """);
using var http = new HttpClient();using var request = new HttpRequestMessage(HttpMethod.Post, apiUrl){ Content = JsonContent.Create(new { query, variables }),};request.Headers.Add("x-huat-platform", "customer");request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("WETEL_JWT"));
using var response = await http.SendAsync(request);var body = JsonNode.Parse(await response.Content.ReadAsStringAsync())!;if (body["errors"] is JsonArray errors && errors.Count > 0){ Console.Error.WriteLine($"{errors[0]?["extensions"]?["code"]}: {errors[0]?["message"]}"); return 1;}Console.WriteLine(body["data"]?["agents"]?.ToJsonString(new JsonSerializerOptions { WriteIndented = true }));return 0;# agents: List every agent in your workspace (a plain list, not paginated).# Credential: Dashboard JWT (WETEL_JWT). Python 3.8+ with "requests".import jsonimport os
import requests
API_URL = os.environ.get("WETEL_API_URL", "https://api.wetel.dev/graphql")
QUERY = """query ListAgents { agents { id name status useCase workflowId }}"""
VARIABLES = {}
response = requests.post( API_URL, json={"query": QUERY, "variables": VARIABLES}, headers={ "x-huat-platform": "customer", "Authorization": "Bearer " + os.environ["WETEL_JWT"], }, timeout=30,)body = response.json()if body.get("errors"): error = body["errors"][0] raise SystemExit(f"{error.get('extensions', {}).get('code')}: {error['message']}")print(json.dumps(body["data"]["agents"], indent=2))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>, fromlogin(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 }}{ "id": "7"}Allowed values
AgentStatus:ACTIVE,INACTIVEAgentUseCase:CUSTOM,EDUCATION,INTERVIEW,ONBOARDING,SALES,SUPPORTVoiceTier:CHIRP3_HD,NEURAL2,STANDARD,STUDIO,WAVENET
Code samples
#!/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// agent: Read one agent by id.// Credential: Dashboard JWT (WETEL_JWT). Node 18+ (built-in fetch).const API_URL = process.env.WETEL_API_URL ?? "https://api.wetel.dev/graphql";
const query = `query OneAgent($id: ID!) { agent(id: $id) { id name position personaPrompt openingGreeting status useCase voiceTier timezone workflowId }}`;
const variables = { id: "7",};
type GraphQLResponse = { data?: Record<string, unknown>; errors?: { message: string; extensions?: { code?: string } }[];};
async function main(): Promise<void> { const res = await fetch(API_URL, { method: "POST", headers: { "Content-Type": "application/json", "x-huat-platform": "customer", Authorization: `Bearer ${process.env.WETEL_JWT ?? ""}`, }, body: JSON.stringify({ query, variables }), }); const body = (await res.json()) as GraphQLResponse; if (body.errors?.length) { const error = body.errors[0]; throw new Error(`${error.extensions?.code}: ${error.message}`); } console.log(JSON.stringify(body.data?.agent, null, 2));}
main().catch(err => { console.error(err); process.exit(1);});
export {};<?php// agent: Read one agent by id.// Credential: Dashboard JWT (WETEL_JWT). PHP 7.3+ with the curl extension.$apiUrl = getenv('WETEL_API_URL') ?: 'https://api.wetel.dev/graphql';
$query = <<<'GRAPHQL'query OneAgent($id: ID!) { agent(id: $id) { id name position personaPrompt openingGreeting status useCase voiceTier timezone workflowId }}GRAPHQL;
$variables = json_decode(<<<'JSON'{ "id": "7"}JSON);
$ch = curl_init($apiUrl);curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'x-huat-platform: customer', 'Authorization: Bearer ' . getenv('WETEL_JWT'), ], CURLOPT_POSTFIELDS => json_encode(['query' => $query, 'variables' => $variables]),]);$body = json_decode(curl_exec($ch), true);curl_close($ch);
if (!empty($body['errors'])) { $error = $body['errors'][0]; fwrite(STDERR, ($error['extensions']['code'] ?? 'ERROR') . ': ' . $error['message'] . PHP_EOL); exit(1);}echo json_encode($body['data']['agent'], JSON_PRETTY_PRINT), PHP_EOL;// agent: Read one agent by id.// Credential: Dashboard JWT (WETEL_JWT). .NET 8: put this in Program.cs of a console app and run "dotnet run".using System.Net.Http.Headers;using System.Net.Http.Json;using System.Text.Json;using System.Text.Json.Nodes;
var apiUrl = Environment.GetEnvironmentVariable("WETEL_API_URL") ?? "https://api.wetel.dev/graphql";
const string query = """ query OneAgent($id: ID!) { agent(id: $id) { id name position personaPrompt openingGreeting status useCase voiceTier timezone workflowId } } """;
var variables = JsonNode.Parse(""" { "id": "7" } """);
using var http = new HttpClient();using var request = new HttpRequestMessage(HttpMethod.Post, apiUrl){ Content = JsonContent.Create(new { query, variables }),};request.Headers.Add("x-huat-platform", "customer");request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("WETEL_JWT"));
using var response = await http.SendAsync(request);var body = JsonNode.Parse(await response.Content.ReadAsStringAsync())!;if (body["errors"] is JsonArray errors && errors.Count > 0){ Console.Error.WriteLine($"{errors[0]?["extensions"]?["code"]}: {errors[0]?["message"]}"); return 1;}Console.WriteLine(body["data"]?["agent"]?.ToJsonString(new JsonSerializerOptions { WriteIndented = true }));return 0;# agent: Read one agent by id.# Credential: Dashboard JWT (WETEL_JWT). Python 3.8+ with "requests".import jsonimport os
import requests
API_URL = os.environ.get("WETEL_API_URL", "https://api.wetel.dev/graphql")
QUERY = """query OneAgent($id: ID!) { agent(id: $id) { id name position personaPrompt openingGreeting status useCase voiceTier timezone workflowId }}"""
VARIABLES = { "id": "7",}
response = requests.post( API_URL, json={"query": QUERY, "variables": VARIABLES}, headers={ "x-huat-platform": "customer", "Authorization": "Bearer " + os.environ["WETEL_JWT"], }, timeout=30,)body = response.json()if body.get("errors"): error = body["errors"][0] raise SystemExit(f"{error.get('extensions', {}).get('code')}: {error['message']}")print(json.dumps(body["data"]["agent"], indent=2))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 }}createAgent
Section titled “createAgent”Create an agent. It has no workflow until you attach one with updateAgent.
- Kind: mutation
- Credential: Dashboard JWT:
Authorization: Bearer <jwt>, fromlogin(a person or a one-off script) - Available in: sandbox and production
- [object Object]
useCase: CUSTOMalso needsevaluationPromptTemplate(with a{transcript}placeholder) andevaluationRecommendationLabels.openingGreetingis 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 }}{ "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
| Field | Type | Required | Description |
|---|---|---|---|
avatarBackend | AvatarBackendType! | yes | How clients render the avatar (default CLIENT_3D). |
avatarBackendConfig | JSON | no | Settings 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. |
avatarGender | AvatarGenderCode | no | Gender of the avatar model (default F). |
avatarGlb | String | no | File 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. |
evaluationPromptTemplate | String | no | Your 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!] | no | Recommendation labels a CUSTOM evaluation may return (at most 20, each at most 50 characters), required when useCase is CUSTOM. |
externalSyncOwnerId | Int | no | Owner id your endpoint expects when the mirrored conversation is created (a positive integer of your system). |
externalSyncSchemaConfig | JSON | no | Optional overrides for how mirrored turns are written to externalSyncUrl: a JSON object with any of conversationInputTypeName, messageInputTypeName, userRoleValue, assistantRoleValue. |
externalSyncSecretRef | String | no | Reference 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. |
externalSyncUrl | String | no | URL 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. |
lipsyncLang | String | no | Short language code for 3D avatar lip-sync, such as “en” (at most 10 characters; default “en”). |
llmModelOverride | String | no | Specific 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. |
llmProviderOverride | LlmProviderType | no | Model provider for this agent; omit to use the workspace setting or the platform default. |
name | String! | yes | Display name (at most 100 characters). |
openingGreeting | String | no | Fixed 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. |
personaPrompt | String! | yes | System prompt: identity, tone and boundaries of the agent (at most 10000 characters). |
position | String! | yes | Role title, for example “Support Specialist” (at most 200 characters); also the evaluation subject when subject is empty. |
speakingRate | Float | no | Text-to-speech speaking rate, 0.25 to 4.0 where 1.0 is normal (default 1.0). |
sttAlternativeLanguageCodes | [String!] | no | Speech-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. |
sttLanguageCode | String | no | Speech-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. |
subject | String | no | What sessions are about (the job, product or course), used by the evaluation prompt; position is used when empty (at most 200 characters). |
timezone | String | no | IANA 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. |
ttsLang | String | no | Language the agent speaks, a BCP-47 code such as “en-US” (at most 20 characters; default “en-US”). |
ttsVoice | String | no | Text-to-speech voice name, for example “en-US-Neural2-F” (at most 100 characters; default “en-US-Standard-C”). See agentConfigOptions for recommended voices. |
useCase | AgentUseCase! | yes | Kind of conversation; selects how finished sessions are evaluated (default INTERVIEW). CUSTOM requires evaluationPromptTemplate and evaluationRecommendationLabels. |
vadThreshold | Float | no | Voice-activity detection threshold for the microphone, 0.1 to 1.0 (default 0.8). |
voiceTier | VoiceTier! | yes | Voice quality tier label (default STANDARD). |
Allowed values
AvatarBackendType:CLIENT_3D,HOSTED_API,SELF_HOSTED_VIDEO_STREAMAvatarGenderCode:F,MLlmProviderType:BEDROCK_MANTLE,GEMINI_DIRECT(plus 1 internal value, not listed)AgentUseCase:CUSTOM,EDUCATION,INTERVIEW,ONBOARDING,SALES,SUPPORTVoiceTier:CHIRP3_HD,NEURAL2,STANDARD,STUDIO,WAVENETAgentStatus:ACTIVE,INACTIVE
Code samples
#!/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// createAgent: Create an agent. It has no workflow until you attach one with updateAgent.// Credential: Dashboard JWT (WETEL_JWT). Node 18+ (built-in fetch).const API_URL = process.env.WETEL_API_URL ?? "https://api.wetel.dev/graphql";
const query = `mutation CreateAgent($input: CreateAgentInput!) { createAgent(input: $input) { id name status workflowId }}`;
const 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", },};
type GraphQLResponse = { data?: Record<string, unknown>; errors?: { message: string; extensions?: { code?: string } }[];};
async function main(): Promise<void> { const res = await fetch(API_URL, { method: "POST", headers: { "Content-Type": "application/json", "x-huat-platform": "customer", Authorization: `Bearer ${process.env.WETEL_JWT ?? ""}`, }, body: JSON.stringify({ query, variables }), }); const body = (await res.json()) as GraphQLResponse; if (body.errors?.length) { const error = body.errors[0]; throw new Error(`${error.extensions?.code}: ${error.message}`); } console.log(JSON.stringify(body.data?.createAgent, null, 2));}
main().catch(err => { console.error(err); process.exit(1);});
export {};<?php// createAgent: Create an agent. It has no workflow until you attach one with updateAgent.// Credential: Dashboard JWT (WETEL_JWT). PHP 7.3+ with the curl extension.$apiUrl = getenv('WETEL_API_URL') ?: 'https://api.wetel.dev/graphql';
$query = <<<'GRAPHQL'mutation CreateAgent($input: CreateAgentInput!) { createAgent(input: $input) { id name status workflowId }}GRAPHQL;
$variables = json_decode(<<<'JSON'{ "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);
$ch = curl_init($apiUrl);curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'x-huat-platform: customer', 'Authorization: Bearer ' . getenv('WETEL_JWT'), ], CURLOPT_POSTFIELDS => json_encode(['query' => $query, 'variables' => $variables]),]);$body = json_decode(curl_exec($ch), true);curl_close($ch);
if (!empty($body['errors'])) { $error = $body['errors'][0]; fwrite(STDERR, ($error['extensions']['code'] ?? 'ERROR') . ': ' . $error['message'] . PHP_EOL); exit(1);}echo json_encode($body['data']['createAgent'], JSON_PRETTY_PRINT), PHP_EOL;// createAgent: Create an agent. It has no workflow until you attach one with updateAgent.// Credential: Dashboard JWT (WETEL_JWT). .NET 8: put this in Program.cs of a console app and run "dotnet run".using System.Net.Http.Headers;using System.Net.Http.Json;using System.Text.Json;using System.Text.Json.Nodes;
var apiUrl = Environment.GetEnvironmentVariable("WETEL_API_URL") ?? "https://api.wetel.dev/graphql";
const string query = """ mutation CreateAgent($input: CreateAgentInput!) { createAgent(input: $input) { id name status workflowId } } """;
var variables = JsonNode.Parse(""" { "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" } } """);
using var http = new HttpClient();using var request = new HttpRequestMessage(HttpMethod.Post, apiUrl){ Content = JsonContent.Create(new { query, variables }),};request.Headers.Add("x-huat-platform", "customer");request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("WETEL_JWT"));
using var response = await http.SendAsync(request);var body = JsonNode.Parse(await response.Content.ReadAsStringAsync())!;if (body["errors"] is JsonArray errors && errors.Count > 0){ Console.Error.WriteLine($"{errors[0]?["extensions"]?["code"]}: {errors[0]?["message"]}"); return 1;}Console.WriteLine(body["data"]?["createAgent"]?.ToJsonString(new JsonSerializerOptions { WriteIndented = true }));return 0;# createAgent: Create an agent. It has no workflow until you attach one with updateAgent.# Credential: Dashboard JWT (WETEL_JWT). Python 3.8+ with "requests".import jsonimport os
import requests
API_URL = os.environ.get("WETEL_API_URL", "https://api.wetel.dev/graphql")
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", },}
response = requests.post( API_URL, json={"query": QUERY, "variables": VARIABLES}, headers={ "x-huat-platform": "customer", "Authorization": "Bearer " + os.environ["WETEL_JWT"], }, timeout=30,)body = response.json()if body.get("errors"): error = body["errors"][0] raise SystemExit(f"{error.get('extensions', {}).get('code')}: {error['message']}")print(json.dumps(body["data"]["createAgent"], indent=2))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" } } ]}updateAgent
Section titled “updateAgent”Change an agent. Send only the fields that change; attach a workflow with workflowId.
- Kind: mutation
- Credential: Dashboard JWT:
Authorization: Bearer <jwt>, fromlogin(a person or a one-off script) - Available in: sandbox and production
idis a separate argument, not a field ofinput.- The workflow you attach must belong to your workspace. Sessions run its **published** version, so publish it first (see Workflows).
- Set
statustoINACTIVEto stop new tasks from running against the agent.
Request
mutation UpdateAgent($id: ID!, $input: UpdateAgentInput!) { updateAgent(id: $id, input: $input) { id workflowId status updatedAt }}{ "id": "7", "input": { "workflowId": 12 }}Input fields
UpdateAgentInput
| Field | Type | Required | Description |
|---|---|---|---|
avatarBackend | AvatarBackendType | no | How clients render the avatar. Omit to leave unchanged; null is refused. |
avatarBackendConfig | JSON | no | Settings 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. |
avatarGender | AvatarGenderCode | no | Gender of the avatar model (default F). Omit to leave unchanged; null is refused. |
avatarGlb | String | no | File 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. |
evaluationPromptTemplate | String | no | Your 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!] | no | Recommendation 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. |
externalSyncOwnerId | Int | no | Owner id your endpoint expects when the mirrored conversation is created (a positive integer of your system). Omit to leave unchanged; null is refused. |
externalSyncSchemaConfig | JSON | no | Optional 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. |
externalSyncSecretRef | String | no | Reference 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. |
externalSyncUrl | String | no | URL 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. |
lipsyncLang | String | no | Short language code for 3D avatar lip-sync, such as “en” (at most 10 characters; default “en”). Omit to leave unchanged; null is refused. |
llmModelOverride | String | no | Specific 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. |
llmProviderOverride | LlmProviderType | no | Model provider for this agent; send null to clear the override (back to the workspace setting or platform default). |
name | String | no | Display name (at most 100 characters). Omit to leave unchanged; null is refused. |
openingGreeting | String | no | Fixed 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. |
personaPrompt | String | no | System prompt: identity, tone and boundaries of the agent (at most 10000 characters). Omit to leave unchanged; null is refused. |
position | String | no | Role title, for example “Support Specialist” (at most 200 characters); also the evaluation subject when subject is empty. Omit to leave unchanged; null is refused. |
speakingRate | Float | no | Text-to-speech speaking rate, 0.25 to 4.0 where 1.0 is normal (default 1.0). Omit to leave unchanged; null is refused. |
status | AgentStatus | no | ACTIVE 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!] | no | Speech-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. |
sttLanguageCode | String | no | Speech-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. |
subject | String | no | What 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. |
timezone | String | no | IANA 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. |
ttsLang | String | no | Language 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. |
ttsVoice | String | no | Text-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. |
useCase | AgentUseCase | no | Kind of conversation. Switching to CUSTOM requires evaluationPromptTemplate and evaluationRecommendationLabels in the same call. Omit to leave unchanged; null is refused. |
vadThreshold | Float | no | Voice-activity detection threshold for the microphone, 0.1 to 1.0 (default 0.8). Omit to leave unchanged; null is refused. |
voiceTier | VoiceTier | no | Voice quality tier label. Omit to leave unchanged; null is refused. |
workflowId | Int | no | Attach 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_STREAMAvatarGenderCode:F,MLlmProviderType:BEDROCK_MANTLE,GEMINI_DIRECT(plus 1 internal value, not listed)AgentStatus:ACTIVE,INACTIVEAgentUseCase:CUSTOM,EDUCATION,INTERVIEW,ONBOARDING,SALES,SUPPORTVoiceTier:CHIRP3_HD,NEURAL2,STANDARD,STUDIO,WAVENET
Code samples
#!/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// updateAgent: Change an agent. Send only the fields that change; attach a workflow with workflowId.// Credential: Dashboard JWT (WETEL_JWT). Node 18+ (built-in fetch).const API_URL = process.env.WETEL_API_URL ?? "https://api.wetel.dev/graphql";
const query = `mutation UpdateAgent($id: ID!, $input: UpdateAgentInput!) { updateAgent(id: $id, input: $input) { id workflowId status updatedAt }}`;
const variables = { id: "7", input: { workflowId: 12, },};
type GraphQLResponse = { data?: Record<string, unknown>; errors?: { message: string; extensions?: { code?: string } }[];};
async function main(): Promise<void> { const res = await fetch(API_URL, { method: "POST", headers: { "Content-Type": "application/json", "x-huat-platform": "customer", Authorization: `Bearer ${process.env.WETEL_JWT ?? ""}`, }, body: JSON.stringify({ query, variables }), }); const body = (await res.json()) as GraphQLResponse; if (body.errors?.length) { const error = body.errors[0]; throw new Error(`${error.extensions?.code}: ${error.message}`); } console.log(JSON.stringify(body.data?.updateAgent, null, 2));}
main().catch(err => { console.error(err); process.exit(1);});
export {};<?php// updateAgent: Change an agent. Send only the fields that change; attach a workflow with workflowId.// Credential: Dashboard JWT (WETEL_JWT). PHP 7.3+ with the curl extension.$apiUrl = getenv('WETEL_API_URL') ?: 'https://api.wetel.dev/graphql';
$query = <<<'GRAPHQL'mutation UpdateAgent($id: ID!, $input: UpdateAgentInput!) { updateAgent(id: $id, input: $input) { id workflowId status updatedAt }}GRAPHQL;
$variables = json_decode(<<<'JSON'{ "id": "7", "input": { "workflowId": 12 }}JSON);
$ch = curl_init($apiUrl);curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'x-huat-platform: customer', 'Authorization: Bearer ' . getenv('WETEL_JWT'), ], CURLOPT_POSTFIELDS => json_encode(['query' => $query, 'variables' => $variables]),]);$body = json_decode(curl_exec($ch), true);curl_close($ch);
if (!empty($body['errors'])) { $error = $body['errors'][0]; fwrite(STDERR, ($error['extensions']['code'] ?? 'ERROR') . ': ' . $error['message'] . PHP_EOL); exit(1);}echo json_encode($body['data']['updateAgent'], JSON_PRETTY_PRINT), PHP_EOL;// updateAgent: Change an agent. Send only the fields that change; attach a workflow with workflowId.// Credential: Dashboard JWT (WETEL_JWT). .NET 8: put this in Program.cs of a console app and run "dotnet run".using System.Net.Http.Headers;using System.Net.Http.Json;using System.Text.Json;using System.Text.Json.Nodes;
var apiUrl = Environment.GetEnvironmentVariable("WETEL_API_URL") ?? "https://api.wetel.dev/graphql";
const string query = """ mutation UpdateAgent($id: ID!, $input: UpdateAgentInput!) { updateAgent(id: $id, input: $input) { id workflowId status updatedAt } } """;
var variables = JsonNode.Parse(""" { "id": "7", "input": { "workflowId": 12 } } """);
using var http = new HttpClient();using var request = new HttpRequestMessage(HttpMethod.Post, apiUrl){ Content = JsonContent.Create(new { query, variables }),};request.Headers.Add("x-huat-platform", "customer");request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("WETEL_JWT"));
using var response = await http.SendAsync(request);var body = JsonNode.Parse(await response.Content.ReadAsStringAsync())!;if (body["errors"] is JsonArray errors && errors.Count > 0){ Console.Error.WriteLine($"{errors[0]?["extensions"]?["code"]}: {errors[0]?["message"]}"); return 1;}Console.WriteLine(body["data"]?["updateAgent"]?.ToJsonString(new JsonSerializerOptions { WriteIndented = true }));return 0;# updateAgent: Change an agent. Send only the fields that change; attach a workflow with workflowId.# Credential: Dashboard JWT (WETEL_JWT). Python 3.8+ with "requests".import jsonimport os
import requests
API_URL = os.environ.get("WETEL_API_URL", "https://api.wetel.dev/graphql")
QUERY = """mutation UpdateAgent($id: ID!, $input: UpdateAgentInput!) { updateAgent(id: $id, input: $input) { id workflowId status updatedAt }}"""
VARIABLES = { "id": "7", "input": { "workflowId": 12, },}
response = requests.post( API_URL, json={"query": QUERY, "variables": VARIABLES}, headers={ "x-huat-platform": "customer", "Authorization": "Bearer " + os.environ["WETEL_JWT"], }, timeout=30,)body = response.json()if body.get("errors"): error = body["errors"][0] raise SystemExit(f"{error.get('extensions', {}).get('code')}: {error['message']}")print(json.dumps(body["data"]["updateAgent"], indent=2))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}