Convert a chat message to speech and stream the audio. Audio is generated via our TTS provider on first request and cached automatically — subsequent requests are served from cache with no added latency.
The response is a WAV stream (RIFF container, IEEE float32 PCM, mono, 44.1 kHz). Standard audio players — browser <audio>, Web Audio decodeAudioData, ffplay, afplay, expo-av — play it directly with no custom decoding.
Request
Bearer token obtained from the authenticate endpoint.
ID of the chat message to synthesize. The message must belong to your organization.
Response
Returns a streaming audio/wav body.
| Property | Value |
|---|
| Content-Type | audio/wav |
| Container | WAV (RIFF) |
| Encoding | PCM float32, little-endian |
| Sample rate | 44100 Hz |
| Channels | Mono |
| Content-Disposition | inline; filename="message-{message_id}.wav" |
During the first request for a message the audio is streamed live; the WAV header’s size fields are written as 0xFFFFFFFF (read-until-EOF). Cached responses carry real sizes, so seek and duration work from the first byte.
Playback
Browser (Web Audio API)
async function playMessageAudio(messageId, token) {
const response = await fetch(
`https://api.trellis.sh/v1/tts/messages/${messageId}/audio`,
{ headers: { Authorization: `Bearer ${token}` } }
);
const audioCtx = new AudioContext();
const audioBuffer = await audioCtx.decodeAudioData(await response.arrayBuffer());
const source = audioCtx.createBufferSource();
source.buffer = audioBuffer;
source.connect(audioCtx.destination);
source.start();
}
Browser (<audio> element)
async function playMessageAudio(messageId, token) {
const response = await fetch(
`https://api.trellis.sh/v1/tts/messages/${messageId}/audio`,
{ headers: { Authorization: `Bearer ${token}` } }
);
const blob = await response.blob();
const audio = new Audio(URL.createObjectURL(blob));
await audio.play();
}
React Native (Expo AV)
import { Audio } from "expo-av";
import * as FileSystem from "expo-file-system";
async function playMessageAudio(messageId, token) {
const localPath = FileSystem.cacheDirectory + `${messageId}.wav`;
await FileSystem.downloadAsync(
`https://api.trellis.sh/v1/tts/messages/${messageId}/audio`,
localPath,
{ headers: { Authorization: `Bearer ${token}` } }
);
const { sound } = await Audio.Sound.createAsync({ uri: localPath });
await sound.playAsync();
}
curl -X GET "https://api.trellis.sh/v1/tts/messages/8f14e45f-ceea-467f-a83c-0a06b8901a45/audio" \
-H "Authorization: Bearer YOUR_TOKEN" \
--output message_audio.wav
import requests
message_id = "8f14e45f-ceea-467f-a83c-0a06b8901a45"
response = requests.get(
f"https://api.trellis.sh/v1/tts/messages/{message_id}/audio",
headers={"Authorization": "Bearer YOUR_TOKEN"},
stream=True,
)
with open("message_audio.wav", "wb") as f:
for chunk in response.iter_content(chunk_size=4096):
f.write(chunk)
const messageId = "8f14e45f-ceea-467f-a83c-0a06b8901a45";
const response = await fetch(
`https://api.trellis.sh/v1/tts/messages/${messageId}/audio`,
{
headers: { Authorization: "Bearer YOUR_TOKEN" },
}
);
const wavBuffer = await response.arrayBuffer();
// See Playback section above — the buffer is a self-describing WAV,
// decode with AudioContext.decodeAudioData or play via `<audio>` + blob URL.
<binary WAV audio stream>
{
"detail": "Missing Authorization header"
}
{
"detail": "Message not found"
}
{
"detail": "Audio generation failed"
}