WebSocket Dashboard →
⚡ Real-time TTS & STT · run it right here

Quickdial API

Text-to-speech and speech-to-text over REST and WebSocket. Try every endpoint live below — synthesize a voice and download the audio, or upload a clip and get a transcript.

Overview

The Quickdial API has two directions, each on REST and WebSocket. REST is a single request/response; WebSocket streams audio and text continuously for the lowest latency. All examples below are runnable against this server.

🔊  TTS  POST /v1/tts 📝  STT  POST /v1/stt 🎙  Voices  GET /v1/voices  Streaming  wss://…/v1/*/stream

Authentication

Authenticate with a Bearer API key (create one in the dashboard). Paste it once here — the runnable examples on this page will use it. Leave it blank to use the free, rate-limited public demo instead.

🔑 Your API key used by every “Run” below
Stored only in this browser tab, never sent anywhere except your requests to this API.
auth
# Every REST call takes an Authorization header
curl https://api.quickdial.ai/v1/voices \
  -H "Authorization: Bearer qdl_live_your_key"

TTS Text-to-Speech

Send text and a voice, get audio back. Choose opus for the cheapest streaming, or wav for uncompressed PCM.

POST /v1/tts
▶ Run Text-to-Speech plays + downloads audio
Free demo caps text length; a key unlocks full requests.
tts.sh
curl https://api.quickdial.ai/v1/tts \
  -H "Authorization: Bearer qdl_live_your_key" \
  -H "Content-Type: application/json" \
  -d '{ "text": "Hello world", "voice": "alba", "format": "wav" }' \
  --output hello.wav

Voices

List every available voice with its language and gender. This endpoint is public — no key required.

GET /v1/voices
▶ List voices
Also populates the voice picker above.
voices.sh
curl https://api.quickdial.ai/v1/voices \
  -H "Authorization: Bearer qdl_live_your_key"

STT Speech-to-Text

Upload an audio file and get an accurate transcript with word-level timestamps, powered by whisper.cpp.

POST /v1/stt
▶ Run Speech-to-Text
stt.sh
curl https://api.quickdial.ai/v1/stt \
  -H "Authorization: Bearer qdl_live_your_key" \
  -F audio=@speech.wav

WebSocket streaming

For the lowest latency, keep a socket open so audio and text flow continuously — no request/response round-trip per chunk. Same voices and models as REST, relayed byte-for-byte. Streaming isn't runnable from this page, but the protocol and full code are below.

DirectionText → SpeechSpeech → Text
You sendOne JSON message (text + voice)A stream of audio frames, then eos
You receiveBinary PCM audio framesA JSON transcript
Audio format16-bit PCM · mono · 24 kHz16-bit PCM · mono · 16 kHz

Authentication

Browsers can't set headers on a WebSocket handshake, so pass your key as a query parameter. Non-browser clients may send an Authorization header instead.

connect.js
// Browser — key in the query string
const ws = new WebSocket("wss://api.quickdial.ai/v1/tts/stream?key=qdl_live_your_key");

// Node / server — Authorization header on the handshake
const ws = new WebSocket("wss://api.quickdial.ai/v1/tts/stream", {
  headers: { Authorization: "Bearer qdl_live_your_key" },
});

TTS Text → Speech streaming

Open the socket, send one JSON message, and receive PCM audio frames as they're synthesized — start playing before the sentence finishes.

ClientServer
text →
{"text":"Hello world","voice":"alba"}
← text
{"type":"start","sample_rate":24000}
← binary ×N
16-bit PCM mono @ 24 kHz frames
← text
{"type":"end"}
tts-stream.js
const KEY = "qdl_live_your_key";
const ctx = new AudioContext({ sampleRate: 24000 });
let playhead = ctx.currentTime;

const ws = new WebSocket(`wss://api.quickdial.ai/v1/tts/stream?key=${KEY}`);
ws.binaryType = "arraybuffer";

ws.onopen = () =>
  ws.send(JSON.stringify({ text: "Hello from Quickdial, streamed in real time.", voice: "jane" }));

ws.onmessage = (e) => {
  if (typeof e.data === "string") {           // control frames are text
    const msg = JSON.parse(e.data);
    if (msg.type === "error") console.error(msg.message);
    return;
  }
  const pcm = new Int16Array(e.data);         // 16-bit PCM mono @ 24 kHz → Web Audio
  const buf = ctx.createBuffer(1, pcm.length, 24000);
  const ch = buf.getChannelData(0);
  for (let i = 0; i < pcm.length; i++) ch[i] = pcm[i] / 32768;
  const src = ctx.createBufferSource();
  src.buffer = buf; src.connect(ctx.destination);
  playhead = Math.max(playhead, ctx.currentTime);
  src.start(playhead);
  playhead += buf.duration;
};

