Skip to main content
Twilio and Vobiz drive calls the same way: the platform makes an HTTP request to your app, you return XML, and each request is signed so you can prove it came from the platform. Migrating is a matter of renaming a few request parameters, branching on Vobiz’s Event field instead of Twilio’s separate callback URLs, and swapping Twilio’s X-Twilio-Signature (HMAC-SHA1) validator for Vobiz’s X-Vobiz-Signature-V3 (HMAC-SHA256 + nonce). This page maps every piece and shows before/after validation code.
AUTH_TOKEN is your Vobiz Auth Token (the api_key you pass to the SDK is your Auth ID → X-Auth-ID; the Auth Token → X-Auth-Token). The same Auth Token is the HMAC key that signs your inbound webhooks.

Request parameter mapping

Twilio POSTs application/x-www-form-urlencoded params to your voice URL; Vobiz posts the same content type to your answer_url. The values you already read carry over under Vobiz names.
Twilio paramVobiz paramNotes
CallSidCallUUIDUnique ID for the call leg.
FromFromCaller’s number in E.164 (or caller ID you set for outbound).
ToToCalled party / your inbound number.
Direction (inbound, outbound-api, outbound-dial)Direction (inbound, outbound)Inbound calls arrive ringing; API-initiated calls arrive answered.
CallStatus (ringing, in-progress, completed, busy, failed, no-answer, canceled)CallStatus (ringing, in-progress, completed, busy, failed, timeout, no-answer)Same lifecycle vocabulary.
ForwardedFromForwardedFromPresent when the carrier passes it on forwarded calls.
ParentCallSidALegUUIDThe originating leg’s ID on outbound child legs.
CallDuration (status callback)DurationWall-clock seconds; present after hangup.
— (Twilio bills separately)BillDurationBilled seconds, delivered on the same hangup payload.
HangupCause (via DialCallStatus / SIP code)HangupCauseStandard telephony hangup cause on end-of-call.
CallStatus=in-progress after answerEvent=StartAppVobiz signals “answered / app started” as an event.
StatusCallback (ringing)Event=RingRinging notification.
StatusCallback (completed)Event=HangupEnd-of-call notification.

<Gather> action-URL parameters

Twilio’s <Gather> posts Digits and SpeechResult (plus Confidence) to its action URL. Vobiz’s <Gather> posts the same input under Vobiz names.
Twilio Gather paramVobiz Gather paramNotes
DigitsDigitsDTMF entered, excluding finishOnKey.
SpeechResultSpeechTranscribed speech result.
ConfidenceSpeechConfidenceScore0.0–1.0 recognition confidence.
input="dtmf speech"inputType="dtmf speech"First input detected wins.
InputTypeVobiz also tells you which input type (dtmf/speech) fired.
Twilio’s <Gather timeout=…> becomes Vobiz’s executionTimeout; speechTimeout becomes speechEndTimeout; numDigits, finishOnKey, and hints keep their names. Full attribute list: Gather reference.

Callback flow: separate URLs → one Event field

Twilio uses a primary voice URL plus a separate StatusCallback for lifecycle events. Vobiz delivers lifecycle transitions to your flow as an Event value, so you branch on one field.
TwilioVobizMeaning
Voice URL returns TwiMLanswer_url + answer_method returns XMLDrives the call.
StatusCallback = ringingEvent=RingCall is ringing.
StatusCallback = in-progressEvent=StartAppCall answered, app started.
StatusCallback = completedhangup_url / Event=HangupCall ended.
action on a verb (Gather/Record/Dial)action on the verb (Gather/Record/Dial)Returns XML to continue the flow.

Signature validation: X-Twilio-Signature → X-Vobiz-Signature-V3

