or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-services.mdauthentication-jwt.mdcore-communications.mdindex.mdinfrastructure.mdrest-client.mdtwiml-generation.mdwebhooks-validation.md

twiml-generation.mddocs/

0

# TwiML Generation

1

2

XML markup language generation for controlling voice calls and messaging flows. Provides Python classes that generate TwiML XML for call routing, text-to-speech, user input collection, and message handling.

3

4

## Capabilities

5

6

### Voice Response Generation

7

8

Create TwiML responses for voice calls with support for speech synthesis, call routing, user input collection, and call control.

9

10

```python { .api }

11

class VoiceResponse:

12

"""Main class for generating voice TwiML responses"""

13

14

def __init__(self):

15

"""Initialize a new voice response"""

16

17

def say(

18

self,

19

message: str = None,

20

voice: str = None,

21

language: str = None,

22

loop: int = None

23

) -> Say:

24

"""

25

Text-to-speech synthesis.

26

27

Args:

28

message (str): Text to speak

29

voice (str): Voice to use ('man', 'woman', 'alice')

30

language (str): Language code (e.g., 'en-US', 'es-ES')

31

loop (int): Number of times to repeat

32

33

Returns:

34

Say: Say verb element

35

"""

36

37

def play(

38

self,

39

url: str = None,

40

loop: int = None,

41

digits: str = None

42

) -> Play:

43

"""

44

Play audio file from URL.

45

46

Args:

47

url (str): URL of audio file to play

48

loop (int): Number of times to repeat

49

digits (str): DTMF digits to send during playback

50

51

Returns:

52

Play: Play verb element

53

"""

54

55

def dial(

56

self,

57

number: str = None,

58

action: str = None,

59

method: str = None,

60

timeout: int = None,

61

hangup_on_star: bool = None,

62

time_limit: int = None,

63

caller_id: str = None,

64

record: str = None,

65

trim: str = None,

66

recording_status_callback: str = None,

67

recording_status_callback_method: str = None,

68

recording_status_callback_event: list = None,

69

answer_on_bridge: bool = None,

70

ring_tone: str = None,

71

recording_track: str = None,

72

sequential: bool = None

73

) -> Dial:

74

"""

75

Dial phone numbers, SIP addresses, or clients.

76

77

Args:

78

number (str): Phone number to dial

79

action (str): Webhook URL after dial completes

80

method (str): HTTP method for action URL

81

timeout (int): Ring timeout in seconds

82

hangup_on_star (bool): Hang up when caller presses *

83

time_limit (int): Maximum call duration in seconds

84

caller_id (str): Caller ID to display

85

record (str): Record the call ('record-from-answer')

86

87

Returns:

88

Dial: Dial verb element

89

"""

90

91

def gather(

92

self,

93

input: str = None,

94

action: str = None,

95

method: str = None,

96

timeout: int = None,

97

finish_on_key: str = None,

98

num_digits: int = None,

99

partial_result_callback: str = None,

100

partial_result_callback_method: str = None,

101

language: str = None,

102

hints: str = None,

103

barge_in: bool = None,

104

debug: bool = None,

105

action_on_empty_result: bool = None,

106

speech_timeout: str = None,

107

enhanced: bool = None,

108

speech_model: str = None,

109

profanity_filter: bool = None

110

) -> Gather:

111

"""

112

Collect user input via DTMF or speech.

113

114

Args:

115

input (str): Input type ('dtmf', 'speech', 'dtmf speech')

116

action (str): Webhook URL to send results

117

method (str): HTTP method for action URL

118

timeout (int): Input timeout in seconds

119

finish_on_key (str): Key to end input (default: #)

120

num_digits (int): Number of digits to collect

121

language (str): Speech recognition language

122

hints (str): Speech recognition hints

123

barge_in (bool): Allow input during nested verbs

124

125

Returns:

126

Gather: Gather verb element

127

"""

128

129

def record(

130

self,

131

action: str = None,

132

method: str = None,

133

timeout: int = None,

134

finish_on_key: str = None,

135

max_length: int = None,

136

play_beep: bool = None,

137

trim: str = None,

138

recording_status_callback: str = None,

139

recording_status_callback_method: str = None,

140

transcribe: bool = None,

141

transcribe_callback: str = None

142

) -> Record:

143

"""

144

Record caller's voice.

145

146

Args:

147

action (str): Webhook URL after recording

148

method (str): HTTP method for action URL

149

timeout (int): Silence timeout in seconds

150

finish_on_key (str): Key to stop recording

151

max_length (int): Maximum recording length in seconds

152

play_beep (bool): Play beep before recording

153

trim (str): Trim silence ('trim-silence')

154

transcribe (bool): Enable transcription

155

156

Returns:

157

Record: Record verb element

158

"""

159

160

def pause(self, length: int = None) -> Pause:

161

"""

162

Pause execution.

163

164

Args:

165

length (int): Pause duration in seconds

166

167

Returns:

168

Pause: Pause verb element

169

"""

170

171

def redirect(

172

self,

173

url: str = None,

174

method: str = None

175

) -> Redirect:

176

"""

177

Redirect to new TwiML URL.

178

179

Args:

180

url (str): New TwiML URL

181

method (str): HTTP method ('GET' or 'POST')

182

183

Returns:

184

Redirect: Redirect verb element

185

"""

186

187

def hangup(self) -> Hangup:

188

"""

189

End the call.

190

191

Returns:

192

Hangup: Hangup verb element

193

"""

194

195

def reject(self, reason: str = None) -> Reject:

196

"""

197

Reject incoming call.

198

199

Args:

200

reason (str): Rejection reason ('rejected', 'busy')

201

202

Returns:

203

Reject: Reject verb element

204

"""

205

206

def enqueue(

207

self,

208

name: str = None,

209

action: str = None,

210

method: str = None,

211

wait_url: str = None,

212

wait_url_method: str = None,

213

workflow_sid: str = None

214

) -> Enqueue:

215

"""

216

Place caller in queue.

217

218

Args:

219

name (str): Queue name

220

action (str): Webhook URL after dequeue

221

wait_url (str): TwiML URL while waiting

222

workflow_sid (str): TaskRouter workflow SID

223

224

Returns:

225

Enqueue: Enqueue verb element

226

"""

227

228

def leave(self) -> Leave:

229

"""

230

Leave current queue.

231

232

Returns:

233

Leave: Leave verb element

234

"""

235

236

def to_xml(self) -> str:

237

"""

238

Generate XML string.

239

240

Returns:

241

str: Complete TwiML XML document

242

"""

243

244

# Dial sub-elements

245

class Number:

246

"""Phone number to dial within <Dial>"""

247

def __init__(

248

self,

249

number: str,

250

send_digits: str = None,

251

url: str = None,

252

method: str = None,

253

status_callback_event: list = None,

254

status_callback: str = None,

255

status_callback_method: str = None,

256

byoc: str = None,

257

machine_detection: str = None,

258

machine_detection_timeout: int = None,

259

amd_status_callback: str = None,

260

amd_status_callback_method: str = None

261

): ...

262

263

class Conference:

264

"""Conference room within <Dial>"""

265

def __init__(

266

self,

267

name: str,

268

muted: bool = None,

269

beep: str = None,

270

start_conference_on_enter: bool = None,

271

end_conference_on_exit: bool = None,

272

wait_url: str = None,

273

wait_method: str = None,

274

max_participants: int = None,

275

record: str = None,

276

region: str = None,

277

whisper: str = None,

278

trim: str = None,

279

status_callback_event: list = None,

280

status_callback: str = None,

281

status_callback_method: str = None,

282

recording_status_callback: str = None,

283

recording_status_callback_method: str = None,

284

recording_status_callback_event: list = None,

285

event_callback_url: str = None,

286

jitter_buffer_size: str = None,

287

coach: str = None,

288

call_sid_to_coach: str = None

289

): ...

290

291

class Queue:

292

"""Queue within <Dial>"""

293

def __init__(

294

self,

295

name: str,

296

url: str = None,

297

method: str = None,

298

reservation_sid: str = None,

299

post_work_activity_sid: str = None

300

): ...

301

302

class Sip:

303

"""SIP address within <Dial>"""

304

def __init__(

305

self,

306

uri: str,

307

username: str = None,

308

password: str = None

309

): ...

310

311

class Client:

312

"""Twilio Client within <Dial>"""

313

def __init__(

314

self,

315

identity: str,

316

url: str = None,

317

method: str = None,

318

status_callback_event: list = None,

319

status_callback: str = None,

320

status_callback_method: str = None

321

): ...

322

```

