TwiML™ for Programmable Voice

TwiMLとは何か

TwiMLは、通話やFaxの着信やSMSの受信時にTwilioが行うべきことを指示するために使用される一連の命令文です。

Twilio電話番号に音声通話の着信があった場合、Twilioはその電話番号に関連づけられたURLを見つけ、そのURLにリクエストを送信します。 その後TwilioはそのURLでTwiML命令を読んで通話の録音、発信者に対するメッセージの読み上げ、プッシュボタンによる番号の入力を促すなどといった、実行する内容を決定します。

たとえば、次のサンプルでは、短いアナウンスを流した後、発信者の声を録音します。

<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Say voice="woman">Please leave a message after the tone.</Say>
    <Record maxLength="20" />
</Response>

TwiML は HTML とよく似ています。 一度に1つの TwiML 文書だけが実行されますが、TwiML 文書を複数リンクさせれば、複雑な音声処理アプリケーションを作ることができます。

Twilio番号から外部の番号に発信された通話は着信通話と同様の方法で、TwiMLを使用して制御されます。 通話のための開始URLは、通話を開始するために送信するTwilio REST APIリクエストに対するパラメーターとして指定されます。

Programmable Voice用のTwiML動詞

下記の動詞をさまざまに組み合わせて使用し、あらゆる種類のインタラクティブな音声通話アプリケーションを作成できます。

  • Say - 通話の相手に対してテキストを読み上げます
  • Play - 通話の相手に対してオーディオファイルを再生します
  • Dial - 通話の相手をもうひとり追加します
  • Record - 通話の相手の音声を録音します
  • Gather - 通話の相手がプッシュボタンで入力した番号を収集します
  • Hangup - 通話を切断します
  • Enqueue - 通話の相手をキュー (待ち行列) に追加します
  • Leave - 通話の相手をキューから外します
  • Redirect - 通話のフローを別のTwiMLドキュメントにリダイレクトします
  • Pause - 追加の命令の実行前に待機します
  • Reject - 課金を発生させることなく着信通話を拒否します。

開発者のアプリケーションへのTwilioからのリクエスト

Twilioは通常のWebブラウザー同様、application/x-www-form-urlencoded形式でHTTPリクエストをユーザーのアプリケーションに送信します。 (Twilioが)このリクエストにパラメーターと値を含めることで、Twilioはユーザーのアプリケーションにデータを送信し、これを使用してレスポンスの前に処理を行うことができます。

TwilioはPOSTリクエストをキャッシュできません。 Twilioに静的なTwiMLページをキャッシュさせたい場合は、GETを使用してTwilioからリクエストを送信させるようにしてください。

Twilio番号のいずれかに着信があると、Twilioはその番号に対して構成されたVoice URLに同期HTTPリクエストを送信し、そのレスポンスとしてTwiMLの受信を想定しています。

Twilioはリクエストと一緒に下記のパラメーターを構成したHTTPメソッドに応じて、POSTパラメーターまたはURLクエリーパラメーターとして送信します。

リクエストパラメーター

パラメーター 説明
CallSid Twilio が生成したこの通話のユニークな識別子です。
AccountSid ユーザーの Twilio アカウント ID です。アカウント ID は 34 文字で、必ず AC から始まります。
From 通話を開始する側、つまり発信者の電話番号またはクライアント識別子です。 電話番号は、たとえば +16175551212 といったように「+」記号と国コードを使用してフォーマットされている (E.164形式) ことが必要です。 クライアント識別子は client: URIスキームから始まります。 たとえば「tommy」という名前のクライアント空の通話では、 From パラメーターは client:tommy となります。
To 発信先の電話番号またはクライアント識別子です。 電話番号は「+」希望に続き国コードが続く形式で指定します。 電話番号は「+」希望に続き国コードが続く形式で指定します。 (例: +16175551212) E.164形式と呼ばれます。クライアント識別子は client: URIスキームから始まります。 たとえば「joey」というクライアント名に通話を発信するには、 To パラメーターの値は client:joey となります。
CallStatus 通話に対する記述ステータスです。 あたいは下記のうちのいずれかです。 queuedringingin-progresscompletedbusyfailed、またはno-answerです。 詳細については下記のCallStatusセクションを参照してください。
ApiVersion この通話の処理に使用する Twilio API のバージョンです。 着信通話では、宛先の電話番号に設定された API バージョンになります。 発信通話では、発信通話の REST API リクエストで使用する API のバージョンになります。
Direction 通話の向きを示す文字列です。 着信通話については inbound、REST APIによって開始された通話については outbound-api 、または <Dial> 動詞によって開始された通話にはついては outbound-dial となります。
ForwardedFrom Twilio が転送通話を受けた場合のみ設定されます。ただし、転送情報などの値は、発信者が使用している通信事業者により異なります。 この情報を渡さない通信事業者もあります。
CallerName 通話の着信した IncomingPhoneNumber で VoiceCallerIdLookup の値が true に設定されている場合にこのパラメーターが設定されます (1回のルックアップにつき¥1.5) 。
ParentCallSid このレグを生成した通話の一意な識別子です。 通話の最初のレグにはこのパラメーターは渡されません。

