Skip to main content

Twilio Voice Compatibility Adapter

The Twilio Voice Compatibility Adapter lets an existing Twilio voice application run on Bandwidth's network by changing one URL with no application rewrite. It's a live translator: it speaks Twilio's 2010-04-01 REST shape, TwiML, and webhook payloads on the front, and the Bandwidth Voice API on the back.

info

The everyday call-flow building blocks are proven end-to-end on real Twilio and Bandwidth calls. The status labels throughout these pages tell you exactly what's verified live, what's covered by automated tests, and what's still experimental, so you always know what you can rely on.

How it works

A phone call on either platform is driven by a small script the network reads step by step — "say a greeting → wait for a key press → if they press 1, transfer to sales." Twilio writes that script in TwiML; Bandwidth uses BXML for the same ideas. Roughly 80% maps one-to-one; the adapter handles the rest.

The network doesn't get the whole script at once. Instead, it asks the app "what now?" one step at a time. The adapter sits in the middle of that conversation:

  1. A call hits a Bandwidth number → Bandwidth asks the adapter, in BXML, "what now?"
  2. The adapter asks your unmodified Twilio app the same question, signing the request the way Twilio would, so your app trusts it.
  3. Your app replies with TwiML → the adapter translates it to BXML on the spot and hands it back.
  4. Caller input (DTMF or speech) loops back through the same path for the life of the call.

The translation is deterministic and driven by a single compatibility matrix, not an AI guessing. When your app uses something the adapter can't do yet, it fails loudly with a clear error rather than mistranslating a live call silently.

What you can do

TwiML verbs

VerbSupportNotes
Say, Play, Pause, Hangup, RedirectSSML touches supported on Say
GatherDTMF + speech; speech input needs enablement on your Bandwidth account
RecordactionrecordCompleteUrl; recordingStatusCallbackrecordingAvailableUrl
DialNumber, SipcallerId, timeout, action mapped
DialConference⚠️Mute + event callbacks; no hold music or start/end lifecycle
Connect/Start/Stop (Stream, Transcription)Media Streams bridge emulates Twilio's WebSocket protocol
Reject, Refer⚠️Reject → Hangup (with warning); Refer is inbound-SIP only
Queue, Client, Enqueue, Leave, PayNo Bandwidth equivalent — the adapter fails loudly

REST API facade

Backend calls your Twilio SDK makes are served in Twilio's shape under /2010-04-01/Accounts/{accountSid} and translated to Bandwidth.

Twilio SDK callAdapter endpointStatus
calls.create()POST /Calls.json
calls(sid).update()POST /Calls/{sid}.json✅ hang up / redirect
calls(sid).fetch()GET /Calls/{sid}.json
calls(sid).recordings.list()GET /Calls/{sid}/Recordings.json
recordings(sid).fetch() / mediaGET /Recordings/{sid}.json / .mp3 / .wav
recordings(sid).update({status})POST /Calls/{sid}/Recordings/{recSid}.json✅ pause/resume (stopped unsupported)

Errors mirror Twilio: unknown resources return 20404, bad credentials 20003, missing params 21201/21205/21213.

The full machine-readable surface is published as an OpenAPI spec at openapi/twilio-compat-adapter.yml in the adapter repo. It intentionally mirrors Twilio's API paths, JSON shapes, and error codes, so it diverges from Bandwidth API Standards v3 by design — byte-level Twilio compatibility is the whole point.

What you can't do yet

  • Call queues ("you're caller number 3, please hold") — Bandwidth has no queue primitive to translate to. The most significant current limitation.
  • Conference hold music — no Bandwidth equivalent.
  • Stopping a recording over REST — Bandwidth pauses and resumes over REST but has no REST stop (StopRecording is a BXML verb), so Status=stopped fails loudly.
  • Number provisioning — the adapter does not provision numbers. Ordering, activation, and release are handled by the Bandwidth band CLI (https://dev.bandwidth.com/tools/cli/).

In every case, the adapter surfaces a clear error rather than silently mistranslating. You can trust us to let you know where the gaps are.

What you need to get started

  • A Bandwidth App account with Voice enabled
  • OAuth2 client credentials (client ID and client secret) from The Bandwidth App, plus a Bandwidth Voice application ID
  • An existing Twilio voice application you want to migrate
  • Node.js 20+ to run the adapter

Once you have credentials, head to the quickstart guide to run the adapter and point your app at it.