# Twilio Integration

> Configure Twilio for global voice agent calls with WebSocket streaming.

Source: https://edesy.in/docs/voice-agent/telephony/twilio

Twilio is the most widely-used cloud communications platform, offering excellent global coverage and robust APIs.

## Why Twilio?

- **Global Coverage**: 180+ countries
- **Excellent Documentation**: Best-in-class developer experience
- **Native WebSocket**: First-class streaming support via Media Streams

## Prerequisites

1. Twilio account (sign up at [twilio.com](https://www.twilio.com))
2. A phone number capable of voice calls
3. Account SID and Auth Token

## Configuration

### Environment Variables

```bash
TWILIO_ACCOUNT_SID=ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TWILIO_AUTH_TOKEN=your_auth_token_here
TWILIO_PHONE_NUMBER=+1234567890
```

### TwiML Configuration

For inbound calls, configure your Twilio phone number's webhook to return TwiML that connects to your WebSocket:

```xml
<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Connect>
        <Stream url="wss://your-domain.com/agent/{agentId}/user/{userId}/">
            <Parameter name="agentId" value="{agentId}"/>
        </Stream>
    </Connect>
</Response>
```

## Call Flows

### Inbound Call Flow

```
1. Caller dials your Twilio number
          ↓
2. Twilio requests TwiML from your webhook
          ↓
3. Your server returns TwiML with <Stream> element
          ↓
4. Twilio connects WebSocket to specified URL
          ↓
5. Bidirectional audio streaming begins
          ↓
6. Voice agent handles conversation
```

### Outbound Call Flow

```
1. POST /make-call with agent_id, phone_number
          ↓
2. TwilioMakeCall() builds TwiML with WebSocket URL
          ↓
3. POST to Twilio API to initiate call
          ↓
4. Twilio dials recipient
          ↓
5. On answer, Twilio connects to WebSocket
          ↓
6. Voice agent handles conversation
```

## API Reference

### Make Outbound Call

```bash
POST /make-call
Content-Type: application/json

{
  "agent_id": "123",
  "phone_number": "+1234567890",
  "workspace_id": "ws_456",
  "call_provider": "twilio",
  "variables": {
    "customer_name": "John Doe",
    "order_id": "ORD-12345"
  }
}
```

> **Need your workspace ID?** See [Finding Your Workspace ID](https://edesy.in/docs/voice-agent/workspace/finding-workspace-id).

**Response:**
```json
{
  "status": "success",
  "call_sid": "CAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
```

### WebSocket Message Format

Twilio uses **camelCase** for message fields:

**Connected Message:**
```json
{
  "event": "connected",
  "protocol": "Call",
  "version": "1.0.0"
}
```

**Start Message:**
```json
{
  "event": "start",
  "sequenceNumber": "1",
  "start": {
    "streamSid": "MZxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "callSid": "CAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "accountSid": "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "tracks": ["inbound"],
    "customParameters": {
      "agentId": "123"
    }
  },
  "streamSid": "MZxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
```

**Media Message (from Twilio):**
```json
{
  "event": "media",
  "sequenceNumber": "2",
  "media": {
    "track": "inbound",
    "chunk": "1",
    "timestamp": "5",
    "payload": "base64_encoded_mulaw_audio..."
  },
  "streamSid": "MZxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
```

**Media Response (to Twilio):**
```json
{
  "event": "media",
  "streamSid": "MZxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "media": {
    "payload": "base64_encoded_mulaw_audio..."
  }
}
```

**Clear Buffer:**
```json
{
  "event": "clear",
  "streamSid": "MZxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
```

## Audio Specifications

| Parameter | Value |
|-----------|-------|
| Sample Rate | 8000 Hz |
| Channels | Mono |
| Encoding | **μ-law (mulaw)** |
| Chunk Size | ~20ms per frame |

### Audio Conversion

Twilio uses μ-law encoding. Convert to/from Linear PCM:

```go
// μ-law to Linear PCM
func mulawToLinear(mulaw byte) int16 {
    mulaw = ^mulaw
    sign := (mulaw & 0x80) >> 7
    exponent := (mulaw & 0x70) >> 4
    mantissa := mulaw & 0x0F

    sample := ((int16(mantissa) << 3) + 0x84) << exponent
    sample -= 0x84

    if sign == 1 {
        return -sample
    }
    return sample
}
```

## Recording

Enable call recording in your TwiML or API call:

```go
payload.Set("Record", "true")
payload.Set("RecordingStatusCallback", "https://your-domain.com/api/webhooks/telephony/twilio")
```

## Status Webhooks

Configure status callback URL to receive call events:

```bash
POST /api/webhooks/telephony/twilio
Content-Type: application/x-www-form-urlencoded

CallSid=CAxxxxxxxxx&
CallStatus=completed&
Duration=120&
RecordingUrl=https://api.twilio.com/...
```

## Pricing

| Region | Outbound/min | Inbound/min |
|--------|-------------|-------------|
| US/Canada | $0.014 | $0.0085 |
| UK | $0.045 | $0.0085 |
| India | $0.025 | $0.0085 |

*Prices as of 2024. Check [Twilio Pricing](https://www.twilio.com/voice/pricing) for current rates.*

## Troubleshooting

### WebSocket Not Connecting

1. Verify your domain has valid SSL certificate
2. Check Twilio console for error logs
3. Ensure WebSocket endpoint is publicly accessible

### Audio Quality Issues

1. Verify μ-law encoding/decoding is correct
2. Check for sample rate mismatches
3. Monitor WebSocket latency

### Call Not Initiating

1. Verify Account SID and Auth Token
2. Check phone number format (E.164: +1234567890)
3. Ensure account has sufficient balance

## Next Steps

- [Exotel Integration](https://edesy.in/docs/voice-agent/telephony/exotel) - Alternative for India
- [STT Configuration](https://edesy.in/docs/voice-agent/providers/deepgram) - Optimize speech recognition
- [Latency Optimization](https://edesy.in/docs/voice-agent/advanced/latency) - Reduce response time
