Skip to main content
Refactoring a Plivo app to Vobiz is mostly a tab-swap: same call flow, a few renamed methods, and an explicit auth_id. Each task below shows the Plivo code and the equivalent Vobiz code in Python and Node — copy the Vobiz tab.
Set your credentials once: AUTH_ID is your Vobiz Auth ID (MA_…), AUTH_TOKEN is your Auth Token. In the Vobiz SDK, api_key is the Auth ID, and every account-scoped method takes that auth_id explicitly.

Set up the client

import plivo

client = plivo.RestClient(AUTH_ID, AUTH_TOKEN)
from vobiz import Vobiz

client = Vobiz(api_key=AUTH_ID, auth_token=AUTH_TOKEN)
const plivo = require('plivo');

const client = new plivo.Client(AUTH_ID, AUTH_TOKEN);
import { VobizClient } from '@vobiz/sdk';

const client = new VobizClient({ apiKey: AUTH_ID, authToken: AUTH_TOKEN });

Make an outbound call

The classic “change a few lines” migration: calls.createcalls.make_call, add auth_id, and to_to.
client.calls.create(
    from_='+14155551234',
    to_='+14165553434',
    answer_url='https://example.com/answer.xml',
    answer_method='POST',
)
client.calls.make_call(
    auth_id=AUTH_ID,
    from_='+14155551234',
    to='+14165553434',
    answer_url='https://example.com/answer.xml',
    answer_method='POST',
)
await client.calls.create(
  '+14155551234',
  '+14165553434',
  'https://example.com/answer.xml',
  { answerMethod: 'POST' },
);
await client.calls.makeCall({
  auth_id: AUTH_ID,
  from: '+14155551234',
  to: '+14165553434',
  answer_url: 'https://example.com/answer.xml',
  answer_method: 'POST',
});

Answer a call with XML (TTS + menu)

The XML builder mirrors plivoxmlResponseElement with add_* methods. GetDigits/GetInput become Gather (and add_get_digits is kept as an alias).
from plivo import plivoxml

resp = plivoxml.ResponseElement()
menu = resp.add_get_digits(action='https://example.com/menu', method='POST', num_digits=1)
menu.add_speak('Press 1 for sales, 2 for support.')
print(resp.to_string())
from vobiz import vobizxml

resp = vobizxml.ResponseElement()
menu = resp.add_gather(action='https://example.com/menu', method='POST',
                       input_type='dtmf', num_digits=1)
menu.add_speak('Press 1 for sales, 2 for support.')
print(resp.to_string())
const plivo = require('plivo');

const resp = new plivo.Response();
const menu = resp.addGetDigits({ action: 'https://example.com/menu', method: 'POST', numDigits: 1 });
menu.addSpeak('Press 1 for sales, 2 for support.');
console.log(resp.toXML());
import { vobizxml } from '@vobiz/sdk';

const resp = new vobizxml.ResponseElement();
const menu = resp.addGather({ action: 'https://example.com/menu', method: 'POST', inputType: 'dtmf', numDigits: 1 });
menu.addSpeak('Press 1 for sales, 2 for support.');
console.log(resp.toString());

Serve the answer URL (Flask / FastAPI / Express)

When Vobiz rings your number it fetches your answer_url over HTTP — return the VobizXML from any web framework, exactly as you did with Plivo. Just build the response with vobizxml and send it as application/xml.
from flask import Flask, Response
from plivo import plivoxml

app = Flask(__name__)

@app.route('/answer', methods=['POST'])
def answer():
    resp = plivoxml.ResponseElement()
    resp.add_speak('Hello from Plivo.')
    return Response(resp.to_string(), mimetype='application/xml')
from flask import Flask, Response
from vobiz import vobizxml

app = Flask(__name__)

@app.route('/answer', methods=['POST'])
def answer():
    resp = vobizxml.ResponseElement()
    resp.add_speak('Hello from Vobiz.')
    return Response(resp.to_string(), mimetype='application/xml')
from fastapi import FastAPI, Response
from vobiz import vobizxml

app = FastAPI()