Twilio は To と From の電話番号から、場所の検索も行います。 次のパラメーターが存在する場合は、これらも送信されます。

パラメーター 説明
FromCity 発信者の都市名です。
FromState 発信者の州名です。
FromZip 発信者の郵便番号です。
FromCountry 発信者の国名です。
ToCity 相手の都市名です。
ToState 相手の州名です。
ToZip 相手の郵便番号です。
ToCountry 相手の国名です。

通話中に起こったことに応じて、他の変数も送信されることがあります。

TwilioからSIPを受信する場合、下記のパラメーターも開発者のWebアプリケーションに対して送信されます。

パラメーター名 説明
SipDomain INVITEの送信元Twilio SIP ドメイン
SipUsername クレデンシャルリストが有効になっている際に認証に使われるユーザー名
SipCallId インカミングINVITEの Call-ID
SipSourceIp インカミングINVITEの送信元IPアドレス
SipHeader_<name> SipHeader_<name> としてインカミングINVITEに含まれるX- header。<name>がヘッダーキーになります。複数の値を受信できます。

CallStatus 値

下記が「CallStatus」パラメーターの取りうる値となります。 これらの値は <Dial> 動詞の action URLへのリクエストで送信される「DialCallStatus」パラメーターに対しても適用されます。

Status 説明
queued 通話は発信待ち状態です。
ringing 呼び出し中です。
in-progress 相手が応答し、通話中です。
completed 相手が応答し、通話が正常に終了しました。
BUSY 相手からビジー信号を受信しました。
failed 通話を接続できませんでした。通常は、ダイヤルした電話番号が存在しません。
no-answer 相手が応答せず、通話が終了しました。
canceled 通話がqueued(発信待機中)またはringing(呼び出し中)の間に、REST APIによってキャンセルされました。

通話終了のコールバック (StatusCallback)

通話の着信後、アプリケーションにTwiMLをリクエストし、それ処理し、最終的に通話が終了します。 Twilioは非同期のHTTPリクエストを着信したTwilio番号(もしあれば)用に設定されたStatusCallback URLに向けて発行します。

Twilio番号にStatusCallback URLを提供し、このリクエストを捕捉すると、通話の終了タイミングを検出してその通話についての情報を受け取ることができます。 相対URL以外では、有効なホスト名を指定しなければなりません(アンダースコアは使用できません)。

リクエストパラメーター

TwilioがStatusCallback URLへの非同期リクエストで開発者のアプリケーションに渡すパラメーターには同期TwiMLリクエストで渡されるパラメーターが含まれます。

この他にも、StatusCallback リクエストは次のパラメーターを渡します。

パラメーター 説明
CallDuration 通話の秒数
RecordingUrl 音声通話の録音済みオーディオのURLです。 このパラメーターはREST APIリクエストにRecorded=trueが設定されている場合にのみ追加され、 <Dial> または <Record> での録音には含まれません。
RecordingSid この通話に関連づけられた録音の一意なIDです。
RecordingDuration 録音された音声ファイルの長さ (秒) です。

データフォーマット

電話番号

可能な場合、Twilioからのリクエスト中のすべての電話番号はE.164形式となります。たとえば、「080-1234-5678」は「+818012345678」となります。しかし、まれにTwilioが着信時の発信者IDをE.164に変換できない場合があります。このような場合、Twilioは発信者IDの文字列をそのまま通知します。

日付と時間

Twilio空のリクエスト内のすべての日付と時刻にはRFC 2822形式のGMTが使用されます。 たとえば、日本時間で2010年8月20日の午前10時13分は、「Fri, 20 Aug 2010 01:13:42 +0000」として表されます。