323

324

Voice TwiML examples:

325

326

```python

327

from twilio.twiml.voice_response import VoiceResponse

328

329

# Basic text-to-speech

330

response = VoiceResponse()

331

response.say("Hello, welcome to our service!")

332

print(response)

333

# Output: <Response><Say>Hello, welcome to our service!</Say></Response>

334

335

# Play audio with loop

336

response = VoiceResponse()

337

response.play("https://example.com/music.mp3", loop=3)

338

339

# Collect DTMF input

340

response = VoiceResponse()

341

gather = response.gather(num_digits=4, action="/process-input", method="POST")

342

gather.say("Please enter your 4-digit PIN followed by the pound key")

343

response.say("We didn't receive any input. Goodbye!")

344

345

# Make outbound call

346

response = VoiceResponse()

347

dial = response.dial("+15559876543", timeout=30, caller_id="+15551234567")

348

349

# Conference call

350

response = VoiceResponse()

351

dial = response.dial()

352

dial.conference("My Conference Room",

353

start_conference_on_enter=True,

354

end_conference_on_exit=True)

355

356

# Record voicemail

357

response = VoiceResponse()

358

response.say("Please leave a message after the beep")

359

response.record(max_length=30,

360

action="/handle-recording",

361

finish_on_key="#")

362

363

# Call screening with gather

364

response = VoiceResponse()

365

gather = response.gather(num_digits=1, action="/screen-response")

366

gather.say("Press 1 to accept this call, press 2 to send to voicemail")

367

response.hangup()

368

369

# Complex call flow

370

response = VoiceResponse()

371

gather = response.gather(input="speech dtmf",

372

action="/handle-input",

373

speech_timeout="auto")

374

gather.say("Say or press a department: Sales, Support, or Billing")

375

response.redirect("/main-menu")

376

```