Twilio signs with HMAC-SHA1 keyed by your Auth Token over the full URL (scheme, host, port, query) with every POST field appended in alphabetical order, base64-encoded, sent as X-Twilio-Signature. The RequestValidator helper reproduces the string and compares. Vobiz signs with HMAC-SHA256 keyed by your Auth Token over baseURL + "." + nonce (query stripped), base64-encoded, sent as X-Vobiz-Signature-V3 with the random nonce in X-Vobiz-Signature-V3-Nonce.
TwilioVobizScheme
X-Twilio-SignatureX-Vobiz-Signature-V3Twilio: HMAC-SHA1(URL + sorted params). Vobiz: HMAC-SHA256(baseURL + . + nonce). Both base64.
X-Vobiz-Signature-V3-NonceRandom per-request nonce mixed into the V3 hash.
X-Vobiz-Signature-V2 (+ -Nonce)HMAC-SHA256 of baseURL + nonce (no separator).
X-Vobiz-Signature-MA-V3Same scheme, signed with the parent (main-account) token on sub-account callbacks.

Before / after — Flask (Python)

from flask import Flask, request, abort
from twilio.request_validator import RequestValidator

app = Flask(__name__)
AUTH_TOKEN = "your_twilio_auth_token"

@app.route("/voice", methods=["POST"])
def voice():
    validator = RequestValidator(AUTH_TOKEN)
    # HMAC-SHA1 over full URL + sorted POST params
    valid = validator.validate(
        request.url,
        request.form,
        request.headers.get("X-Twilio-Signature", ""),
    )
    if not valid:
        abort(403)

    call_sid = request.form["CallSid"]
    direction = request.form["Direction"]
    digits = request.form.get("Digits")
    speech = request.form.get("SpeechResult")
    # ... return TwiML

Before / after — Node

import express from 'express';
import twilio from 'twilio';

const app = express();
app.use(express.urlencoded({ extended: false }));
const AUTH_TOKEN = 'your_twilio_auth_token';

app.post('/voice', (req, res) => {
  const signature = req.header('X-Twilio-Signature');
  const url = `${req.protocol}://${req.get('host')}${req.originalUrl}`;
  // HMAC-SHA1 over full URL + sorted POST params
  const valid = twilio.validateRequest(AUTH_TOKEN, signature, url, req.body);
  if (!valid) return res.sendStatus(403);

  const callSid = req.body.CallSid;
  const digits = req.body.Digits;
  const speech = req.body.SpeechResult;
  // ... return TwiML
});

Handling the lifecycle event in one handler

@app.route("/voice", methods=["POST"])
def voice():
    if not validate_v3(request.url, request.headers, AUTH_TOKEN):
        abort(403)

    event = request.form.get("Event")
    if event == "Ring":
        return "", 200                          # notify-only
    if event == "Hangup":
        log_cdr(request.form["CallUUID"],
                request.form.get("HangupCause"),
                request.form.get("BillDuration"))
        return "", 200
    # StartApp (or first answer request): return XML to drive the call
    return app_xml(), 200, {"Content-Type": "application/xml"}

Key differences

  • One signature helper, HMAC-SHA256. Where Twilio’s RequestValidator rebuilds the full URL plus every sorted POST field, Vobiz signs baseURL + "." + nonce with SHA-256 — a short, deterministic string that’s easy to reproduce in any language with the standard library (no param-sorting step). Validate values you read from the body in your handler, as you would on any platform.
  • A nonce per request. Vobiz adds X-Vobiz-Signature-V3-Nonce, giving each signed request a fresh random component. Read it case-insensitively and feed it straight into the HMAC.
  • Events in the same handler. Instead of wiring a separate StatusCallback URL, branch on the Event field (Ring, StartApp, Hangup) inside your existing endpoint — fewer URLs to register and secure.
  • Same parameter vocabulary. CallStatus and Direction use the same words you already parse; mostly you rename CallSid → CallUUID and SpeechResult → Speech.
  • Constant-time compares. Use hmac.compare_digest (Python) or crypto.timingSafeEqual (Node) — never == — exactly as Twilio’s helper does internally.
  • Sub-account safety built in. On sub-account callbacks Vobiz adds X-Vobiz-Signature-MA-V3, signed with the parent-account token, so a parent can independently verify child traffic with the same validator.

Twilio migration overview

The at-a-glance matrix and recommended migration order.

Voice Call API mapping

REST calls: create, fetch, and control live calls on Vobiz.
Full request-parameter reference: XML request params.