Agent-readable docs index: /docs/llms.txt. Full docs in one file: /docs/llms-full.txt. Download /docs/docs.zip to grep all markdown files locally.

TwiML verbs

Every TwiML verb with its attributes. All verbs live inside <Response> and execute in order.

<Say>

Speak text to the caller using text-to-speech.
<Response> <Say voice="alice" language="en-NG" loop="1">Welcome to Ruut Voice.</Say> </Response>
ParameterTypeDescription
voice optionalstringTTS voice (e.g. alice, man).
language optionalstringLanguage code (e.g. en-NG, en).
loop optionalintegerTimes to repeat (0 = infinite). Default 1.
SDK: response.say("…", { voice: "alice", language: "en-NG" })

<Play>

Play an audio file. The element content is the audio URL.
<Response> <Play loop="1">https://cdn.example.com/greeting.mp3</Play> </Response>
ParameterTypeDescription
loop optionalintegerTimes to repeat (0 = infinite). Default 1.
SDK: response.play("https://cdn.example.com/greeting.mp3", { loop: 1 })

<Gather>

Collect DTMF digits (or a spoken keypress) from the caller, then request the action URL with the input.
<Response> <Gather numDigits="1" action="/twiml/menu" method="POST"> <Say>Press 1 for sales. Press 2 for support.</Say> </Gather> <Say>No input received.</Say> </Response>
ParameterTypeDescription
action optionalstringURL to request when gathering finishes (with Digits).
method optionalstringHTTP method for action: GET or POST.
numDigits optionalintegerNumber of digits to collect before proceeding.
finishOnKey optionalstringDigit that ends gathering (e.g. #).
timeout optionalintegerSeconds to wait for input. Default 5.
actionOnEmptyResult optionalbooleanRequest action even when no input is received.
SDK: response.gather({ numDigits: 1, action: "/twiml/menu" }, (g) => g.say("Press 1 for sales."))

<Record>

Record the caller's voice — a message, a greeting, or a conversation — and optionally transcribe it.
<Response> <Say>Please leave a message after the tone.</Say> <Record transcribe="true" transcribeCallback="/twiml/transcription" maxLength="120" playBeep="true" /> </Response>
ParameterTypeDescription
action optionalstringURL to request when recording completes.
method optionalstringHTTP method for action.
timeout optionalintegerSeconds of silence before finishing. Default 5.
finishOnKey optionalstringKey that ends the recording.
maxLength optionalintegerMaximum recording length in seconds. Default 3600.
playBeep optionalbooleanPlay a beep before recording. Default true.
transcribe optionalbooleanTranscribe the recording after it completes.
transcribeCallback optionalstringURL to receive the transcription webhook.
recordingStatusCallback optionalstringURL to receive recording status webhooks.
SDK: response.record({ transcribe: true, transcribeCallback: "/twiml/transcription" })

<Dial>

Transfer the call to a phone number, SIP URI, client, or conference. Nested nouns choose the target.
<Response> <Dial record="record-from-answer-dual" callerId="+2348000000002">+2348000000009</Dial> </Response>
ParameterTypeDescription
callerId optionalstringCaller ID presented to the destination.
record optionalstringRecording mode: do-not-record, record-from-answer, record-from-ringing, record-from-answer-dual, record-from-ringing-dual.
recordingTrack optionalstringTrack(s) to record: inbound, outbound, or both.
recordingStatusCallback optionalstringURL for recording status webhooks.
recordingStatusCallbackMethod optionalstringHTTP method for the callback.
recordingStatusCallbackEvent optionalstringEvents to notify on (e.g. in-progress completed absent).
timeout optionalintegerSeconds to ring before giving up. Default 60.

Nested nouns

  • <Number> — dial an E.164 number.
  • <Sip> — dial a SIP URI (e.g. sip:agent-1001@sip.ruut.chat).
  • <Client> — dial a registered client/softphone identity.
  • <Conference> — join a conference; see recording for recording conferences.
// Conference with recording new VoiceResponse() .dial({ record: "record-from-answer-dual" }, (d) => { d.conference("support-room", { startConferenceOnEnter: true, endConferenceOnExit: false }); }) .toXml();

<Pause>

Wait for a number of seconds.
<Response> <Say>Checking your account.</Say> <Pause length="2" /> </Response>
ParameterTypeDescription
length optionalintegerSeconds to pause. Default 1.

<Redirect>

Fetch new TwiML from a URL and continue executing from there.
<Response> <Redirect method="POST">https://app.example.com/twiml/next</Redirect> </Response>
ParameterTypeDescription
method optionalstringHTTP method for the URL: GET or POST.

<Reject>

Reject an incoming call without answering (useful for blocking numbers).
<Response> <Reject reason="busy" /> </Response>
ParameterTypeDescription
reason optionalstringRejection reason: rejected or busy.

<Hangup>

End the call immediately.
<Response> <Say>Goodbye.</Say> <Hangup /> </Response>

<Connect>

Connect the call to a media stream (e.g. for a voice AI agent or live transcription).
<Response> <Connect> <Stream url="wss://app.example.com/audio" /> </Connect> </Response>
ParameterTypeDescription
url optionalstringWebSocket URL to stream audio to (on <Stream>).
name optionalstringStream name.
track optionalstringTrack(s): inbound_track, outbound_track, or both_tracks.
See the receive calls guide for a full IVR example, and the TwiML overview for structure and content-type notes.