377

378

### Messaging Response Generation

379

380

Create TwiML responses for SMS/MMS message handling with support for replies and redirects.

381

382

```python { .api }

383

class MessagingResponse:

384

"""Main class for generating messaging TwiML responses"""

385

386

def __init__(self):

387

"""Initialize a new messaging response"""

388

389

def message(

390

self,

391

body: str = None,

392

to: str = None,

393

from_: str = None,

394

action: str = None,

395

method: str = None,

396

status_callback: str = None

397

) -> Message:

398

"""

399

Send reply message.

400

401

Args:

402

body (str): Message text content

403

to (str): Recipient phone number

404

from_ (str): Sender phone number

405

action (str): Webhook URL after sending

406

method (str): HTTP method for action URL

407

status_callback (str): Delivery status webhook

408

409

Returns:

410

Message: Message element

411

"""

412

413

def redirect(

414

self,

415

url: str = None,

416

method: str = None

417

) -> Redirect:

418

"""

419

Redirect to new TwiML URL.

420

421

Args:

422

url (str): New TwiML URL

423

method (str): HTTP method ('GET' or 'POST')

424

425

Returns:

426

Redirect: Redirect element

427

"""

428

429

def to_xml(self) -> str:

430

"""

431

Generate XML string.

432

433

Returns:

434

str: Complete TwiML XML document

435

"""

436

437

class Message:

438

"""Message element for replies"""

439

def __init__(

440

self,

441

body: str = None,

442

to: str = None,

443

from_: str = None,

444

action: str = None,

445

method: str = None,

446

status_callback: str = None

447

): ...

448

449

def body(self, message: str) -> Body:

450

"""Set message body text"""

451

452

def media(self, url: str) -> Media:

453

"""Add media attachment"""

454

455

class Body:

456

"""Message body text"""

457

def __init__(self, message: str): ...

458

459

class Media:

460

"""Media attachment"""

461

def __init__(self, url: str): ...

462

```