STT Speech → Text streaming

Open the socket, (optionally) set params, stream 16 kHz PCM frames as you capture them, then send eos to receive the transcript.

ClientServer
← text
{"type":"start","sample_rate":16000}
binary → ×N
16-bit PCM mono @ 16 kHz frames
text →
{"type":"eos"}
← text
{"type":"transcript","text":"…","segments":[…]}
stt-stream.js
const KEY = "qdl_live_your_key";
const ws = new WebSocket(`wss://api.quickdial.ai/v1/stt/stream?key=${KEY}`);

ws.onopen = async () => {
  ws.send(JSON.stringify({ params: { language: "en" } }));      // optional config
  const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
  const ac = new AudioContext({ sampleRate: 16000 });
  const src = ac.createMediaStreamSource(stream);
  const node = ac.createScriptProcessor(4096, 1, 1);
  src.connect(node); node.connect(ac.destination);
  node.onaudioprocess = (e) => {
    const f32 = e.inputBuffer.getChannelData(0);
    const pcm = new Int16Array(f32.length);                     // float32 → 16-bit PCM
    for (let i = 0; i < f32.length; i++) pcm[i] = Math.max(-1, Math.min(1, f32[i])) * 32767;
    if (ws.readyState === 1) ws.send(pcm.buffer);
  };
  setTimeout(() => { node.disconnect(); ws.send(JSON.stringify({ type: "eos" })); }, 5000);
};

ws.onmessage = (e) => {
  const msg = JSON.parse(e.data);
  if (msg.type === "transcript") console.log(msg.text, msg.segments);
};

Message reference

Server → client

TypeSent byPayload
startTTS & STT{ type, requestId, voice?, sample_rate } — session opened
binaryTTSRaw 16-bit little-endian PCM, mono, 24 kHz — one or more frames
readySTTAcknowledges a {params} config message
transcriptSTT{ type, text, language, duration_seconds, segments:[{start,end,text}] }
endTTS{ type, requestId } — synthesis complete
errorboth{ type, message }

Client → server

MessageEndpointMeaning
{ text, voice, params? }TTSSynthesize this text (one per socket message)
{ params }STTOptional config before audio (language, translate, …)
binarySTT16-bit PCM mono @ 16 kHz audio frame
{ type: "eos" }STTEnd of utterance → returns a transcript

Integrations LiveKit Pipecat

Official plugins let you drop Quickdial STT & TTS into the popular voice-agent frameworks. Set QUICKDIAL_API_KEY in your environment, then swap in the components below.

LiveKit Agents Python v0.1.4 Node v0.1.4

agent.py
# pip install livekit-plugins-quickdial   (v0.1.4)
from livekit.agents import AgentSession
from livekit.plugins import quickdial, silero

session = AgentSession(
    stt=quickdial.STT(language="en"),   # POST /v1/stt (whisper.cpp)
    tts=quickdial.TTS(voice="alba"),    # POST /v1/tts, 24 kHz
    vad=silero.VAD.load(),
)
# export QUICKDIAL_API_KEY=qtts_live_...
agent.ts
// npm i @quickdial-ai/livekit-plugins-quickdial   (v0.1.4)
import * as quickdial from '@quickdial-ai/livekit-plugins-quickdial';

const session = new voice.AgentSession({
  stt: new quickdial.STT({ language: 'en' }),
  tts: new quickdial.TTS({ voice: 'alba' }),
});
// QUICKDIAL_API_KEY=qtts_live_...

Pipecat Python v0.1.0

pipeline.py
# pip install pipecat-quickdial   (v0.1.0)
from pipecat_quickdial import QuickdialSTTService, QuickdialTTSService

stt = QuickdialSTTService(language="en")   # QUICKDIAL_API_KEY from env
tts = QuickdialTTSService(voice="alba")
# add stt / tts to your Pipecat Pipeline([...])
i
Same Bearer key powers every plugin. All three wrap the same REST endpoints (/v1/tts, /v1/stt) — see the sections above for parameters and voices.

Errors & tips

  • 401 / handshake close 4401 — missing or invalid API key. Check the header or ?key= param.
  • 402 — free credits exhausted; add a payment method under Billing.
  • 429 — rate limit or demo cap hit; slow down or use a key.
  • Sample rates are fixed24 kHz for TTS, 16 kHz for STT, mono, 16-bit signed little-endian.
  • Reconnect with backoff — on unexpected close, retry with exponential backoff; sockets are stateless between utterances.
Building something? Create a key in the dashboard and start with 1000 free credits.