Programmable voice in JSON. Calls, IVR, recording, TTS.
Voice for developers — 140+ countries with voice coverage, 1,500+ phone-number prefixes, masked calls, virtual numbers. Same API surface as Email and SMS — calls are just another resource.
import { BirdClient } from "@bird/sdk";
const bird = new BirdClient({ apiKey: process.env.BIRD_API_KEY! });
const { data, error } = await bird.voice.calls.create({
to: "+15005550010",
from: "+14155550199",
flow: [
{ say: "Your verification code is..." },
{ say: "4. 2. 9. 1. 7." },
{ gather: { digits: 1, timeout: 5 } },
{ record: { transcribe: true } },
],
}).safe();
if (error) throw error;
console.log(data.id);
// → "call_7tQ04Lp2n..."5 minutes from install to first call
Place a call from the language you already use.
SDKs in every major runtime. The first call goes to a sanctioned test number (+15005550010) so you can ship a CI check before you provision a real number.
import { BirdClient } from "@bird/sdk";
const bird = new BirdClient({ apiKey: process.env.BIRD_API_KEY! });
const { data, error } = await bird.voice.calls.create({
to: "+15005550010",
from: "+14155550199",
flow: [{ say: "Hello from Node." }],
}).safe();Ten parts of voice you'd rather not write yourself.
Carrier routing, call control, and observability primitives — named and audit-able.
- 01
Outbound and inbound calls
Place and receive calls over REST or SIP — same auth model, same idempotency contract.
- 02
Declarative call flows in JSON
Compose say, play, gather, record, transfer, and dial as a flat JSON array.
- 03
Recording with transcription
Optional recording on any leg; transcripts auto-generated in 40+ languages.
- 04
Streaming TTS, sub-250ms
First-byte audio over HTTP chunked transfer or WebSocket — billed by character.
- 05
Voice OTP via verifications
Same bird.verifications resource as SMS OTP; switch the channel field.
- 06
Virtual numbers in 100+ countries
Provision long codes from the dashboard or the numbers API in seconds.
- 07
Masked calls
Caller and callee numbers are never exposed to each other — privacy by routing.
- 08
SmartRouting per call
Least-cost carrier selected in real time for every leg, with route reselection on failure.
- 09
Per-call webhook events
call.ringing, call.answered, call.completed and friends — HMAC-signed, replay-protected.
- 10
WebRTC client SDK
Browser-to-PSTN bridges from a single npm package; works in any modern runtime.
Why we build Voice
Voice is the channel everyone treats like an afterthought. We didn't.
Voice is hard — sub-second latency, real carrier routing, recording compliance — and that's why most vendors give it its own auth, its own SDK, its own webhook contract. We took the time to make it shaped like every other Bird endpoint: same auth, same idempotency, same error envelope. Call control is just JSON.
import { BirdClient } from "@bird/sdk";
const bird = new BirdClient({ apiKey: process.env.BIRD_API_KEY! });
const { data, error } = await bird.voice.calls.create({
to: "+15005550010",
from: "+14155550199",
flow: [
{ say: "Your verification code is..." },
{ say: "4. 2. 9. 1. 7." },
{ gather: { digits: 1, timeout: 5 } },
{ record: { transcribe: true } },
],
}).safe();
if (error) throw error;
console.log(data.id);
// → "call_7tQ04Lp2n..."Every state change is a webhook.
HMAC-signed payloads, replay-protected, idempotent. The same envelope on every Bird channel — learn one, you've learned them all.
{
"type": "call.completed",
"id": "evt_8qC42v...",
"created_at": "2026-05-19T15:42:01.221Z",
"data": {
"call_id": "call_7tQ04Lp2n",
"from": "+14155550199",
"to": "+15005550010",
"direction": "outbound",
"status": "completed",
"duration_s": 42,
"answered_at": "2026-05-19T15:41:18.402Z",
"ended_at": "2026-05-19T15:42:00.117Z",
"price": { "amount": 0.014, "currency": "USD" }
}
}Retry schedule: 5s, 30s, 5m, 30m, 2h, 6h, 12h. Dead-letter after the final attempt; every dead-lettered event is replayable from the dashboard or API.
call.queuedAccepted by the API and queued for dial-out.call.ringingThe receiving line is ringing — pre-answer state.call.answeredThe callee picked up; billing starts on this event.call.completedThe call ended normally — duration and price in the payload.call.failedPermanent failure (busy, no-answer, carrier reject) with a typed reason.call.recording.readyRecording is encoded and available at the signed URL in the payload.call.transcript.readyTranscription completed; payload includes language and segments.
Voice OTP is the same resource as SMS OTP.
Place a custom call or hand the verification off to the runtime. Same auth, same idempotency, same error envelope — the channel field is the only thing that moves.
Custom call.
await bird.voice.calls.create({
to: "+15005550010",
flow: [
{ say: `Your code is ${code}.` },
],
});Compose any flow — say, gather, transfer — for the cases where you want the script in your code.
Verifications.
await bird.verifications.start({
to: "+15005550010",
channel: "voice",
});One line. Bird picks the route, runs the fraud check, dispatches the audio prompt. Same code on every channel.