- 技術 💻
Twilioとは|使い方・料金・日本のSMS規制とAPI・署名検証の実例
結論
Twilioは、SMS・電話・WhatsAppなどをAPIで送受信できるクラウドサービスです。読み方は「トゥイリオ」。料金は使った分だけのドル建てです。
この記事でわかること
- 製品10種と日本向けSMS・通話・番号の料金表
- Python・Node.js・curlで送ったリクエストの実物
- 署名検証3通りの一致とエラーコード15種の直し方
アプリは Twilio の REST API に「送って」と頼み、相手からの返信や着信は Twilio が Webhook でアプリに知らせます。この往復がTwilioの基本の形です。
flowchart TD
A[自分のアプリ<br>REST API で送信] --> B[Twilio]
B --> C[SMS・電話・WhatsApp<br>相手のスマホに届く]
C --> D[相手が返信・着信]
D --> E[Twilio が受ける]
E --> F[Webhook でアプリへ<br>TwiML で応答]
急いでいる人向けに、よく調べられることの答えを先にまとめます。
| 知りたいこと | 答え | 詳しい節 |
|---|---|---|
| 何ができる? | SMS・音声通話・WhatsApp・認証コード・メール | できること |
| 料金は? | 従量課金・ドル建て。日本宛 SMS は1セグメント 0.089ドル | 料金 |
| 無料で使える? | トライアルで SMS 100通・通話 75分など。30日間 | トライアル |
| 日本の番号で SMS は? | 送れない。米国番号か英数字の送信者 ID を使う | 日本で使う注意 |
| 050番号は取れる? | 取れる(音声用)。法人の書類が要る | 日本で使う注意 |
| API の認証は? | HTTP Basic。API キーか Account SID+Auth Token | API の呼び方 |
| Webhook の検証は? | X-Twilio-Signature を SDK で検証 | 署名の検証 |
| 21608 が出た | トライアルで未認証の番号に送った | エラーコード |
確認環境:製品・料金・トライアル・日本の規制は Twilio の公式サイト(料金ページ、Japan SMS・Voice・Regulatory の各ガイドライン)と公式ドキュメント(docs.twilio.com)、ソフトバンクの Twilio 解説記事、総務省の特定電子メール法のパンフレットで確かめました。API の呼び方は、Ubuntu 24.04・Python 3.11.15 に公式 SDK の twilio 9.12.0(PyPI の最新)、Node.js 22.22.2 に twilio 6.2.0(npm の最新)を入れ、Twilio の REST API と同じパス・エラーの形を返す擬似サーバー(127.0.0.1:35400)を Python で作って、SDK と curl 8.5.0 から送ったリクエスト(URL・ヘッダー・本文)と戻り値・例外を記録しました。Webhook の署名は OpenSSL 3.0.13 で手計算し、Flask 3 のアプリ(127.0.0.1:35401)と両 SDK の検証関数で照合しています。実際の配信・音声の聞こえ方は公式ドキュメントの記述に基づきます(確認日 2026年10月23日)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Twilioとは|使い方・料金・日本のSMS規制とAPI・署名検証の実例」
Twilioとは(読み方・運営会社)
この節では、Twilio がどんなサービスで、日本ではどう契約できるかが分かります。
Twilio(トゥイリオ)は、電話・SMS・チャット・メールなどの「連絡の手段」を、プログラムから使える API として提供するクラウドサービスです。 電話会社と自分で契約したり、交換機を置いたりしなくても、数行のコードで SMS を送ったり、電話をかけたり、かかってきた電話に自動で応答したりできます。このような形のサービスは CPaaS(Communications Platform as a Service)と呼ばれます。
1運営会社
米国の Twilio Inc.。2008年創業、本社はサンフランシスコ。ニューヨーク証券取引所に上場(TWLO)
2日本での提供
2019年に日本法人 Twilio Japan 合同会社を設立。2023年10月からソフトバンクが販売代理店として提供
3料金の形
使った分だけの従量課金。表示はドル建て。月額の基本料はなく、電話番号は月ごとの料金
読み方は、ソフトバンクのサービスページなどで「トゥイリオ」と書かれています。メール配信の SendGrid は 2019年に、顧客データ基盤の Segment は 2020年に Twilio の一部になりました。ソフトバンク経由の契約では、日本語のサポートと日本の固定電話番号(0AB-J)の申し込みを受けられます(2023年10月16日の発表)。
Twilioでできること(製品の早見表)
この節では、Twilio の主な製品と、それぞれで何が作れるかが分かります。
よく使われるのは、SMS(Programmable Messaging)・音声(Programmable Voice)・WhatsApp・Verify(本人確認)・SendGrid(メール)の5つです。 公式の料金ページ(日本語版)に載っている製品から、開発者がよく使うものを抜き出しました。
| 製品 | できること | 使われる例 |
|---|---|---|
| Programmable Messaging(SMS) | SMS・MMS の送受信 | 予約の通知・配送の連絡 |
| Programmable Voice | 電話の発信・着信・録音・自動音声 | IVR(番号を押して振り分け)・自動架電 |
| WhatsApp Business API | WhatsApp でメッセージを送受信 | 海外の顧客へのサポート |
| RCS | 画像やボタン付きのメッセージ | SMS の代わりのリッチな通知 |
| Verify | SMS・電話・メール等で認証コードを送り、照合 | 二段階認証・電話番号の確認 |
| Lookup | 電話番号の形式・種類を調べる | 入力された番号の確認 |
| SendGrid Email API | メールの送信 | 会員登録・パスワード再設定のメール |
| Studio | 画面で流れを組み立てる(ノーコード) | 簡単な IVR・SMS の自動応答 |
| Flex | コールセンターのシステム | 電話・チャットの窓口 |
| Conversation Relay | 音声通話と AI(LLM)をつなぐ | AI の電話応答 |
このほか、ビデオ通話の Video、サーバーレスの Functions、通話の振り分けの TaskRouter、SIP の Elastic SIP Trunking などがあります。どの製品も、API を呼ぶ側の書き方(認証・REST・Webhook)は共通です。
Twilioの料金(2026年10月23日時点)
この節では、日本で使うときにかかる SMS・通話・電話番号・Verify などの料金が分かります。
料金はすべて従量課金で、ドル建て・税別です。 SMS は「セグメント」(短い区切り)ごと、通話は分ごと、電話番号は月ごとにかかります。以下は Twilio の料金ページ(日本向け SMS・日本向け Voice・WhatsApp・Verify)に 2026年10月23日に表示されていた値です。
SMS(日本宛て)
| 送信元の種類 | 送信(1セグメント) | 受信 |
|---|---|---|
| 英数字の送信者 ID(Alphanumeric) | 0.089ドル | 受信できない |
| ロングコード(米国などの電話番号) | 0.0890ドル | 記載なし |
| ショートコード | 0.0800ドル | 0.0800ドル |
| 追加の料金 | 金額 | 条件 |
|---|---|---|
| 失敗したメッセージの処理料 | 1通 0.001ドル | 最終の状態が failed のときだけ |
| SMS pumping protection | 1通 0.025ドル | 不正な大量送信の対策を使うとき |
| Engagement Suite(短縮 URL・予約送信) | 1通 0.015ドル | 毎月 1,000通までは無料 |
| 送信元に使う米国などの番号 | 月 1.15ドル〜 | 番号の国と種類で変わる |
日本語の SMS は1セグメントが70文字までで、超えると67文字ずつに分かれ、分かれた数だけ料金がかかります(セグメントの節に計算の実物)。携帯電話会社の手数料(carrier fees)が別にかかる場合があると料金ページに書かれています。
音声通話と日本の電話番号
| 項目 | 料金 | 備考 |
|---|---|---|
| 050番号(National) | 月 4.75ドル | 着信 1分 0.0100ドル |
| 固定電話番号(0AB-J) | 月 20.00ドル | 地域の住所が要る |
| フリーダイヤル(0120・0800) | 月 25.00ドル | 着信 1分 0.1854ドル |
| 日本の固定電話へ発信 | 1分 0.0746ドル | 東京・VoIP 宛も同じ |
| 日本の携帯電話へ発信 | 1分 0.1850ドル | ― |
| アプリ・ブラウザとの通話 | 1分 0.0040ドル | 発信・着信とも |
そのほかの製品
| 製品 | 料金 | 備考 |
|---|---|---|
| Verify | 成功1件 0.05ドル+送信料 | 失敗・期限切れは 0.05ドルがかからない |
| 1通 0.005ドル(Twilio)+Meta の料金 | Meta の料金は種類と国で変わる | |
| SendGrid Email API | 月 19.95ドル〜 | 1日100通の無料トライアル |
| Twilio Email | 1通 0.0013ドル〜 | ― |
| Studio | 実行1回 0.0025ドル〜 | ― |
| Functions | 月 10,000回まで無料 | 以降 1回 0.0001ドル |
Verify は、コードが照合されて成功したときに 0.05ドルがかかり、SMS や電話の送信料は成功しなくても送るたびにかかります(Verify の料金ページ)。量が多い場合は、営業窓口で量に応じた割引(committed-use discounts)を相談できると、どの料金ページにも書かれています。
無料トライアルでできること・制限
この節では、お金を払う前に何を試せるかと、トライアルの制限が分かります。
トライアルは、SMS 100通・WhatsApp 100通・メール 3,000通・音声 75分の無料分つきで、登録から30日で終わります。 以前のような共通のドル残高ではなく、製品ごとの無料分になっています(公式「How to use your free trial account」)。
トライアルでできること
Twilio の番号から SMS・電話を試す
Webhook・TwiML の動きを確かめる
クレジットカードなしで始める
トライアルの制限
送れる相手は認証した番号だけ(最大5件)
SMS と通話は登録した国の中だけ
自由に書いた本文(カスタム本文)は使えない
公式ページは、トライアル中は「カスタムのメッセージ本文、メールの内容、WhatsApp のテンプレートは使えない」と書いています。未認証の番号に送ると、エラー 21608(Upgrade and create an approved primary compliance profile to reach unverified numbers)になります。コンソールの「Upgrade your account」から、プロフィールと住所を登録し、残高を入れ、支払い方法を登録すると有料の状態になります。
Twilioの使い方(アカウント作成から最初の送信まで)
この節では、アカウントを作ってから API で最初のメッセージを送るまでの流れが分かります。
アカウントを作る
twilio.com でサインアップし、メールと電話番号を確かめます。登録した電話番号の国が、トライアルで SMS・通話できる国になります。
Account SID と認証情報を控える
コンソールのトップに Account SID(AC で始まる34文字)と Auth Token があります。本番では API キー(SK で始まる)を作って使う形が推奨されています。
電話番号を取る
Phone Numbers から番号を買います。日本宛ての SMS には、日本の番号ではなく SMS が使える米国などの番号を使います(次の節)。
送り先の国を許可する
Messaging の Geographic Permissions(送信できる国の設定)で日本を有効にします。無効の国へ送るとエラー 21408 になります。
SDK を入れて送る
Python なら pip install twilio、Node.js なら npm install twilio。messages.create に宛先・送信元・本文を渡します。
Webhook の URL を登録する
番号の設定画面で「A message comes in」「A call comes in」に自分のアプリの URL を入れると、返信や着信がその URL に届きます。
開発中のパソコンで Webhook を受けるには、外から届く URL が要ります。関連記事「ngrokとは|使い方・料金・Webhook受信とエラーの直し方」で扱っています。Twilio は自己署名の証明書の HTTPS には接続しないと公式に書かれています。
日本で使うときの注意(SMSの送信元・電話番号・規制)
この節では、日本宛ての SMS の送信元の選び方、日本の電話番号の取り方、守るべき決まりが分かります。
Twilio で買った日本の電話番号(050・0AB-J・0120・0800)は、SMS の送信元に使えません。 日本の番号は音声通話用です(ソフトバンクの解説記事「Twilioから購入した日本の電話番号はSMSの送信元に利用できません。」)。日本宛ての SMS は、Twilio の Japan SMS ガイドラインで「Supported」とされている次の2つから送ります。
返信を受けたいなら電話番号、名前を見せたいなら英数字の送信者 ID
Japan SMS ガイドライン(2026年10月23日時点)の送信元の対応表です。
| 送信元の種類 | Twilio の対応 | 備考 |
|---|---|---|
| 英数字・動的(登録なし) | 対応 | 送信者 ID は保たれる |
| 海外のロングコード | 対応 | 返信(双方向)に対応 |
| 英数字・国内の事前登録 | 国内ゲートウェイ経由のみ | 営業に連絡。準備に約5週間 |
| 英数字・国際の事前登録 | 非対応 | ― |
| 国内のロングコード | 非対応 | 日本の番号からは送れない |
| ショートコード | 非対応 | ― |
国内のゲートウェイ(日本の携帯電話会社に直接つながる経路)を使うには登録が必須で、営業窓口に申し込みます。ソフトバンクの記事も、日本の送信元を使いたい場合は別のオプションの国内 SMS サービスを案内しています。KDDI 宛てに5セグメントを超える SMS は、KDDI 側の制限で遅れることがあるとガイドラインに書かれています。固定電話の番号には SMS を送れず、API は 400 とエラー 21614 を返し、料金はかかりません。
日本の電話番号(050・0AB-J・0120)の取り方
日本の電話番号は法人だけが取れ、規制のための書類(Regulatory Bundle)の審査が要ります。 Twilio の Japan Regulatory ガイドラインに書かれている、0AB-J(03・06 など)の番号で求められる書類です。
| 求められるもの | 書類の例 |
|---|---|
| 申込書 | Japan Regulatory Bundle Application(代表者が署名) |
| 会社の存在と目的 | 履歴事項全部証明書(6か月以内に発行) |
| 会社の住所 | 登記簿、または納税証明書・公共料金の請求書 |
| 代表者の権限 | 委任状・登記簿・社判のある書面 |
| 代表者の本人確認 | 運転免許証・マイナンバーカード(表面)・在留カードなど |
0AB-J の番号は、番号の市外局番の地域にある住所が要り、私書箱は使えず、住所は日本語で書きます。050 とフリーダイヤルは日本国内の住所であればよく、地域の制限はありません。ソフトバンクの記事によると、050 と 0800 はコンソールで買え、0120 は番号の枯渇でコンソールから買うのが難しく、0AB-J はソフトバンクの営業担当経由で申し込みます。
日本の番号から日本の番号へ電話をかけるときは、国際回線を通らないよう「Tokyo」エッジを使うよう Japan Voice ガイドラインに書かれています。Twilio からは緊急通報(110・119 など)はできず、+81180・+81990 などの一部の番号への発信はブロックされます。
日本で SMS を送るときに確かめること
- 1広告の SMS は相手の同意を得て、記録を残したか特定電子メール法は SMS も対象。原則、事前に同意した相手にだけ広告を送れ、同意の記録の保存が要る(総務省)
- 2送信者の名前と、受信を拒否する方法を書いたか特定電子メール法の表示義務。Twilio のガイドラインも日本語での停止の受付を勧めている
- 3禁止された内容が含まれていないかガイドラインは、金融・貸付、ギャンブル、成人向け、政治、宗教、酒類などの内容と、本文中の電話番号を禁止としている
- 4送る時間帯は相手の昼間か急ぎでない限り、受け取る人の昼間に送るよう Twilio のガイドラインが勧めている
- 5宛先は携帯電話の番号か固定電話には届かない(21614)。日本の携帯は主に +8170・+8180・+8190 で始まる
本文に電話番号を書けない、という制限に注意します。 「お問い合わせは 03-xxxx-xxxx へ」のような本文は、ガイドラインの禁止内容に当たります。電話番号の形を入力時に確かめる方法は、関連記事「電話番号の正規表現とチェック|携帯・固定・060・フリーダイヤル」で扱っています。
Twilio APIの呼び方(認証・curl・Python・Node.js)
この節では、認証のしかたと、SMS を送る API を curl・Python・Node.js から呼ぶ書き方が、実際に送られた中身つきで分かります。
Twilio の REST API は、HTTP Basic 認証とフォーム形式(application/x-www-form-urlencoded)の本文で呼びます。 SMS の送信は次の1本です(公式「Message resource」)。
POST https://api.twilio.com/2010-04-01/Accounts/{AccountSid}/Messages.json
| 本文の項目 | 中身 | 例 |
|---|---|---|
To |
宛先(E.164 形式) | +819012345678・whatsapp:+819012345678 |
From |
送信元(自分の番号・英数字 ID) | +15017122661・RJC |
MessagingServiceSid |
From の代わりに Messaging Service を指定 |
MG… |
Body |
本文(最大1,600文字) | ご予約は… |
StatusCallback |
配信状態を知らせてもらう URL | https://…/status |
ValidityPeriod |
送れなかったときに待つ秒数(1〜36000、既定36000) | 600 |
SendAt・ScheduleType |
予約送信(Messaging Service のみ) | fixed |
認証:Auth Token と API キー
| 認証のしかた | ユーザー名 | パスワード |
|---|---|---|
| API キー(推奨) | API キーの SID(SK…) | API キーのシークレット |
| アカウントの認証情報 | Account SID(AC…) | Auth Token |
公式は API キーを「推奨の認証方法」とし、用途や人ごとに別のキーを作り、使える範囲を絞った Restricted キーを使い、環境変数に置くよう書いています。Auth Token は Webhook の署名の鍵にも使われるので、漏れたら作り直します。キーの置き方は、関連記事「.envの使い方と注意点|APIキーを安全に管理する方法」で扱っています。
curl で SMS を送る
export TWILIO_ACCOUNT_SID="AC…" # コンソールの Account SID
export TWILIO_AUTH_TOKEN="…" # コンソールの Auth Token
curl -X POST "https://api.twilio.com/2010-04-01/Accounts/$TWILIO_ACCOUNT_SID/Messages.json" \
--data-urlencode "To=+819012345678" \
--data-urlencode "From=+15017122661" \
--data-urlencode "Body=【RJC】ご予約は10月24日 15:00です。" \
-u "$TWILIO_ACCOUNT_SID:$TWILIO_AUTH_TOKEN"
ホストの部分を擬似サーバーに変えて実行し、擬似サーバーが受け取った中身と、返した応答です(Authorization の中身は伏せています)。
--> POST https://api.twilio.com/2010-04-01/Accounts/AC0123456789abcdef0123456789abcdef/Messages.json
Authorization: Basic (AC0123… : シークレット)
Content-Type: application/x-www-form-urlencoded
User-Agent: curl/8.5.0
body: To=%2B819012345678&From=%2B15017122661&Body=%E3%80%90RJC%E3%80%91%E3%81%94%E4%BA%88%E7%B4%84%E3%81%AF10%E6%9C%8824%E6%97%A5+15%3A00%E3%81%A7%E3%81%99%E3%80%82
{"sid": "SM5c11c17558c99bc61817ec072e8b6837", "account_sid": "AC0123456789abcdef0123456789abcdef", "from": "+15017122661", "to": "+819012345678", "body": "【RJC】ご予約は10月24日 15:00です。", "status": "queued", "num_segments": "1", "direction": "outbound-api", "price": null, "price_unit": "USD", "error_code": null, "api_version": "2010-04-01"}
成功すると HTTP 201 で、sid(SM で始まる ID)と status: queued が返ります。応答の項目名は公式のサンプルと同じにしてあります。queued は「受け付けた」という意味で、届いたという意味ではありません。 届いたかどうかは、後の StatusCallback か、GET …/Messages/{sid}.json で status を見ます。
--data-urlencode を使わずに -d "To=+819012345678" と書くと、+ が空白として送られます。 擬似サーバーで受けた中身と応答です。
--> POST …/Messages.json
body: To=+819012345678
{"code": 21211, "message": "Invalid 'To' Phone Number: 819012345678", "more_info": "https://www.twilio.com/docs/errors/21211", "status": 400}
フォーム形式では + は空白の意味なので、受け取った側には「 819012345678」と見えます。日本語の本文も同じ理由で、curl では --data-urlencode を使います。
Python で SMS を送る
pip install twilio
import os
from twilio.rest import Client
client = Client(os.environ["TWILIO_ACCOUNT_SID"], os.environ["TWILIO_AUTH_TOKEN"])
message = client.messages.create(
to="+819012345678",
from_="+15017122661", # from は Python の予約語なので from_
body="【RJC】ご予約は10月24日 15:00です。",
status_callback="https://example.com/status",
)
print(message.sid, message.status, message.num_segments)
擬似サーバーに向けるため、SDK の HTTP クライアント(TwilioHttpClient)を受け継いだクラスで、SDK が組み立てた URL を表示してから宛先のホストだけを差し替えて実行しました(Client(..., http_client=…) で渡せます)。status_callback は、手元の Flask のアプリ(127.0.0.1:35401)にしています。
[SDK] POST https://api.twilio.com/2010-04-01/Accounts/AC0123456789abcdef0123456789abcdef/Messages.json
SM0eec4e77015829f381b2ca6ac63de497 queued 1
擬似サーバーが受け取った中身です。
--> POST https://api.twilio.com/2010-04-01/Accounts/AC0123456789abcdef0123456789abcdef/Messages.json
Authorization: Basic (AC0123… : シークレット)
Content-Type: application/x-www-form-urlencoded
User-Agent: twilio-python/9.12.0 (Linux x86_64) Python/3.11.15
X-Twilio-Client: python-9.12.0
Accept: application/json
Accept-Charset: utf-8
body: To=%2B819012345678&StatusCallback=http%3A%2F%2F127.0.0.1%3A35401%2Fstatus&From=%2B15017122661&Body=%E3%80%90RJC%E3%80%91%E3%81%94%E4%BA%88%E7%B4%84%E3%81%AF10%E6%9C%8824%E6%97%A5+15%3A00%E3%81%A7%E3%81%99%E3%80%82
読み取れることは次の3つです。
- Python の引数
to・from_・status_callbackは、送るときにTo・From・StatusCallbackという先頭が大文字の名前に変わる。 - 本文は JSON ではなくフォーム形式。日本語は UTF-8 のバイトを %XX で表した形になる。
- SDK は
User-Agentに SDK と Python の版を入れる。問い合わせのときにどの版から送ったかが分かる。
API キーで認証するときは、Client("SK…", "シークレット", "AC…") のように3つ目に Account SID を渡します。擬似サーバーでは、Basic 認証のユーザー名が SKfedc… になり、URL のパスには Account SID(AC…)が入ったままでした。
Client(..., edge="tokyo", region="us1") のようにエッジ(Twilio のネットワークへの入口)を指定すると、SDK が組み立てる URL のホストが変わりました。
[SDK] POST https://api.tokyo.us1.twilio.com/2010-04-01/Accounts/AC0123456789abcdef0123456789abcdef/Messages.json
Node.js で SMS を送る
npm install twilio
const twilio = require("twilio");
const client = twilio(process.env.TWILIO_ACCOUNT_SID, process.env.TWILIO_AUTH_TOKEN);
async function main() {
const message = await client.messages.create({
to: "+819012345678",
from: "+15017122661",
body: "【RJC】ご予約は10月24日 15:00です。",
});
console.log(message.sid, message.status, message.numSegments);
try {
await client.messages.create({ to: "09012345678", from: "+15017122661", body: "テスト" });
} catch (e) {
console.log(e.constructor.name, e.status, e.code, e.message, e.moreInfo);
}
}
main();
twilio.RequestClient を受け継いだクラスを httpClient オプションで渡し、擬似サーバーに向けて実行しました。
[SDK] POST https://api.twilio.com/2010-04-01/Accounts/AC0123456789abcdef0123456789abcdef/Messages.json
SMa1c5b1993882231bb8b64b800d1fbaa9 queued 1
[SDK] POST https://api.twilio.com/2010-04-01/Accounts/AC0123456789abcdef0123456789abcdef/Messages.json
RestException 400 21211 Invalid 'To' Phone Number: 09012345678 https://www.twilio.com/docs/errors/21211
--> POST https://api.twilio.com/2010-04-01/Accounts/AC0123456789abcdef0123456789abcdef/Messages.json
Authorization: Basic (AC0123… : シークレット)
Content-Type: application/x-www-form-urlencoded
User-Agent: twilio-node/6.2.0 (linux x64) node/v22.22.2
body: To=%2B819012345678&From=%2B15017122661&Body=%E3%80%90RJC%E3%80%91%E3%81%94%E4%BA%88%E7%B4%84%E3%81%AF10%E6%9C%8824%E6%97%A5%2015%3A00%E3%81%A7%E3%81%99%E3%80%82
Node.js の SDK は応答の項目名を numSegments のようなキャメルケースに変えて返します。本文の空白は Python と curl が +、Node.js が %20 で送っていましたが、どちらもフォーム形式では同じ空白です。09012345678 のように国番号の無い番号は、エラー 21211 になります。日本の番号は先頭の 0 を取って +81 を付けます(090-1234-5678 → +819012345678)。
送ったSMSが届いたか確かめる(StatusCallback)
StatusCallback に URL を入れておくと、状態が変わるたびに Twilio がその URL に POST します。 本文には MessageSid・MessageStatus、失敗したときは ErrorCode が入ります(公式「Track the message status」)。擬似サーバーから、自分の Flask アプリ(127.0.0.1:35401)に状態を送り、アプリ側で受けた記録です。
status SM0eec4e77015829f381b2ca6ac63de497 sent -
status SM0eec4e77015829f381b2ca6ac63de497 delivered -
status SMed9e918d4dbfdbebaa84b32fa3e78246 sent -
status SMed9e918d4dbfdbebaa84b32fa3e78246 undelivered 30003
主な状態は queued(受付)→ sending → sent(携帯電話会社に渡した)→ delivered(届いた)で、届かなければ undelivered、送れなければ failed になります。状態の通知は送った順に届くとは限らないと公式に書かれているので、受け取る側は「後から来た通知で状態を戻さない」ように作ります。Webhook の再送と重複の扱いは、関連記事「Webhookとは?実装までわかる|署名検証・リトライ・冪等性を実行ログで解説」で扱っています。
日本語のSMSは何通分になる?(セグメントの計算)
日本語を1文字でも含むと UCS-2 という形になり、1セグメントは70文字まで、それを超えると67文字ずつに分かれます。 英数字だけ(GSM-7)なら160文字、超えると153文字ずつです(公式「What is the SMS character limit?」)。公式の表どおりに数える関数を書いて実行しました。
GSM7 = set("@£$¥èéùìòÇ\nØø\rÅåΔ_ΦΓΛΩΠΨΣΘΞÆæßÉ !\"#¤%&'()*+,-./0123456789:;<=>?¡"
"ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÑܧ¿abcdefghijklmnopqrstuvwxyzäöñüà")
GSM7_EXT = set("^{}\\[~]|€") # GSM-7 の拡張文字は2文字ぶん数える
def estimate_segments(body: str):
if all(c in GSM7 or c in GSM7_EXT for c in body):
units = sum(2 if c in GSM7_EXT else 1 for c in body)
single, multi, enc = 160, 153, "GSM-7"
else:
units = len(body.encode("utf-16-le")) // 2 # 絵文字は2単位
single, multi, enc = 70, 67, "UCS-2"
seg = 1 if units <= single else -(-units // multi)
return enc, units, seg
for body in ["Your code is 123456", "認証コードは123456です。有効期限は10分です。",
"A" * 160, "A" * 161, "あ" * 70, "あ" * 71, "あ" * 134, "あ" * 135,
"Hello 😀", "Price: 100€"]:
enc, units, seg = estimate_segments(body)
label = body if len(body) <= 24 else body[:6] + f"…({len(body)}文字)"
print(f"{enc:<5} {units:>4}単位 → {seg}セグメント | {label}")
GSM-7 19単位 → 1セグメント | Your code is 123456
UCS-2 26単位 → 1セグメント | 認証コードは…(26文字)
GSM-7 160単位 → 1セグメント | AAAAAA…(160文字)
GSM-7 161単位 → 2セグメント | AAAAAA…(161文字)
UCS-2 70単位 → 1セグメント | ああああああ…(70文字)
UCS-2 71単位 → 2セグメント | ああああああ…(71文字)
UCS-2 134単位 → 2セグメント | ああああああ…(134文字)
UCS-2 135単位 → 3セグメント | ああああああ…(135文字)
UCS-2 8単位 → 1セグメント | Hello 😀
GSM-7 12単位 → 1セグメント | Price: 100€
日本語は71文字で2セグメント、135文字で3セグメントになり、料金も2倍・3倍になります。 絵文字は1つで2単位を使い、英語の文に1つ入るだけで全体が UCS-2 になります。実際のセグメント数は、送信後の応答の num_segments で確かめられます。公式は、届きやすさのために SMS は320文字未満を勧め、UCS-2 で分割して送れる上限を700文字としています。
Webhookの受け方と署名の検証(X-Twilio-Signature)
この節では、Twilio から届いたリクエストが本物かを確かめる仕組みを、手で計算した値と SDK の結果を並べて理解できます。
Twilio は Webhook のリクエストに、Auth Token を鍵にした HMAC-SHA1 の署名を X-Twilio-Signature ヘッダーで付けます。 受け取ったアプリは同じ計算をして、値が一致したときだけ処理します。一致しなければ、第三者が Twilio のふりをして送ったリクエストかもしれません。
flowchart TD
A[Twilio に登録した URL] --> B[URL の後ろに<br>パラメーターを名前順につなぐ]
B --> C[Auth Token を鍵に<br>HMAC-SHA1]
C --> D[Base64 にする]
D --> E{X-Twilio-Signature<br>と一致する?}
E -->|一致| F[処理して応答]
署名を手で計算する
Twilio に登録した URL をそのまま取る
クエリ文字列も含めた、Twilio がアクセスした URL です。URL をデコードしたり、組み立て直したりすると一致しません。
POST のパラメーターを名前の昇順に並べてつなぐ
「名前+値」を区切り文字なしで URL の後ろに足します。値は URL エンコード前の文字(日本語ならそのまま)です。
Auth Token を鍵に HMAC-SHA1 をとる
API キーのシークレットではなく、アカウントの Auth Token が鍵です。
Base64 にして比べる
結果の20バイトを Base64 にした28文字が、ヘッダーの値と一致すれば本物です。
SMS を受けたときに Twilio が送る形のパラメーターで、シェルと OpenSSL で計算しました。
TOKEN="test_auth_token_0123456789abcdef"
URL="http://127.0.0.1:35401/sms"
S="${URL}AccountSid${TWILIO_ACCOUNT_SID}Body予約を確認したいFrom+819012345678MessageSidSM11111111111111111111111111111111To+15017122661"
echo "署名する文字列: $S"
SIG=$(printf '%s' "$S" | openssl dgst -sha1 -hmac "$TOKEN" -binary | base64)
echo "X-Twilio-Signature: $SIG"
署名する文字列: http://127.0.0.1:35401/smsAccountSidAC0123456789abcdef0123456789abcdefBody予約を確認したいFrom+819012345678MessageSidSM11111111111111111111111111111111To+15017122661
X-Twilio-Signature: 7pEIRAmo9tdeE0HyeYTXIn1rOk8=
同じ値を、Python の RequestValidator と Node.js の getExpectedTwilioSignature でも計算しました(結果の上2行が Python、下2行が Node.js)。
from twilio.request_validator import RequestValidator
v = RequestValidator("test_auth_token_0123456789abcdef")
params = {"AccountSid": "AC0123456789abcdef0123456789abcdef", "Body": "予約を確認したい", "From": "+819012345678",
"MessageSid": "SM11111111111111111111111111111111", "To": "+15017122661"}
print("compute_signature:", v.compute_signature("http://127.0.0.1:35401/sms", params))
print("validate:", v.validate("http://127.0.0.1:35401/sms", params, "7pEIRAmo9tdeE0HyeYTXIn1rOk8="))
compute_signature: 7pEIRAmo9tdeE0HyeYTXIn1rOk8=
validate: True
getExpectedTwilioSignature: 7pEIRAmo9tdeE0HyeYTXIn1rOk8=
validateRequest: true
OpenSSL の手計算・Python SDK・Node.js SDK の3つが同じ 7pEIRAmo9tdeE0HyeYTXIn1rOk8= になりました。 仕組みを確かめるために手で計算しましたが、公式は「署名の検証を自分で実装しない」で SDK の関数を使うよう書いています。SDK 9.12.0 のソースでは、比較に時間が一定になる関数を使い、URL にポート番号(:443・:80)を付けた形と外した形の両方で照合していました。
Flask で署名を検証して自動返信する
import os
from functools import wraps
from flask import Flask, request, abort
from twilio.request_validator import RequestValidator
from twilio.twiml.messaging_response import MessagingResponse
app = Flask(__name__)
validator = RequestValidator(os.environ["TWILIO_AUTH_TOKEN"])
PUBLIC_BASE = os.environ.get("PUBLIC_BASE") # 例 https://example.ngrok.app(プロキシの内側で動かすとき)
def twilio_only(f):
@wraps(f)
def wrapper(*args, **kwargs):
url = request.url
if PUBLIC_BASE: # Twilio に登録した「外から見た URL」で検証する
url = PUBLIC_BASE + request.full_path.rstrip("?")
if not validator.validate(url, request.form, request.headers.get("X-Twilio-Signature", "")):
abort(403)
return f(*args, **kwargs)
return wrapper
@app.post("/sms")
@twilio_only
def sms():
resp = MessagingResponse()
resp.message(f"受け付けました:{request.form.get('Body', '')}")
return str(resp), 200, {"Content-Type": "text/xml"}
@app.post("/status")
@twilio_only
def status():
print("status", request.form["MessageSid"], request.form["MessageStatus"], request.form.get("ErrorCode", "-"))
return "", 204
計算した署名を付けて curl で送ったときと、本文だけ書き換えて同じ署名で送ったときの結果です。
## 正しい署名
<?xml version="1.0" encoding="UTF-8"?><Response><Message>受け付けました:予約を確認したい</Message></Response> → HTTP 200
## 本文を書き換え
→ HTTP 403
本文を「予約を取り消したい」に1か所変えただけで、署名が合わずに 403 になりました。Flask の使い方は、関連記事「Flask入門|最小APIとBlueprint・テストの完成コード」で扱っています。
本番で検証が失敗するとき(プロキシと URL の違い)
よくある失敗は、アプリが見ている URL と、Twilio に登録した URL が違うことです。 ngrok やロードバランサーの内側では、Twilio は https://example.ngrok.app/sms に送りますが、アプリには http://127.0.0.1:35401/sms として届きます。登録した URL で署名した同じリクエストを、2つのアプリに送りました。
35401 は PUBLIC_BASE なし、35402 は PUBLIC_BASE=https://example.ngrok.app で起動したアプリです。curl の結果と、それぞれのアプリのログです。
http://127.0.0.1:35401/sms → HTTP 403
http://127.0.0.1:35402/sms → HTTP 200
validate url=http://127.0.0.1:35401/sms sig=BvCFxCOyjfca0LE0Io3wiUVMNM4= → False
validate url=https://example.ngrok.app/sms sig=BvCFxCOyjfca0LE0Io3wiUVMNM4= → True
RequestValidator.validate で URL の違いごとに試した結果です(Twilio に登録した URL は https://example.ngrok.app/sms)。
| 検証に使った URL | 結果 |
|---|---|
https://example.ngrok.app:443/sms(ポート番号つき) |
True |
http://example.ngrok.app/sms(http と https の違い) |
False |
https://example.ngrok.app/sms/(末尾のスラッシュ) |
False |
http://127.0.0.1:35401/sms(内側の URL) |
False |
ポート番号の有無は SDK が吸収しますが、http と https・末尾のスラッシュ・ホスト名の違いは失敗します。 外から見た URL を設定で持つか、プロキシが付ける X-Forwarded-Proto・X-Forwarded-Host から組み立てます。
JSON で届く Webhook(bodySHA256)
本文が JSON の Webhook では、Twilio は URL に bodySHA256(本文の SHA-256)を付け、本文そのものは署名の計算に入れません。SDK には生の本文を文字列のまま渡します(Python は validate(url, 本文の文字列, 署名)、Node.js は validateRequestWithBody)。小さな JSON で試した結果です(上4行が Python、最後の行が Node.js)。
bodySHA256: 4b293e7aa55ce647a31dbca8b098fc96f18c0a4607f49b5dba81f6b045e26964
JSON の署名: O+Wup191fzi2FEbZBVJqwJvAyq8=
validate(JSON): True
validate(本文を1文字変更): False
validateRequestWithBody: true
JSON を一度辞書に直してから文字列に戻すと、空白や順番が変わってハッシュが合わなくなります。受け取った生の本文で検証します。
Webhook のタイムアウトと再試行
| 設定 | 既定値 | 変えられる範囲 |
|---|---|---|
| 接続のタイムアウト(ct) | 5,000ミリ秒 | 100〜10,000 |
| 応答のタイムアウト(rt) | 15,000ミリ秒 | 100〜15,000 |
| 全体の時間(tt) | 15,000ミリ秒 | 100〜15,000 |
| 再試行の回数(rc) | 1回 | 0〜5 |
| 再試行する条件(rp) | ct(接続の失敗) | 4xx・5xx・ct・rt・all |
URL の後ろに #rc=3&rp=5xx,ct のように書くと変えられます(公式「Webhooks Connection Overrides」。公式はこの方法を以前からの方法(legacy)とし、Webhooks の設定 API を勧めています)。署名の検証では、この # 以降を URL に含めません。音声通話の Webhook は15秒が上限で、それより長くかかる処理は応答を返してから別に行います。
TwiMLとは(電話とSMSの応答の書き方)
この節では、Twilio に「どう応答するか」を伝える TwiML の書き方が、生成した XML の実物つきで分かります。
TwiML(Twilio Markup Language)は、着信や受信のときに Twilio に返す XML の指示書です。 「読み上げる」「番号の入力を待つ」「転送する」などを、<Response> の中に上から順に書きます。Webhook の応答の Content-Type は text/xml にします。
| 動詞 | 働き | よく使う属性 |
|---|---|---|
<Say> |
文を読み上げる | language="ja-JP"・voice |
<Play> |
音声ファイルを流す | loop |
<Gather> |
ボタンの入力・音声を受け取る | numDigits・action・timeout |
<Dial> |
別の電話につなぐ | callerId・timeout |
<Record> |
録音する | maxLength・action |
<Redirect> |
別の TwiML に移る | method |
<Hangup> |
電話を切る | ― |
<Reject> |
着信を拒否する(課金されない) | reason |
<Message> |
SMS で返信する(Messaging の TwiML) | to・from |
Python の SDK で、電話の自動応答(1か2を押させる)の TwiML を作りました。
from twilio.twiml.voice_response import VoiceResponse, Gather
resp = VoiceResponse()
g = Gather(num_digits=1, action="/menu", method="POST", timeout=5)
g.say("お電話ありがとうございます。営業時間のご案内は1を、担当者におつなぎするには2を押してください。",
language="ja-JP", voice="Polly.Kazuha-Neural")
resp.append(g)
resp.say("入力が確認できなかったため、お電話を終了します。", language="ja-JP", voice="Polly.Kazuha-Neural")
resp.hangup()
print(resp)
API で電話をかけ(client.calls.create(to=…, from_="+81501234567", url="…/voice"))、擬似サーバーがその URL から TwiML を取りに行ったときの記録です。
[SDK] POST https://api.twilio.com/2010-04-01/Accounts/AC0123456789abcdef0123456789abcdef/Calls.json
CA4741d0aba54056e19af936fdc976efba queued
<-- TwiML を取得 http://127.0.0.1:35401/voice : 200 text/xml
<?xml version="1.0" encoding="UTF-8"?><Response><Gather action="/menu" method="POST" numDigits="1" timeout="5"><Say language="ja-JP" voice="Polly.Kazuha-Neural">お電話ありがとうございます。営業時間のご案内は1を、担当者におつなぎするには2を押してください。</Say></Gather><Say language="ja-JP" voice="Polly.Kazuha-Neural">入力が確認できなかったため、お電話を終了します。</Say><Hangup /></Response>
SDK は Python の num_digits を XML の numDigits に変えています。<Gather> の中の <Say> を読んでいる間もボタンを受け付け、押されると action の URL に Digits が送られます。入力が無ければ <Gather> の次の行に進みます。
voice は Polly.声の名前 や Google.声の名前 の形で書きます。日本語の Kazuha-Neural・Tomoko-Neural は 2023年5月の Twilio の更新履歴で追加が告知されています。使える声の一覧はコンソールの Text-to-Speech 設定と公式の表で選べ、言語と声の組み合わせが合わないと <Say> が失敗します。Polly の声は1回 3,000文字まで(SSML のタグを除く)、Google の声は 5,000文字までで、料金は100文字単位で数えられます(公式「Text-to-Speech」)。
TwiML はファイルを置くだけでも動きます。動きを変えない応答なら、Twilio の TwiML Bins(コンソールに TwiML を保存する機能)にも置けます。
VerifyでSMS認証(ワンタイムパスコード)を作る
この節では、Verify を使って SMS で認証コードを送り、照合するまでの流れが分かります。
Verify は、認証コードの生成・送信・有効期限・照合を Twilio に任せる API です。 自分でコードを作って SMS で送る形と違い、コードを自分のデータベースに保存しません。コンソールで Verify の Service(VA で始まる ID)を作ってから使います。
svc = "VA11112222333344445555666677778888" # Verify の Service SID
v = client.verify.v2.services(svc).verifications.create(to="+819012345678", channel="sms", locale="ja")
print("send:", v.status)
for code in ["000000", "123456"]: # 利用者が入力したコード
c = client.verify.v2.services(svc).verification_checks.create(to="+819012345678", code=code)
print(f"check {code}:", c.status, c.valid)
擬似サーバー(正しいコードを 123456 にしたもの)に向けた結果と、送られた中身です。
[SDK] POST https://verify.twilio.com/v2/Services/VA11112222333344445555666677778888/Verifications
send: pending
[SDK] POST https://verify.twilio.com/v2/Services/VA11112222333344445555666677778888/VerificationCheck
check 000000: pending False
[SDK] POST https://verify.twilio.com/v2/Services/VA11112222333344445555666677778888/VerificationCheck
check 123456: approved True
--> POST https://verify.twilio.com/v2/Services/VA11112222333344445555666677778888/Verifications
body: To=%2B819012345678&Channel=sms&Locale=ja
--> POST https://verify.twilio.com/v2/Services/VA11112222333344445555666677778888/VerificationCheck
body: Code=123456&To=%2B819012345678
Verify のホストは api.twilio.com ではなく verify.twilio.com で、パスも /v2/ です。公式によると、Channel は sms・call・email・whatsapp・sna・auto から選び(voice は使えず call)、コードは10分で切れ、状態は pending・approved・canceled・max_attempts_reached・expired などです。照合が成功(approved)したときだけ1件 0.05ドルがかかり、SMS の送信料は送るたびにかかります(料金の節)。
WhatsAppのメッセージを送る
この節では、WhatsApp を SMS と同じ API で送る方法と、試すときの Sandbox の決まりが分かります。
WhatsApp は、SMS と同じ messages.create で、宛先と送信元に whatsapp: を付けて送ります。
client.messages.create(
to="whatsapp:+819012345678",
from_="whatsapp:+14155238886", # Sandbox の番号
body="ご注文を受け付けました。",
)
| 項目 | Sandbox(試す用) | 本番 |
|---|---|---|
| 送信元 | 共有の +14155238886 | 自社の WhatsApp Business Account の番号 |
| 相手の準備 | 「join 合言葉」を送って参加 | 参加の手続きは無い |
| 期限 | 参加から3日 | ― |
| テンプレート | 用意された3種だけ | Meta の承認を受けた自社のもの |
| 送信の速さ | 3秒に1通まで | ― |
公式によると、相手からメッセージが来てから24時間(カスタマーサービスの時間帯)は自由な文面を送れ、それ以外は承認済みのテンプレート(ContentSid と ContentVariables)だけを送れます。料金は Twilio の1通 0.005ドルに、Meta の料金(メッセージの種類と国で変わる)が足されます。
Twilioのよくあるエラーコードと直し方
この節では、API と配信で出るエラーコードの意味と、直す場所が分かります。
API がその場で返すエラー(2xxxx)と、送ったあとに配信で起きるエラー(3xxxx)、Webhook のエラー(1xxxx)は、見る場所が違います。 擬似サーバーを公式のエラーの形(code・message・more_info・status)で返すように作り、Python の SDK から7つの失敗を起こしました。
from twilio.base.exceptions import TwilioRestException
def run(label, **kw):
args = dict(to="+819012345678", from_="+15017122661", body="テスト")
args.update(kw)
try:
client.messages.create(**args)
print(f"■ {label}: 成功")
except TwilioRestException as e:
print(f"■ {label}: {type(e).__name__} status={e.status} code={e.code}")
print(f" msg={e.msg}")
■ Auth Token の間違い: TwilioRestException status=401 code=20003
msg=Unable to create record: Authenticate
■ To が国番号なし: TwilioRestException status=400 code=21211
msg=Unable to create record: Invalid 'To' Phone Number: 09012345678
■ To が固定電話: TwilioRestException status=400 code=21614
msg=Unable to create record: 'To' number +81312345678 is not a valid mobile number
■ トライアルで未認証の宛先: TwilioRestException status=400 code=21608
msg=Unable to create record: The number +819011112222 is unverified. Trial accounts may only send messages to verified numbers.
■ From が自分の番号でない: TwilioRestException status=400 code=21606
msg=Unable to create record: The From phone number +15005550000 is not a valid, SMS-capable inbound phone number or short code for your account.
■ 本文が1600文字超: TwilioRestException status=400 code=21617
msg=Unable to create record: The concatenated message body exceeds the 1600 character limit.
■ 送りすぎ: TwilioRestException status=429 code=20429
msg=Unable to create record: Too Many Requests
SDK はどの失敗も TwilioRestException にし、status(HTTP の番号)と code(Twilio のエラーコード)を持たせます。 msg の「Unable to create record:」は SDK が付ける前置きで、その後ろは擬似サーバーで書いた文面です(本物の文面とは違う場合があります)。直すときは code で見分けます。SDK 9.12.0 の既定では、429 が返っても送り直さずにそのまま例外になりました。
エラーの名前は公式のエラー一覧(Error and Warning Dictionary)の表記です。
| コード | 公式の名前 | 主な原因と直し方 |
|---|---|---|
| 20003 | Permission Denied | 認証の誤り。SID とトークン・キーの組を確かめる |
| 20404 | Not Found | SID や URL の誤り。別アカウントのリソース |
| 20429 | Too many requests | 送りすぎ。待って送り直す |
| 21211 | Invalid 'To' Phone Number | 国番号なし・形式の誤り。+81 の E.164 に直す |
| 21408 | Message blocked: permissions disabled for the destination region | 送信先の国を Geographic Permissions で許可 |
| 21606 | 'From' number is not a valid message-capable Twilio number for this account | 自分の SMS 対応の番号か確かめる |
| 21608 | Upgrade and create an approved primary compliance profile to reach unverified numbers | トライアル。宛先を認証するか有料にする |
| 21610 | Attempt to send to unsubscribed recipient | 相手が STOP で停止済み。送らない |
| 21614 | 'To' number is not a valid mobile number | 固定電話宛て。携帯の番号にする |
| 21617 | The concatenated message body exceeds the 1600 character limit | 本文を短く・分けて送る |
| 30003・30005 | Unreachable / Unknown destination handset | 電源オフ・圏外・存在しない番号 |
| 30007 | Message filtered | 携帯電話会社に迷惑 SMS と判定された。内容と送信元を見直す |
| 11200 | HTTP retrieval failure | Webhook の URL に届かない・エラーを返した |
| 12100 | Document parse failure | 返した TwiML の XML が壊れている |
3xxxx は API の応答ではなく、StatusCallback の ErrorCode と、コンソールの Messaging のログで分かります。11200・12100 などの Webhook のエラーは、コンソールの Debugger(Monitor のログ)に記録されます。429 を送り直すときの待ち時間の決め方は、関連記事「指数バックオフとは?リトライ間隔の決め方とジッターの実装」で扱っています。
届かないときに確かめる順番
API の応答が 201 だったか
4xx なら、届く前に断られています。code を上の表で見ます。
最後の状態と ErrorCode を見る
コンソールの Messaging のログか、StatusCallback で、undelivered・failed と ErrorCode を確かめます。
日本の決まりに合っているか
送信元が日本の番号でないか、本文に電話番号が無いか、禁止の内容でないかを、日本の節のチェックで確かめます。
Webhook が動いているか
返信や着信が来ないときは、Debugger で 11200(届かない)・12100(XML の誤り)・署名検証の 403 を確かめます。
よくある質問
Q. Twilioの読み方は? A. 「トゥイリオ」です。ソフトバンクのサービスページなどでもこの表記が使われています。
Q. Twilioは無料で使えますか? A. トライアルで SMS 100通・WhatsApp 100通・メール 3,000通・音声 75分を無料で試せます。期間は登録から30日で、送れる相手は認証した番号(最大5件)だけです。
Q. Twilioの料金は日本円で払えますか? A. Twilio の料金ページの表示はドル建てです。ソフトバンク経由の契約の支払い条件は、ソフトバンクの窓口で確かめます。
Q. Twilioで日本の携帯電話にSMSを送れますか? A. 送れます。米国などの SMS が使える番号か、英数字の送信者 ID(例「RJC」)から送ります。Twilio で買った日本の番号は SMS の送信元に使えません。
Q. Twilioで050番号は取れますか? A. 取れます。音声通話用で、月 4.75ドルです(2026年10月23日時点)。法人の書類(履歴事項全部証明書など)による審査があり、個人向けの要件は公式のガイドラインに載っていません。
Q. Twilioとは何の会社ですか? A. 米国サンフランシスコに本社を置く、通信の API を提供する会社です。2008年に創業し、メール配信の SendGrid も Twilio の製品です。日本法人は Twilio Japan 合同会社です。
Q. TwiMLとは何ですか?
A. 着信や受信のときに Twilio に返す XML の指示書です。<Say> で読み上げ、<Gather> でボタンの入力を受け、<Dial> で転送する、といった動きを書きます。
Q. X-Twilio-Signature の検証が失敗します。 A. Twilio に登録した URL と、アプリが検証に使った URL が違うことが多い原因です。プロキシの内側では http と https、ホスト名、末尾のスラッシュがずれます。外から見た URL で検証します。
Q. エラー21608の意味は? A. トライアルのアカウントから、認証していない番号に送ろうとしたエラーです。コンソールで宛先の番号を認証するか、有料のアカウントに切り替えます。
Q. エラー30007(Message filtered)が出ます。 A. 携帯電話会社に迷惑 SMS と判定されて届かなかった状態です。日本宛てでは、本文に電話番号を入れない・禁止の内容を避ける・同意を得た相手にだけ送る、を確かめます。
Q. Twilio Verify と自分で作る SMS 認証の違いは? A. Verify はコードの生成・有効期限(10分)・照合を Twilio が受け持ち、成功1件 0.05ドル+送信料がかかります。自分で作る場合はコードの保存と期限の管理を自分で書き、SMS の送信料だけがかかります。
Q. TwilioとSendGridの関係は? A. SendGrid は 2019年に Twilio の一部になったメール配信サービスで、今は Twilio の製品の1つ(SendGrid Email API)です。料金は月 19.95ドルからで、1日100通の無料トライアルがあります。
まとめ
- Twilio(トゥイリオ)は、SMS・音声通話・WhatsApp・認証コード・メールを API で扱えるクラウドサービス。料金はドル建ての従量課金。
- 日本宛ての SMS は1セグメント 0.089ドル、050番号は月 4.75ドル、Verify は成功1件 0.05ドル+送信料(2026年10月23日時点)。日本語は70文字を超えると67文字ずつに分かれて課金される。
- Twilio で買った日本の番号は SMS の送信元に使えない。米国などの番号か英数字の送信者 ID から送り、特定電子メール法の同意・表示と、本文に電話番号を入れない決まりを守る。
- API は HTTP Basic 認証とフォーム形式。curl では
--data-urlencodeを使わないと+が空白になる。 - Webhook は
X-Twilio-Signature(URL+名前順のパラメーター → HMAC-SHA1 → Base64)を SDK で検証する。プロキシの内側では外から見た URL で検証する。 - エラーは
codeで見分ける。2xxxx は API の応答、3xxxx は StatusCallback とログ、1xxxx は Debugger で確かめる。
参考・出典
確認日はいずれも 2026年10月23日です。
- Twilio「料金」(日本語版):https://www.twilio.com/ja-jp/pricing
- Twilio「SMS Pricing in Japan」:https://www.twilio.com/en-us/sms/pricing/jp
- Twilio「Voice Pricing in Japan」:https://www.twilio.com/en-us/voice/pricing/jp
- Twilio「Verify Pricing」:https://www.twilio.com/en-us/verify/pricing
- Twilio「WhatsApp Pricing」:https://www.twilio.com/en-us/whatsapp/pricing
- Twilio「Japan SMS Guidelines」:https://www.twilio.com/en-us/guidelines/jp/sms
- Twilio「Japan Voice Guidelines」:https://www.twilio.com/en-us/guidelines/jp/voice
- Twilio「Japan Phone Number Regulations」:https://www.twilio.com/en-us/guidelines/jp/regulatory
- Twilio Docs「How to use your free trial account」:https://www.twilio.com/docs/usage/tutorials/how-to-use-your-free-trial-account
- Twilio Docs「Requests to Twilio」:https://www.twilio.com/docs/usage/requests-to-twilio
- Twilio Docs「API keys」:https://www.twilio.com/docs/iam/api-keys
- Twilio Docs「Message resource」:https://www.twilio.com/docs/messaging/api/message-resource
- Twilio Docs「Track the message status of outbound messages」:https://www.twilio.com/docs/messaging/guides/track-outbound-message-status
- Twilio Docs「Twilio's request to your incoming message webhook URL」:https://www.twilio.com/docs/messaging/guides/webhook-request
- Twilio Docs「What is the SMS character limit?」:https://www.twilio.com/docs/glossary/what-sms-character-limit
- Twilio Docs「Webhooks security」:https://www.twilio.com/docs/usage/webhooks/webhooks-security
- Twilio Docs「Webhooks Connection Overrides」:https://www.twilio.com/docs/usage/webhooks/webhooks-connection-overrides
- Twilio Docs「TwiML for Programmable Voice」:https://www.twilio.com/docs/voice/twiml
- Twilio Docs「TwiML Voice: Say」:https://www.twilio.com/docs/voice/twiml/say
- Twilio Docs「Text-to-Speech」:https://www.twilio.com/docs/voice/twiml/say/text-speech
- Twilio Changelog「New Amazon Polly voices for Say」(2023年5月12日):https://www.twilio.com/en-us/changelog/new-amazon-polly-voices-for-say-update-05-2023
- Twilio Docs「Verification」(Verify API):https://www.twilio.com/docs/verify/api/verification
- Twilio Docs「WhatsApp」:https://www.twilio.com/docs/whatsapp
- Twilio Docs「Twilio Sandbox for WhatsApp」:https://www.twilio.com/docs/whatsapp/sandbox
- Twilio Docs「Error and Warning Dictionary」:https://www.twilio.com/docs/api/errors
- Twilio Press「SoftBank Corp. and Twilio Japan Sign New Reseller Agreement」(2023年10月16日):https://twilio.com/en-us/press/releases/softbank-twilio-japan
- ソフトバンク「Twilio」:https://www.softbank.jp/biz/services/platform/twilio/
- ソフトバンク ビジネスブログ「Twilioで購入できる電話番号」:https://www.softbank.jp/biz/blog/cloud-technology/articles/202501/twilio-phone-number/
- ITmedia NEWS「クラウド電話APIの「Twilio」が日本法人設立」(2019年8月30日):https://www.itmedia.co.jp/news/article/1908/30/1190830103/
- 総務省「特定電子メール法のポイント」(パンフレット):https://www.soumu.go.jp/main_sosiki/joho_tsusin/d_syohi/pdf/m_mail_pamphlet.pdf
- Wikipedia「Twilio」:https://en.wikipedia.org/wiki/Twilio
- PyPI「twilio」:https://pypi.org/project/twilio/
- npm「twilio」:https://www.npmjs.com/package/twilio
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Twilioとは|使い方・料金・日本のSMS規制とAPI・署名検証の実例」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。