Skip to main content
Plivo XML is a set of instructions you use to tell Plivo what to do when you receive an incoming call or make an outbound call. When someone calls your Plivo phone number, Plivo looks up the URL associated with that phone number and makes a request to that URL. Your web application returns an XML document with instructions on how to handle the call.

How XML Works

Incoming Calls

  1. Someone calls your Plivo phone number
  2. Plivo sends a request to your Answer URL
  3. Your server returns Plivo XML instructions
  4. Plivo executes the instructions (speak, play, dial, etc.)
Caller → Plivo → Your Server (Answer URL) → XML Response → Plivo executes

Outbound Calls

  1. You trigger an outbound call via the API with an answer_url
  2. When the call is answered, Plivo fetches XML from your answer_url
  3. Plivo executes the instructions
Your App → Plivo API → Call Recipient → XML from answer_url → Execute

Basic Structure

Every Plivo XML document starts with a <Response> element containing one or more instruction elements:
<Response>
    <Speak>Hello! Welcome to our service.</Speak>
    <Play>https://example.com/audio/menu.mp3</Play>
</Response>
Elements are executed in order. When one element completes, the next begins.

Multiple Elements

<Response>
    <Speak>Please hold while we connect you.</Speak>
    <Play>https://example.com/hold-music.mp3</Play>
    <Dial>
        <Number>+14155551234</Number>
    </Dial>
    <Speak>Sorry, no one is available. Goodbye.</Speak>
    <Hangup/>
</Response>
Execution flow:
  1. Speak the message
  2. Play the audio file
  3. Dial the number
  4. If dial fails, speak the fallback message
  5. Hang up

Generating XML with SDKs

from plivo import plivoxml

response = plivoxml.ResponseElement()
response.add(plivoxml.SpeakElement('Hello, world!'))
response.add(plivoxml.HangupElement())

xml_string = response.to_string()

Available XML Elements

Audio Output

ElementDescription
SpeakConvert text to speech
PlayPlay an audio file
DTMFSend DTMF tones

Input Collection

ElementDescription
GetDigitsCollect DTMF digit input
GetInputCollect speech or digit input

Call Routing

ElementDescription
DialConnect to another number or SIP endpoint
RedirectTransfer call flow to another URL
HangupEnd the call
WaitPause execution

Conferencing

ElementDescription
ConferenceConnect caller to a conference room
MultiPartyCallAdvanced multi-party conferencing

Recording

ElementDescription
RecordRecord the call or a message

Advanced

ElementDescription
PreAnswerPlay media before answering
StreamStream real-time audio via WebSocket

Nesting Elements

Some elements can be nested inside others:
<Response>
    <GetDigits action="/handle-input/" numDigits="1">
        <Speak>Press 1 for sales, 2 for support.</Speak>
    </GetDigits>
    <Speak>We didn't receive any input. Goodbye.</Speak>
</Response>

Nesting Rules

Parent ElementAllowed Children
ResponseAll elements
GetDigitsSpeak, Play
GetInputSpeak, Play
DialNumber, User
PreAnswerSpeak, Play, Wait

Request Parameters

When Plivo requests your XML endpoint, it includes these parameters:

Voice Call Parameters

ParameterDescription
CallUUIDUnique identifier for this call
FromCaller’s phone number (with country code)
ToCalled phone number (with country code)
CallStatusCall status: ringing, in-progress, completed
Directioninbound or outbound

Inbound vs Outbound

Inbound calls:
  • From = Caller’s number
  • To = Your Plivo number
  • Direction = inbound
Outbound calls (via API):
  • From = Caller ID you specified
  • To = Destination number
  • Direction = outbound

Outbound Call Parameters

ParameterDescription
ALegUUIDUUID of the first call leg
ALegRequestUUIDRequest UUID returned by API

Call Forwarding

ParameterDescription
ForwardedFromOriginal number (if call was forwarded). Carrier-dependent

Completed Call Parameters

ParameterDescription
HangupCauseStandard telephony hangup cause
DurationCall duration in seconds
BillDurationBilled duration in seconds
TotalCostTotal cost of the call

Call Status Values

StatusDescription
ringingCall is ringing (inbound, not yet answered)
in-progressCall is active
completedCall ended normally
busyCalled party was busy (outbound only)
failedCall failed to connect (outbound only)
timeoutNo answer within timeout (outbound only)
no-answerCalled party didn’t answer (outbound only)

SIP Headers

For SIP calls, custom SIP headers are included with the X-PH- prefix:
Header FormatDescription
X-PH-<HeaderName>Custom SIP header value
Example: If you send sipHeaders="CustomId=123", the request includes X-PH-CustomId=123.

Response Requirements

Your server must return:
  • Valid XML document
  • Content-Type: application/xml or text/xml
  • Maximum size: 100 KB

Framework Examples

# Flask
from flask import Response
return Response(xml_string, mimetype='application/xml')
// Express
res.set('Content-Type', 'application/xml');
res.send(xmlString);
# Sinatra
content_type 'application/xml'
xml_string
// PHP
header('Content-Type: application/xml');
echo $xml_string;

Empty Response

An empty <Response> element hangs up the call:
<Response>
</Response>

Example: Using Request Parameters

from flask import Flask, request, Response
from plivo import plivoxml

app = Flask(__name__)

@app.route('/answer/', methods=['GET', 'POST'])
def answer():
    call_uuid = request.values.get('CallUUID')
    caller = request.values.get('From')
    called = request.values.get('To')
    direction = request.values.get('Direction')

    response = plivoxml.ResponseElement()

    if direction == 'inbound':
        # Log the incoming call
        print(f"Incoming call from {caller} to {called}, UUID: {call_uuid}")

        # Custom greeting based on caller ID
        if is_vip_customer(caller):
            response.add(plivoxml.SpeakElement('Welcome back, valued customer!'))
        else:
            response.add(plivoxml.SpeakElement('Thank you for calling.'))
    else:
        response.add(plivoxml.SpeakElement('Connecting your call.'))

    return Response(response.to_string(), mimetype='application/xml')

Example: Simple IVR

<Response>
    <GetDigits action="/ivr-response/" numDigits="1" timeout="10">
        <Speak>
            Welcome to Acme Corp.
            Press 1 for sales.
            Press 2 for support.
            Press 3 to hear our hours.
        </Speak>
    </GetDigits>
    <Speak>Sorry, we didn't receive any input. Goodbye.</Speak>
    <Hangup/>
</Response>

Example: Forward Call

<Response>
    <Dial callerId="+14155551234">
        <Number>+14155559876</Number>
    </Dial>
</Response>

Hangup Causes

Common hangup cause values:
CauseDescription
NORMAL_CLEARINGNormal call termination
USER_BUSYCalled party busy
NO_ANSWERNo answer within timeout
CALL_REJECTEDCall was rejected
UNALLOCATED_NUMBERInvalid number
NETWORK_OUT_OF_ORDERNetwork issues

Best Practices

  1. Always return valid XML - Malformed XML will cause call failures
  2. Use HTTPS - All callback URLs should use HTTPS
  3. Handle timeouts - Include fallback behavior for user input
  4. Test thoroughly - Use ngrok for local development testing
  5. Log callback data - Store request parameters for debugging
  6. Return quickly - Plivo has a 15-second timeout for XML responses

Error Handling

If your server returns invalid XML:
  • The call may hang up unexpectedly
  • Plivo logs the error in your console
Common issues:
  • Malformed XML (unclosed tags)
  • Wrong content type
  • Empty response
  • Response too large