Twilioにレスポンスを返す

Twilio電話番号のひとつでメッセージが受信されると、Twilioはその番号に対して構成されたメッセージURLにHTTPリクエストを発行します。このリクエストに対するレスポンスでは、通話で実行する内容をTwilioに指示できます。

Twilioはお行儀のよいHTTPクライアントです

URL へ HTTP リクエストを送信する際、Twilio は通常のウェブ ブラウザと同じように振る舞います。

  • Cookie: 通常のWebブラウザーと同様、TwilioはHTTP Cookieを受け入れ、これらを (Twilioからの) 各リクエストに追加します。
  • リダイレクト: こちらも通常のWebブラウザーと同様、HTTPリダイレクト (HTTPステータスコード301、307、など) に従います。
  • キャッシュ: こちらも通常のWebブラウザーと同様、HTTPヘッダーで許可されており (ETagおよびLast-Modifiedヘッダー) 、かつHTTPメソッドがGETである場合、Twilioはファイルのキャッシュを行います。

MIME Type に対応

Twilio はユーザー アプリケーションのレスポンスの MIME Type に応じて異なる動作をします。

MIME Type 動作
text/xml, application/xml, text/html Twilioは返されたドキュメントをXMLの命令セットとして解釈します (これをTwiMLと呼んでいます) 。これは最もよく使われるレスポンスです。
various audio types Twilio は発信者に向けて音声ファイルを再生し、通話を終了します。 サポートする MIME Type については、 <Play> のドキュメントを参照してください。
text/plain Twilio は発信者に向けてテキストの内容を読み上げ、通話を終了します。

TwilioのTwiMLインタープリターの仕組み

開発者のアプリケーションがTwilioからのリクエストにレスポンスを送信する際、TwilioはTwiMLインタープリターを使用して受信したドキュメントを実行します。物事が複雑化しないよう、TwiMLインタープリターは特別に名前の付けられた、わずかなXML要素のみを解釈します。

TwiMLの用語において、これらは3つのグループに分類されます。 ルートとなる<Response> 要素、「動詞」、そして「名詞」です。 これらのグループについて下記で説明していきます。

インタープリターは、ユーザーの TwiML 文書の先頭から開始し、上から順番に命令を実行 (動詞) します。 たとえば、次の TwiML のコードは、発信者に向けて「Hello World」とテキストを読み上げた後、Cowbell.mp3 を再生し、通話を終了します。

<?xml version="1.0" encoding="UTF-8" ?>  
<Response> 
    <Say>Hello World</Say>
    <Play>https://api.twilio.com/Cowbell.mp3</Play>
</Response>

TwiML要素である動詞、名詞は大文字小文字を区別します。たとえば、<Say>の代わりに<say>を使用するとエラーとなります。 属性名も大文字と小文字を区別し、また「camelCased(キャメルケース)」記法を使用します。 またXMLのコメントを自由に使用でき、インタープリターはこれを無視します。

<Response>要素

Twilioの XMLマークアップにおけるルート要素は<Response>要素です。 Twilioのリクエストに対するTwiMLレスポンスでは、すべての動詞はこの要素内に入れ子にされていることが必要です。 他のいかなる構造も無効とみなされます。

例:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Say>Hello</Say>
</Response>

TwiML 動詞

TwiMLドキュメントで最も使われるXMLエレメントはTwiML動詞です。 動詞名は大文字小文字を区別します、属性名も同様です。 Programmable Voiceの中心的なTwiML動詞は以下のとおりです:

  • <Say>: 発信者にテキストを読み上げます。
  • <Play>: 発信者に音声ファイルを再生します。
  • <Record>: 通話や通話の一部を録音します。
  • <Gather>: 発信者がダイヤルした数字を取得します。
  • <Dial>: 相手の電話番号またはカンファレンスに電話をかけ、発信者を接続します。

下記の動詞は制御フローに影響を与える可能性があります: <Gather><Record><Dial><Redirect><Hangup>、および<Reject>

制御フローが他のドキュメントに渡されるために、TwiMLドキュメントの一部の動詞に到達できない特定のケースがあります。 これは通常、動詞の「action」属性が設定されている場合に起こります。 たとえば、<Redirect>の直後に<Say>があり、もうひとつの<Say>が続く場合、<Redirect>が通話の完全な制御を異なるURLのTwiMLに転送するため、2番目の<Say>は到達不可能になります。

