TwiML(Twilio Markup Language)이란

TwiML(Twilio Markup Language)이란

전화가 걸려 오면 Twilio는 우리 앱에 '어떻게 응답할까'를 물어와요. 그 답을 Twilio가 이해할 수 있는 언어로 써주는 게 바로 TwiML이에요. TwiML은 Twilio가 정의한 XML 문서로, 통화 녹음·메시지 재생·키패드 입력 수집 같은 동작을 지시하는 특수 태그로 이뤄져 있어요. 코드라기보다는 통화 흐름의 설계도라고 보면 돼요.

출처: Twilio 공식 문서 — TwiML™ for Programmable Voice

TwiML이 어떻게 동작하나

전화가 걸려 오면 Twilio는 우선 해당 번호에 설정된 TwiML을 호스팅하는 URL을 요청해요. 그리고 그 TwiML 지시문을 읽어 통화를 녹음할지, 발신자에게 메시지를 재생할지, 키패드 숫자를 눌러 달라고 할지를 결정해요. 단순히 <Say> 하나만 있어도 그 문구를 읽어주는 식으로요. 발신 통화도 같은 방식으로 TwiML로 제어돼요. 실시간으로는 한 번에 하나의 TwiML 문서만 실행되지만, 여러 문서를 서로 연결해 복잡한 대화형 음성 앱을 만들 수 있어요.

누군가 Twilio 번호로 전화를 걸면 "Hello, world!"를 말하는 최소 예시는 이렇게 생겼어요.

<Response>
    <Say>Hello, world!</Say>
</Response>

TwiML 요소: 동사(Verb)와 명사(Noun)

TwiML 문서의 요소는 크게 두 종류로 나뉘어요.

  • 동사(Verb) — 주어진 통화에서 Twilio가 어떤 행동을 할지 지시하는 요소예요. 대부분의 TwiML 요소가 이에 속하고, 동사 이름과 속성 이름은 대소문자를 구분해요.
    • <Say> — 발신자에게 텍스트를 읽어줘요.
    • <Play> — 발신자에게 오디오 파일을 재생해요.
    • <Dial> — 통화에 다른 당사자를 추가해요.
    • <Record> — 발신자의 목소리를 녹음해요.
    • <Gather> — 발신자가 키패드로 입력하는 숫자를 수집해요.
    • <Hangup> — 통화를 끊어요.
    • <Enqueue> — 발신자를 대기열(큐)에 추가해요.
    • <Leave> — 발신자를 대기열에서 제거해요.
    • <Pause> — 다음 지시를 실행하기 전에 기다려요.
    • <Redirect> — 다른 TwiML 문서로 통화 흐름을 리다이렉트해요.
    • <Refer> — Twilio가 IP 통신 인프라 쪽으로 SIP REFER를 시작해요.
    • <Reject> — 과금 없이 들어오는 통화를 거절해요.
  • 명사(Noun) — 동사가 행동을 취할 대상, 즉 동사 안에 중첩되는 요소예요. <Dial> 안의 <Number>가 다른 전화번호에 연결하듯이, 명사는 동사가 작용하는 대상을 가리켜요.

웹훅 요청과 응답

전화가 오면 Twilio가 우리 애플리케이션으로 HTTP 요청을 보내고, 요청 파라미터에 통화 방향 정보가 들어와요. Direction 파라미터는 inbound(착신), outbound-api(REST API로 시작한 발신), outbound-dial(<Dial> 동사로 시작한 발신)을 구분해요.

통화가 끝나면 상태 콜백(StatusCallback)으로도 정보를 받을 수 있어요. 대표 파라미터는 다음과 같아요.

  • CallDuration — 방금 끝난 통화의 길이(초).
  • RecordingSid — 이 통화에서 만들어진 Recording의 고유 ID.
  • RecordingDuration — 녹음된 오디오 길이(초).

응답은 XML로 돌려주면 TwiML 인터프리터가 문서 맨 위에서부터 순서대로 동사(지시문)를 실행해요. 예를 들어 아래 코드는 "Hello World"를 읽어주고 나서 https://api.twilio.com/cowbell.mp3를 10번 반복 재생한 뒤 통화를 끊어요.

<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Play loop="10">https://api.twilio.com/cowbell.mp3</Play>
</Response>

주의할 점은, 어떤 동사의 action 속성이 설정되면 제어 흐름이 다른 문서로 넘어가서 그 뒤의 동사들이 실행되지 않을 수 있다는 거예요.

더 알아보기