463

464

Messaging TwiML examples:

465

466

```python

467

from twilio.twiml.messaging_response import MessagingResponse

468

469

# Simple reply

470

response = MessagingResponse()

471

response.message("Thanks for your message!")

472

print(response)

473

# Output: <Response><Message>Thanks for your message!</Message></Response>

474

475

# Reply with media

476

response = MessagingResponse()

477

message = response.message()

478

message.body("Here's the image you requested:")

479

message.media("https://example.com/image.jpg")

480

481

# Forward to another number

482

response = MessagingResponse()

483

response.message("Message forwarded", to="+15551234567")

484

485

# Auto-reply with redirect

486

response = MessagingResponse()

487

response.message("Processing your request...")

488

response.redirect("/process-message", method="POST")

489

490

# Conditional responses based on webhook data

491

response = MessagingResponse()

492

# This would typically be in a webhook handler

493

incoming_body = "HELP" # From webhook parameters

494

if incoming_body.upper() == "HELP":

495

response.message("Available commands: INFO, SUPPORT, STOP")

496

elif incoming_body.upper() == "STOP":

497

response.message("You have been unsubscribed.")

498

else:

499

response.message("Unknown command. Reply HELP for options.")

500

```

501

502

### TwiML Base Classes

503

504

Base functionality shared across voice and messaging TwiML generation.

505

506

```python { .api }

507

class TwiML:

508

"""Base class for all TwiML responses"""

509

510

def __init__(self):

511

"""Initialize TwiML response"""

512

513

def append(self, twiml: 'TwiML') -> 'TwiML':

514

"""

515

Append another TwiML element.

516

517

Args:

518

twiml (TwiML): Element to append

519

520

Returns:

521

TwiML: Self for chaining

522

"""

523

524

def to_xml(self) -> str:

525

"""

526

Generate XML string representation.

527

528

Returns:

529

str: XML document string

530

"""

531

532

def __str__(self) -> str:

533

"""String representation returns XML"""

534

535

class GenericNode:

536

"""Generic XML element for custom TwiML"""

537

538

def __init__(

539

self,

540

name: str,

541

body: str = None,

542

**kwargs

543

):

544

"""

545

Create custom XML element.

546

547

Args:

548

name (str): XML element name

549

body (str): Element text content

550

**kwargs: Element attributes

551

"""

552

```

553

554

Advanced TwiML usage:

555

556

```python

557

from twilio.twiml.voice_response import VoiceResponse

558

from twilio.twiml import GenericNode

559

560

# Chaining TwiML elements

561

response = VoiceResponse()

562

response.say("Welcome").pause(1).say("Please hold")

563

564

# Using generic nodes for custom elements

565

response = VoiceResponse()

566

custom = GenericNode("CustomElement", "Custom content", attr="value")

567

response.append(custom)

568

569

# Building complex nested structures

570

response = VoiceResponse()

571

gather = response.gather(action="/process")

572

gather.say("Press 1 for sales")

573

gather.pause(1)

574

gather.say("Press 2 for support")

575

response.say("No input received")

576

response.hangup()

577

578

# Multiple dial targets

579

response = VoiceResponse()

580

dial = response.dial()

581

dial.number("+15551111111", status_callback="/call-progress")

582

dial.number("+15552222222", status_callback="/call-progress")

583

dial.client("alice")

584

585

# XML output customization

586

response = VoiceResponse()

587

response.say("Hello")

588

xml_string = response.to_xml()

589

print(xml_string) # Pretty-printed XML

590

```

591

592

### Fax Response Generation

593

594

Create TwiML responses for fax transmission and reception handling.

595

596