TwiML名詞

TwiMLの名詞は、動詞の内部に入れ子にされたもののことを指し、これには動詞自身は含まれません。 これは動詞の作用する対象を指します。 これは通常テキストです。 しかし場合によっては、<Dial>動詞内の<Conference>および<Conference>名詞のように、名詞となる入れ子にされたXML要素も存在します。

ステータスコールバック

ステータスコールバックは通話フローを制御しないため、TwiMLを返す必要はありません。 レスポンスを行う場合は、204 No Contentのステータスコードか、Content-Type: text/xmlと空の<Response/>をBodyに指定した200 OKを使用してください。 正しくレスポンスを返さないと、デバッガーで警告が発生します。

Twilioヘルパーライブラリーを使用したTwiMLの生成

Twilioでは、使い慣れたプログラミング言語でこうしたTwiMLを簡単に生成できるようにするヘルパーライブラリーを提供しています。

コードサンプルを読み込んでいます...
Language
SDKバージョン:
  • 5.x
SDKバージョン:
  • 7.x
SDKバージョン:
  • 3.x
SDKバージョン:
  • 5.x
SDKバージョン:
  • 6.x
SDKバージョン:
  • 5.x
形式:
  • TwiML
const VoiceResponse = require('twilio').twiml.VoiceResponse;

const response = new VoiceResponse();
response.say('Hello World');
response.play('https://api.twilio.com/Cowbell.mp3');

console.log(response.toString());
using Twilio.TwiML;
using System;

class Example
{
    static void Main()
    {
        var response = new VoiceResponse();
        response.Say("Hello World");
        response.Play(new Uri("https://api.twilio.com/Cowbell.mp3"));

        Console.WriteLine(response.ToString());;
    }
}
<?php
require_once './vendor/autoload.php';
use Twilio\Twiml;

$response = new Twiml();
$response->say('Hello World');
$response->play('https://api.twilio.com/Cowbell.mp3');

echo $response;
require 'twilio-ruby'

response = Twilio::TwiML::VoiceResponse.new
response.say('Hello World')
response.play(url: 'https://api.twilio.com/Cowbell.mp3')

puts response
from twilio.twiml.voice_response import Play, VoiceResponse, Say

response = VoiceResponse()
response.say('Hello World')
response.play('https://api.twilio.com/Cowbell.mp3')

print(response)
import com.twilio.twiml.voice.Play;
import com.twilio.twiml.VoiceResponse;
import com.twilio.twiml.voice.Say;
import com.twilio.twiml.TwiMLException;


