GA Twilio

Twilio Media Streams

Raw call audio over WebSocket: bidirectional streams send you the caller's audio as base64 8 kHz mu-law and let you play audio back, so you can connect any STT/LLM/TTS or speech-to-speech model to a phone call.

Est. per minute$0.035 - 0.12

Overview

Best for: Developers wiring their own pipeline or a speech-to-speech model (OpenAI Realtime, Gemini Live) to phone numbers.

At a glance

Platform $/min$0.0044
All-in priceNo
Entry plan $/mo$0
Free tierYes
Phone numbersYes
Own LLMYes
Own keysYes
RecordingYes
Smart turnsNo
WebSocketYes
Phone / SIPYes
Self-hostNo
Open weightsNo

Raw 8 kHz mu-law audio transport; you handle barge-in and turn-taking. Voice minutes billed on top. Free tier is Twilio trial credit only. BAA not re-verified for Media Streams.

Audio in

audio/x-mulaw 8000 Hz mono, base64 in JSON 'media' events

Audio out

Same format sent back in 'media' events; 'clear' to flush on barge-in, 'mark' to track playback

Languages

Whatever your models support.

Latency

Not applicable (transport); your pipeline determines latency.

Regions

Twilio global.

Compliance

Twilio offers BAAs for HIPAA-eligible products; not re-verified for Media Streams here.

Features

  • telephony
  • raw audio access
  • barge-in via clear
  • playback marks
  • DTMF (bidirectional, inbound only)
  • works with OpenAI/Gemini realtime APIs

Pricing

WhatPriceUnitNotes
Media Streams$0.0044per minuteTransport only.
Inbound local / outbound US$0.0085 / $0.014per minutePlus $1.15/month per local number; toll-free inbound $0.022/min.
SIP interface$0.004per minuteIf you bring calls in over SIP.
How the per-minute estimate was worked out

$0.0044 stream + $0.0085-$0.014 voice + your STT/LLM/TTS ($0.02-$0.10 depending on providers; speech-to-speech realtime models can exceed this).

Free tier: Twilio trial credit only.

Source: twilio.com

Setup

  1. Point a Twilio number's voice webhook at TwiML returning <Connect><Stream url="wss://..."/>.
  2. Accept the WebSocket; read 'start' for streamSid, decode 'media' payloads (mu-law 8 kHz) into your STT or realtime model.
  3. Send TTS audio back as mu-law 8 kHz base64 in 'media' events; send 'clear' when the caller interrupts.

Endpoint

wss:// endpoint you host

Authentication

Twilio credentials for webhooks; validate X-Twilio-Signature

Quick start javascript

// Twilio bidirectional Media Stream skeleton
import express from "express";
import { WebSocketServer } from "ws";
const app = express();
app.post("/voice", (req, res) => res.type("text/xml").send(
  '<Response><Connect><Stream url="wss://ai.example.com/media" /></Connect></Response>'));
const wss = new WebSocketServer({ server: app.listen(3000), path: "/media" });
wss.on("connection", (ws) => {
  let streamSid;
  ws.on("message", (raw) => {
    const m = JSON.parse(raw);
    if (m.event === "start") streamSid = m.start.streamSid;
    if (m.event === "media") {
      const ulaw8k = Buffer.from(m.media.payload, "base64");
      sendToSTTorRealtimeModel(ulaw8k);            // your pipeline
    }
  });
  // when your TTS produces mu-law 8 kHz audio:
  onAgentAudio((ulawChunk) => ws.send(JSON.stringify(
    { event: "media", streamSid, media: { payload: ulawChunk.toString("base64") } })));
  onUserBargeIn(() => ws.send(JSON.stringify({ event: "clear", streamSid })));
});

Written from the current docs. Check the vendor's SDK version before you ship.

Warnings

8 kHz mu-law in and out

You must convert to/from mu-law 8 kHz. Sending PCM16 or 24 kHz audio unconverted produces noise. Many realtime model APIs accept g711_ulaw directly, which avoids resampling.

You own barge-in

Without sending 'clear' on interruption, Twilio keeps playing buffered audio after the caller starts talking.

<Connect><Stream> blocks the rest of the TwiML

Nothing after it runs until the socket closes; plan transfers via the REST API or by closing the stream and redirecting.

Per-call track limits

Unidirectional streams, SIPREC, real-time transcription and AMD share a 4-track cap; exceeding it silently prevents the stream (stream-stopped callback).

Plus 12 warnings that apply to all platforms and telephony APIs. See category warnings.

Limits

  • One bidirectional stream per call
  • Unidirectional: max 4 tracks per call (shared)
  • Stream resource API cannot start bidirectional streams

Models and products

NameStatusNotes
Bidirectional stream (<Connect><Stream>)GAOne per call; inbound track only; blocks following TwiML until the socket closes.
Unidirectional stream (<Start><Stream>)GAListen-only, up to 4 tracks per call shared with SIPREC, real-time transcription and AMD.

Docs and sources

Docs

Sources used

Not fully verified

Message field names in the snippet come from long-standing Twilio docs (WebSocket messages page not fetched in this session).

Similar platforms APIs

Spotted a wrong price or a dead link?