> ## Documentation Index
> Fetch the complete documentation index at: https://plivo.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Overview

> Control voice calls with XML instructions for IVR, call routing, recording, and more

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:

```xml theme={null}
<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

```xml theme={null}
<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

<CodeGroup>
  ```python Python theme={null}
  from plivo import plivoxml

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

  xml_string = response.to_string()
  ```

  ```javascript Node.js theme={null}
  const plivo = require('plivo');

  const response = plivo.Response();
  response.addSpeak('Hello, world!');
  response.addHangup();

  const xmlString = response.toXML();
  ```

  ```ruby Ruby theme={null}
  require 'plivo'

  response = Plivo::XML::Response.new
  response.addSpeak('Hello, world!')
  response.addHangup()

  xml_string = Plivo::XML::PlivoXML.new(response).to_xml
  ```

  ```php PHP theme={null}
  use Plivo\XML\Response;

  $response = new Response();
  $response->addSpeak('Hello, world!');
  $response->addHangup();

  $xml_string = $response->toXML();
  ```

  ```java Java theme={null}
  import com.plivo.api.xml.*;

  Response response = new Response()
      .children(
          new Speak("Hello, world!"),
          new Hangup()
      );

  String xmlString = response.toXmlString();
  ```

  ```csharp .NET theme={null}
  using Plivo.XML;

  var response = new Response();
  response.AddSpeak("Hello, world!");
  response.AddHangup();

  string xmlString = response.ToString();
  ```

  ```go Go theme={null}
  import "github.com/plivo/plivo-go/v7/xml"

  response := xml.ResponseElement{
      Contents: []interface{}{
          new(xml.SpeakElement).AddSpeak("Hello, world!"),
          new(xml.HangupElement),
      },
  }

  xmlString := response.String()
  ```
</CodeGroup>

***

## Available XML Elements

### Audio Output

| Element                                 | Description            |
| --------------------------------------- | ---------------------- |
| [Speak](/voice/xml/audio-output/#speak) | Convert text to speech |
| [Play](/voice/xml/audio-output/#play)   | Play an audio file     |
| [DTMF](/voice/xml/audio-output/#dtmf)   | Send DTMF tones        |

### Input Collection

| Element                                  | Description                   |
| ---------------------------------------- | ----------------------------- |
| [GetDigits](/voice/xml/input/#getdigits) | Collect DTMF digit input      |
| [GetInput](/voice/xml/input/#getinput)   | Collect speech or digit input |

### Call Routing

| Element                                  | Description                               |
| ---------------------------------------- | ----------------------------------------- |
| [Dial](/voice/xml/routing/#dial)         | Connect to another number or SIP endpoint |
| [Redirect](/voice/xml/routing/#redirect) | Transfer call flow to another URL         |
| [Hangup](/voice/xml/routing/#hangup)     | End the call                              |
| [Wait](/voice/xml/routing/#wait)         | Pause execution                           |

### Conferencing

| Element                                       | Description                         |
| --------------------------------------------- | ----------------------------------- |
| [Conference](/voice/xml/conference/)          | Connect caller to a conference room |
| [MultiPartyCall](/voice/xml/multiparty-call/) | Advanced multi-party conferencing   |

### Recording

| Element                      | Description                  |
| ---------------------------- | ---------------------------- |
| [Record](/voice/xml/record/) | Record the call or a message |

### Advanced

| Element                                   | Description                          |
| ----------------------------------------- | ------------------------------------ |
| [PreAnswer](/voice/xml/routing#preanswer) | Play media before answering          |
| [Stream](/voice/xml/audio-streaming)      | Stream real-time audio via WebSocket |

***

## Nesting Elements

Some elements can be nested inside others:

```xml theme={null}
<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 Element | Allowed Children  |
| -------------- | ----------------- |
| Response       | All elements      |
| GetDigits      | Speak, Play       |
| GetInput       | Speak, Play       |
| Dial           | Number, User      |
| PreAnswer      | Speak, Play, Wait |

***

## Request Parameters

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

### Voice Call Parameters

| Parameter    | Description                                        |
| ------------ | -------------------------------------------------- |
| `CallUUID`   | Unique identifier for this call                    |
| `From`       | Caller's phone number (with country code)          |
| `To`         | Called phone number (with country code)            |
| `CallStatus` | Call status: `ringing`, `in-progress`, `completed` |
| `Direction`  | `inbound` 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

| Parameter         | Description                  |
| ----------------- | ---------------------------- |
| `ALegUUID`        | UUID of the first call leg   |
| `ALegRequestUUID` | Request UUID returned by API |

### Call Forwarding

| Parameter       | Description                                                |
| --------------- | ---------------------------------------------------------- |
| `ForwardedFrom` | Original number (if call was forwarded). Carrier-dependent |

### Completed Call Parameters

| Parameter      | Description                     |
| -------------- | ------------------------------- |
| `HangupCause`  | Standard telephony hangup cause |
| `Duration`     | Call duration in seconds        |
| `BillDuration` | Billed duration in seconds      |
| `TotalCost`    | Total cost of the call          |

### Call Status Values

| Status        | Description                                 |
| ------------- | ------------------------------------------- |
| `ringing`     | Call is ringing (inbound, not yet answered) |
| `in-progress` | Call is active                              |
| `completed`   | Call ended normally                         |
| `busy`        | Called party was busy (outbound only)       |
| `failed`      | Call failed to connect (outbound only)      |
| `timeout`     | No answer within timeout (outbound only)    |
| `no-answer`   | Called party didn't answer (outbound only)  |

### SIP Headers

For SIP calls, custom SIP headers are included with the `X-PH-` prefix:

| Header Format       | Description             |
| ------------------- | ----------------------- |
| `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

```python theme={null}
# Flask
from flask import Response
return Response(xml_string, mimetype='application/xml')
```

```javascript theme={null}
// Express
res.set('Content-Type', 'application/xml');
res.send(xmlString);
```

```ruby theme={null}
# Sinatra
content_type 'application/xml'
xml_string
```

```php theme={null}
// PHP
header('Content-Type: application/xml');
echo $xml_string;
```

### Empty Response

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

```xml theme={null}
<Response>
</Response>
```

***

## Example: Using Request Parameters

```python theme={null}
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

```xml theme={null}
<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

```xml theme={null}
<Response>
    <Dial callerId="+14155551234">
        <Number>+14155559876</Number>
    </Dial>
</Response>
```

***

## Hangup Causes

Common hangup cause values:

| Cause                  | Description              |
| ---------------------- | ------------------------ |
| `NORMAL_CLEARING`      | Normal call termination  |
| `USER_BUSY`            | Called party busy        |
| `NO_ANSWER`            | No answer within timeout |
| `CALL_REJECTED`        | Call was rejected        |
| `UNALLOCATED_NUMBER`   | Invalid number           |
| `NETWORK_OUT_OF_ORDER` | Network 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

***

## Related

* [Audio Output](/voice/xml/audio-output/) - Speak, Play, DTMF
* [Input Collection](/voice/xml/input/) - GetDigits, GetInput
* [Call Routing](/voice/xml/routing/) - Dial, Redirect, Hangup, Wait
* [Conference](/voice/xml/conference/) - Conference calls
* [Multi-party Call](/voice/xml/multiparty-call/) - Role-based multi-party calls
* [Recording](/voice/xml/record/) - Record calls and messages
* [Audio Streaming](/voice/xml/audio-streaming) - Stream real-time audio