public class Example {
    public static void main(String[] args) {
        Say say = new Say.Builder("Hello World").build();
        Play play = new Play.Builder("https://api.twilio.com/Cowbell.mp3")
            .build();
        VoiceResponse response = new VoiceResponse.Builder().say(say)
            .play(play).build();

        try {
            System.out.println(response.toXml());
        } catch (TwiMLException e) {
            e.printStackTrace();
        }
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<Response> 
    <Say>Hello World</Say>
    <Play>https://api.twilio.com/Cowbell.mp3</Play>
</Response>
音楽を伴うHello World
コードサンプルを読み込んでいます...
Language
SDKバージョン:
  • 5.x
SDKバージョン:
  • 7.x
SDKバージョン:
  • 3.x
SDKバージョン:
  • 5.x
SDKバージョン:
  • 6.x
SDKバージョン:
  • 5.x
形式:
  • TwiML
const VoiceResponse = require('twilio').twiml.VoiceResponse;

const response = new VoiceResponse();
response.say('Hello');

console.log(response.toString());
using Twilio.TwiML;
using System;


class Example
{
    static void Main()
    {
        var response = new VoiceResponse();
        response.Say("Hello");

        Console.WriteLine(response.ToString());;
    }
}
<?php
require_once './vendor/autoload.php';
use Twilio\Twiml;

$response = new Twiml();
$response->say('Hello');

echo $response;
require 'twilio-ruby'

response = Twilio::TwiML::VoiceResponse.new
response.say('Hello')

puts response
from twilio.twiml.voice_response import VoiceResponse, Say

response = VoiceResponse()
response.say('Hello')

print(response)
import com.twilio.twiml.VoiceResponse;
import com.twilio.twiml.voice.Say;
import com.twilio.twiml.TwiMLException;


public class Example {
    public static void main(String[] args) {
        Say say = new Say.Builder("Hello").build();
        VoiceResponse response = new VoiceResponse.Builder().say(say).build();

        try {
            System.out.println(response.toXml());
        } catch (TwiMLException e) {
            e.printStackTrace();
        }
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Say>Hello</Say>
</Response>
シンプルなHello

ヘルプが必要ですか?

誰しもが一度は考える「コーディングって難しい」。そんな時は、お問い合わせフォームから質問してください。 または、Stack Overflow でTwilioタグのついた情報から欲しいものを探してみましょう。

コードサンプルを読み込んでいます...
SDKバージョン:
  • 5.x
SDKバージョン:
  • 7.x
SDKバージョン:
  • 3.x
SDKバージョン:
  • 5.x
SDKバージョン:
  • 6.x
SDKバージョン:
  • 5.x
形式:
  • TwiML
const VoiceResponse = require('twilio').twiml.VoiceResponse;

const response = new VoiceResponse();
response.say('Hello World');
response.play('https://api.twilio.com/Cowbell.mp3');

console.log(response.toString());
using Twilio.TwiML;
using System;

class Example
{
    static void Main()
    {
        var response = new VoiceResponse();
        response.Say("Hello World");
        response.Play(new Uri("https://api.twilio.com/Cowbell.mp3"));

        Console.WriteLine(response.ToString());;
    }
}
<?php
require_once './vendor/autoload.php';
use Twilio\Twiml;

$response = new Twiml();
$response->say('Hello World');
$response->play('https://api.twilio.com/Cowbell.mp3');

echo $response;
require 'twilio-ruby'

response = Twilio::TwiML::VoiceResponse.new
response.say('Hello World')
response.play(url: 'https://api.twilio.com/Cowbell.mp3')

puts response
from twilio.twiml.voice_response import Play, VoiceResponse, Say

response = VoiceResponse()
response.say('Hello World')
response.play('https://api.twilio.com/Cowbell.mp3')

print(response)
import com.twilio.twiml.voice.Play;
import com.twilio.twiml.VoiceResponse;
import com.twilio.twiml.voice.Say;
import com.twilio.twiml.TwiMLException;


public class Example {
    public static void main(String[] args) {
        Say say = new Say.Builder("Hello World").build();
        Play play = new Play.Builder("https://api.twilio.com/Cowbell.mp3")
            .build();
        VoiceResponse response = new VoiceResponse.Builder().say(say)
            .play(play).build();

        try {
            System.out.println(response.toXml());
        } catch (TwiMLException e) {
            e.printStackTrace();
        }
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<Response> 
    <Say>Hello World</Say>
    <Play>https://api.twilio.com/Cowbell.mp3</Play>
</Response>
SDKバージョン:
  • 5.x
SDKバージョン:
  • 7.x
SDKバージョン:
  • 3.x
SDKバージョン:
  • 5.x
SDKバージョン:
  • 6.x
SDKバージョン:
  • 5.x
形式:
  • TwiML
const VoiceResponse = require('twilio').twiml.VoiceResponse;

const response = new VoiceResponse();
response.say('Hello');

console.log(response.toString());
using Twilio.TwiML;
using System;


class Example
{
    static void Main()
    {
        var response = new VoiceResponse();
        response.Say("Hello");

        Console.WriteLine(response.ToString());;
    }
}
<?php
require_once './vendor/autoload.php';
use Twilio\Twiml;

$response = new Twiml();
$response->say('Hello');

echo $response;
require 'twilio-ruby'

response = Twilio::TwiML::VoiceResponse.new
response.say('Hello')

puts response
from twilio.twiml.voice_response import VoiceResponse, Say

response = VoiceResponse()
response.say('Hello')

print(response)
import com.twilio.twiml.VoiceResponse;
import com.twilio.twiml.voice.Say;
import com.twilio.twiml.TwiMLException;


public class Example {
    public static void main(String[] args) {
        Say say = new Say.Builder("Hello").build();
        VoiceResponse response = new VoiceResponse.Builder().say(say).build();

        try {
            System.out.println(response.toXml());
        } catch (TwiMLException e) {
            e.printStackTrace();
        }
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Say>Hello</Say>
</Response>