跳转到内容

Sending Voice Messages to an Agent

此内容尚不支持你的语言。

If your integration already receives voice notes — a WhatsApp/Telegram bridge, a call-center recording, a voice-memo upload in your own app — you can transcribe one and feed it into a Wetel agent using the same avatarToken the <vai-avatar> embed widget uses internally. Nothing restricts that token to the widget; this page documents calling it directly from your own backend.

This is a practical, working walkthrough. For the concepts behind each call, see Core API Flow and Authentication.

You need a working sdkStart call already. If you don’t have one yet, set that up first — see Sessions API: sdkStart. Everything below assumes you can already call sdkStart server-side with your API key and get back a sessionId and avatarToken.

Step 1: start a session, keep the avatarToken

Section titled “Step 1: start a session, keep the avatarToken”
const startRes = await fetch(WETEL_GRAPHQL_URL, {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-huat-platform": "customer",
"x-api-key": WETEL_API_KEY, // server-side only, never send this to a client
},
body: JSON.stringify({
query: `mutation Start($input: SdkStartInput!) {
sdkStart(input: $input) { sessionId avatarToken }
}`,
variables: { input: { agentId: YOUR_AGENT_ID } },
}),
});
const { data } = await startRes.json();
const { sessionId, avatarToken } = data.sdkStart;

avatarToken is the credential every call below authenticates with — it’s session-scoped (bound to this sessionId, since 2026-09-08), so keep the pair together.

/stt lives on the avatar-service host, not the main GraphQL API — a separate REST service with its own hostname. Base64-encode your audio and POST it with the avatarToken as a bearer token.

Terminal window
curl -X POST https://avatar.wetel.dev/stt \
-H "Authorization: Bearer <AVATAR_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"audioBase64": "T2dnUwACAAAAAAAAAAB...",
"audioEncoding": "OGG_OPUS",
"languageCode": "en-US"
}'

Or from the same backend that just called sdkStart:

const audioBase64 = rawAudioBuffer.toString("base64"); // your voice-note bytes
const sttRes = await fetch("https://avatar.wetel.dev/stt", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${avatarToken}`,
},
body: JSON.stringify({
audioBase64,
audioEncoding: "OGG_OPUS", // native WhatsApp/Telegram voice-note format
languageCode: "en-US",
}),
});
const { transcript, confidence, languageCode } = await sttRes.json();

OGG_OPUS is exactly what WhatsApp and Telegram voice notes already are — an OGG container with Opus-encoded audio. You do not need to transcode the file before sending it; forward the raw bytes as-is.

{
"transcript": "What time does the library close today?",
"confidence": 0.94,
"languageCode": "en-US"
}
FieldTypeNotes
transcriptstringThe transcribed text
confidencenumber01
languageCodestringEchoes back the language actually recognized

There’s no audio or intermediate state to clean up — this call is stateless; the transcript is everything you need going forward.

Step 4: feed the transcript into the agent

Section titled “Step 4: feed the transcript into the agent”

Send the transcript as a normal turn via sdkSendMessage — same mutation, same credential, as if the user had typed it.

await fetch(WETEL_GRAPHQL_URL, {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-huat-platform": "customer",
Authorization: `Bearer ${avatarToken}`, // avatarToken here, not x-api-key
},
body: JSON.stringify({
query: `mutation Send($input: SdkSendMessageInput!) { sdkSendMessage(input: $input) }`,
variables: { input: { sessionId, text: transcript } },
}),
});

sdkSendMessage returns immediately — the agent’s reply arrives asynchronously over the sessionEvents subscription, exactly like any other turn. See Events & Subscriptions if you haven’t wired that up yet.

Constraints to know before you build on this

Section titled “Constraints to know before you build on this”
  • Accepted audioEncoding values: MP3, LINEAR16, WEBM_OPUS, OGG_OPUS. Don’t send anything else — it’s rejected as a validation error before it reaches the speech provider.
  • ~60 seconds per call. /stt uses synchronous transcription, which has a practical ceiling around a minute of audio. A single voice note or conversational turn is comfortably under that; if you’re transcribing something longer (a recorded call, a long memo), split it client-side into chunks and call /stt once per chunk.
  • 10 requests/minute per avatar token, enforced consistently across the fleet. STT is billed per 15-second audio block upstream, which is why this limit is tighter than /tts’s 30/min — see Avatar Service REST API: POST /stt for the full reference.
  • Max request size: roughly 4MB of raw audio (~5,600,000 base64 characters). Comfortably more than any single voice note; if you’re hitting this, you’re likely sending something other than a short recorded message.
  • Sample rate: optional — if you omit sampleRateHertz, OGG_OPUS (along with everything except WEBM_OPUS) defaults to 16kHz, which matches WhatsApp’s native voice-note rate. You don’t need to set this explicitly for a typical voice note.