@app.post('/answer')
async def answer():
    resp = vobizxml.ResponseElement()
    resp.add_speak('Hello from Vobiz.')
    return Response(content=resp.to_string(), media_type='application/xml')
import express from 'express';
import { vobizxml } from '@vobiz/sdk';

const app = express();

app.post('/answer', (req, res) => {
  const resp = new vobizxml.ResponseElement();
  resp.addSpeak('Hello from Vobiz.');
  res.type('application/xml').send(resp.toString());
});

Control a live call

Plivo’s in-call actions live on calls.*; in Vobiz they’re dedicated resources keyed by (auth_id, call_uuid).
client.calls.play(CALL_UUID, urls='https://example.com/hold.mp3')   # play audio
client.calls.speak(CALL_UUID, text='Please hold.')                  # speak text
client.calls.send_digits(CALL_UUID, digits='1234')                  # send DTMF
client.calls.record(CALL_UUID)                                      # start recording
client.calls.hangup(CALL_UUID)                                      # hang up
client.play_audio.call(AUTH_ID, CALL_UUID, urls='https://example.com/hold.mp3')   # play audio
client.speak_text.call(AUTH_ID, CALL_UUID, text='Please hold.')                   # speak text
client.dtmf.send_dtmf(AUTH_ID, CALL_UUID, digits='1234')                          # send DTMF
client.record_calls.start_recording(AUTH_ID, CALL_UUID)                           # start recording
client.live_calls.hangup_call(AUTH_ID, CALL_UUID)                                 # hang up
await client.calls.play(CALL_UUID, { urls: 'https://example.com/hold.mp3' });
await client.calls.speak(CALL_UUID, 'Please hold.');
await client.calls.sendDigits(CALL_UUID, '1234');
await client.calls.record(CALL_UUID);
await client.calls.hangup(CALL_UUID);
await client.playAudio.call(AUTH_ID, CALL_UUID, { urls: 'https://example.com/hold.mp3' });
await client.speakText.call(AUTH_ID, CALL_UUID, { text: 'Please hold.' });
await client.dtmf.sendDtmf(AUTH_ID, CALL_UUID, { digits: '1234' });
await client.recordCalls.startRecording(AUTH_ID, CALL_UUID);
await client.liveCalls.hangupCall(AUTH_ID, CALL_UUID);

Look up a live call

Retrieving a live call needs status="live" on Vobiz.
live = client.calls.get(CALL_UUID)
calls = client.calls.list(status='live')
live = client.live_calls.get_live_call(AUTH_ID, CALL_UUID, status='live')
calls = client.live_calls.list_live_calls(AUTH_ID, status='live')

Search and buy a phone number

available = client.numbers.search(country_iso='US', type='local')
client.numbers.buy('14155551234')
available = client.phone_numbers.list_inventory_numbers(AUTH_ID, country='US')
client.phone_numbers.purchase_from_inventory(AUTH_ID, e164='+14155551234')
const available = await client.numbers.search('US', { type: 'local' });
await client.numbers.buy('14155551234');
const available = await client.phoneNumbers.listInventoryNumbers(AUTH_ID, { country: 'US' });
await client.phoneNumbers.purchaseFromInventory(AUTH_ID, { e164: '+14155551234' });

List call records

Completed-call history is a first-class cdr resource on Vobiz.
records = client.calls.list(limit=20)
records = client.cdr.list_cdrs(AUTH_ID, start_date='2026-06-01', end_date='2026-06-30')

Handle errors

Catch the Vobiz error types (all subclasses of ApiError) the same way you caught Plivo’s.
from plivo.exceptions import PlivoRestError

try:
    client.calls.make_call(...)
except PlivoRestError as e:
    print(e)
from vobiz.core.api_error import ApiError

try:
    client.calls.make_call(auth_id=AUTH_ID, from_='+1...', to='+1...',
                           answer_url='https://...', answer_method='POST')
except ApiError as e:
    print(e.status_code, e.body)
Need a method that isn’t here? The full per-resource map is in Voice Call API, Call-control XML, and the rest of the Plivo migration section.