```python { .api }

597

class FaxResponse:

598

"""Main class for generating fax TwiML responses"""

599

600

def __init__(self):

601

"""Initialize a new fax response"""

602

603

def receive(

604

self,

605

action: str = None,

606

method: str = None,

607

media_type: str = None,

608

store_media: bool = None,

609

page_size: str = None

610

) -> Receive:

611

"""

612

Receive incoming fax transmission.

613

614

Args:

615

action (str): Webhook URL after fax reception

616

method (str): HTTP method for action URL

617

media_type (str): Media type ('application/pdf', 'image/tiff')

618

store_media (bool): Store received fax media

619

page_size (str): Page size for received fax

620

621

Returns:

622

Receive: Receive verb element

623

"""

624

625

def reject(self, reason: str = None) -> Reject:

626

"""

627

Reject incoming fax.

628

629

Args:

630

reason (str): Rejection reason

631

632

Returns:

633

Reject: Reject verb element

634

"""

635

636

def to_xml(self) -> str:

637

"""

638

Generate XML string.

639

640

Returns:

641

str: Complete TwiML XML document

642

"""

643

644

class Receive:

645

"""Fax receive element"""

646

def __init__(

647

self,

648

action: str = None,

649

method: str = None,

650

media_type: str = None,

651

store_media: bool = None,

652

page_size: str = None

653

): ...

654

```

655

656

Fax TwiML examples:

657

658

```python

659

from twilio.twiml.fax_response import FaxResponse

660

661

# Receive incoming fax

662

response = FaxResponse()

663

response.receive(

664

action="/fax-received",

665

method="POST",

666

media_type="application/pdf",

667

store_media=True

668

)

669

print(response)

670

# Output: <Response><Receive action="/fax-received" method="POST" mediaType="application/pdf" storeMedia="true"/></Response>

671

672

# Reject fax

673

response = FaxResponse()

674

response.reject(reason="busy")

675

print(response)

676

# Output: <Response><Reject reason="busy"/></Response>

677

```

678

679

## TwiML Integration Patterns

680

681

### Webhook Integration

682

683

TwiML responses are typically generated in webhook handlers that respond to Twilio HTTP requests.

684

685

```python

686

from flask import Flask, request

687

from twilio.twiml.voice_response import VoiceResponse

688

689

app = Flask(__name__)

690

691

@app.route("/voice", methods=['GET', 'POST'])

692

def voice_handler():

693

"""Handle incoming voice calls"""

694

response = VoiceResponse()

695

696

# Access Twilio parameters

697

from_number = request.values.get('From')

698

to_number = request.values.get('To')

699

call_sid = request.values.get('CallSid')

700

701

response.say(f"Hello, you called {to_number} from {from_number}")

702

703

return str(response)

704

705

@app.route("/sms", methods=['GET', 'POST'])

706

def sms_handler():

707

"""Handle incoming SMS messages"""

708

from twilio.twiml.messaging_response import MessagingResponse

709

710

response = MessagingResponse()

711

712

# Access message parameters

713

from_number = request.values.get('From')

714

body = request.values.get('Body', '').strip()

715

716

if body.lower() == 'hello':

717

response.message("Hi there! How can I help you?")

718

else:

719

response.message("Thanks for your message!")

720

721

return str(response)

722

```

723

724

### Dynamic TwiML Generation

725

726

Build TwiML responses based on database queries or external APIs.

727

728

```python

729

def create_menu_twiml(menu_options):

730

"""Generate dynamic menu TwiML"""

731

response = VoiceResponse()

732

733

gather = response.gather(num_digits=1, action="/handle-menu")

734

gather.say("Please select from the following options:")

735

736

for i, option in enumerate(menu_options, 1):

737

gather.say(f"Press {i} for {option}")

738

739

response.say("Invalid selection. Please try again.")

740

response.redirect("/main-menu")

741

742

return response

743

744

# Usage

745

menu_items = ["Sales", "Support", "Billing", "Directory"]

746

twiml = create_menu_twiml(menu_items)

747

```