TwilioPay(電話でペイ)で勉強会の会費を徴収してみた

#この記事は
[Twilio Advent Calendar 2018](https://qiita.com/advent-calendar/2018/twilio)の12月16日分の投稿です。
昨日は、@mobilebizさん「[Twilio FlexでLINE Channelを連携させる方法](https://qiita.com/mobilebiz/items/8d8de372da2280d3b0c3)」でした。

#Twilio Payとは
2018年10月にサンフランシスコで開催されたTwilioのビックイベント「SIGNAL」で発表された、音声通話でクレジットカード決済をするための機能です。PCI DSS基準を満たす決済システムを簡単に導入できる機能です。
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f38363034362f32383832643737382d306465312d306330342d636534352d6530353937653363313161332e706e67.png](https://qiita-image-store.s3.amazonaws.com/0/110436/1fd7e118-6ed0-8d53-95ad-80f2590ee953.png)
詳しくはTwilioエバンジェリスト高橋さんの[Qiita記事](https://qiita.com/mobilebiz/items/31b061af62b35fd82724)で紹介されてますので、そちらをご覧いただくのが確実です。作り方も画像付きで説明されているのでわかりやすいです。
ちなみに、現在は、stripeのみの利用となっていますが、\<Pay\> Connectorsというくらいだから、今後はstripe以外も使えるようになるといいなと思っています。(個人の感想です)

#ざっくり作ってみました。
先日開催しました[【TwilioJP-UG 岡山 #2】Twilio SIGNAL報告会 in OKAYAMA](https://twiliojp-ug.doorkeeper.jp/events/81670)にて、ハンズオンを実施し、そこで実装しました。
ほぼ、高橋さんの[Qiita記事](https://qiita.com/mobilebiz/items/31b061af62b35fd82724)でやっていることとほとんど同じなのですが、クレジット決済の結果を取得し、電話でお伝えするようにしてみました。
##着電時のTwiML(TwiML Binsで実装)
ポイントは、\<pay>動詞にactionに、結果を通知する先を指定することです。

```xml
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Say language="ja-JP">勉強会のご参加ありがとうございます。本日の会費は300円です。</Say>   
  <Pay chargeAmount="300" currency='jpy' action="[ここに通知先を指定]" postalCode="false" paymentConnector="default">
    <Prompt for="payment-card-number">
      <Say language="ja-JP">クレジットカード番号を入力してください。</Say>
    </Prompt>    
    <Prompt for="expiration-date">
      <Say language="ja-JP">有効期限を、月と年のそれぞれ2桁の数字で入力してください。</Say>
    </Prompt>    
    <Prompt for="security-code">
      <Say language="ja-JP">セキュリティーコードを入力してください。カードの裏に記載されています。</Say>
    </Prompt> 
  </Pay>
</Response>
```
##結果を受け取る（Twilio Functionsで実装）
上記、「ここに通知先を指定」について、今回は、Twilio Functionsで実装しました。
※自身のWebサーバーで受けることも可能です。
※TwilioFunctionの場合だと、PropertiesのPATHの値を、上記actionに指定します。

```javascript
exports.handler = function(context, event, callback) {
  let twiml = new Twilio.twiml.VoiceResponse();

  switch (event.Result) {
    case "success":
      text = "会費300円の決済が完了しました。ご利用ありがとうございました。";
      break;

    case "payment-connector-error":
      text = "エラーが発生しました。決済に失敗しました。";
      console.log(decodeURIComponent(event.PaymentError));
      break;
    
    default: 
        text = "決済に失敗しました。";
    }
    twiml.say({ language: 'ja-JP' },text);
    callback(null, twiml);
};
```
こちら、POSTで呼び出されるのですが、パラメータとしては以下のようなものが設定されていました。
※2018年12月16日現在
※決済関連だけ赤字にしました。その他は通常の着信と基本的に同じ。
※詳しくは[仕様](https://www.twilio.com/docs/voice/twiml/pay)をご確認ください。

| パラメータ     |  説明 (個人の感想です)    |   値  |
|:--------------|:------------------|:------------------|
|AccountSid	|TwilioのAccountSid|AC******************************|
|ApiVersion	|TwilioのいつものApiVersion|2010-04-01|
|Called	|決済に利用したTwilio側の電話番号(E.164形式)|+8150********	|
|CalledCity	|受信者情報(地域)|空文字|
|CalledCountry	|受信者情報(国)|JP|
|CalledState	|受信者情報(状態)|空文字|
|CalledVia	|受信者情報(電話番号)|050********|
|CalledZip	|受信者情報(Zip)|空文字|
|Caller	|発信者情報(電話番号 E.164形式)|+8190********|
|CallerCity	|発信者情報(地域)|空文字|
|CallerCountry	|発信者情報(国)|JP|
|CallerState	|発信者情報(状態)|空文字|
|CallerZip	|発信者情報(Zip)|空文字|
|CallSid	|CallSid|CA******************************|
|CallStatus	|通話の状態|in-progress|
|Direction	|発着信の種別|inbound|
|<font color="Red">ExpirationDate</font>|<font color="Red">クレジットカード有効期限</font>|<font color="Red">YYMM</font>|
|ForwardedFrom|Twilio番号|050********|
|From	|発信者情報(電話番号 E.164形式)|+8190********|
|FromCity	|発信者情報(地域)|空文字|
|FromCountry	|発信者情報(国)|JP|
|FromState	|発信者情報(状態)|空文字|
|FromZip	|発信者情報(Zip)|空文字|
|<font color="Red">PaymentCardNumber</font>|<font color="Red">クレジットカード番号(下4桁以外マスク)</font>|<font color="Red">xxxxxxxxxxxx0000</font>|
|<font color="Red">PaymentCardPostalCode</font>|<font color="Red">ZIPコード(入力させてない)</font>|<font color="Red">空文字</font>|
|<font color="Red">PaymentCardType</font>|<font color="Red">クレジットカードの種類</font>|<font color="Red">mastercardとかvisaとか</font>|
|<font color="Red">PaymentConfirmationCode</font>|<font color="Red">決済確認コード(stripe側のコード)</font>|	<font color="Red">ch_********************yzf</font>|
|<font color="Red">PaymentError</font>|<font color="Red">決済エラー情報</font>|<font color="Red">空文字。エラーだったら入る？</font>|
|<font color="Red">PaymentToken</font>|<font color="Red">決済トークン</font>|<font color="Red">空文字</font>|
|<font color="Red">Result</font>|<font color="Red">決済結果</font>|<font color="Red">success</font>|
|<font color="Red">SecurityCode</font>|<font color="Red">クレジットカードのセキュリティー番号。常に"xxx"</font>|<font color="Red">xxx</font>|
|To	|決済に利用したTwilio側の電話番号(E.164形式)|+8150********	|
|ToCity	|受信者情報(地域)|空文字|
|ToCountry	|受信者情報(国)|JP|
|ToState	|受信者情報(状態)|空文字|
|ToZip	|受信者情報(Zip)|空文字|
特に、PaymentConfirmationCodeを取得することができ、これが、stripeの管理画面の以下の値と一致しています。<img width="1383" alt="スクリーンショット 2018-12-16 22.58.36.png" src="https://qiita-image-store.s3.amazonaws.com/0/110436/a222a4fb-384c-15b0-f889-185b194b6065.png">
これらの値を利用すれば、他システムと連携できたり、決済後SMSで領収書のURLを送付できたりと、いろいろできそうです。

#会費を徴収してみました。
2018年12月15日に開催しました[JP_Stripes Okayama #1](https://eventregist.com/e/JP_Stripes_OKJ)にて徴収してみました。
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">セミナー中にみんなで電話！<br>会場費を電話クレジット決済(TwilioPay+Stripe)でお支払いいただきました！<a href="https://twitter.com/hashtag/JP_Stripes?src=hash&amp;ref_src=twsrc%5Etfw">#JP_Stripes</a> <a href="https://t.co/AoOpOgwusX">pic.twitter.com/AoOpOgwusX</a></p>&mdash; takeshi.furusato (@t_furusato) <a href="https://twitter.com/t_furusato/status/1073810417242132480?ref_src=twsrc%5Etfw">2018年12月15日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
未だかつてない空気感での会費徴収が斬新でしたね。

ちなみに、徴収した金額はStripeの管理画面で確認することができます。
上記stripeの画面キャプチャ参照。左メニューの「支払い」で表示されます。

また、支払い側のクレジットカード利用明細には、
**ST [明細書表記欄に入力された値]**
となります。左メニューのビジネス設定のクレジットカードの明細書欄に、お客様にわかりやすいちゃんとしたものを設定しておくことが大事。
<img width="1207" alt="スクリーンショット 2018-12-16 23.51.56.png" src="https://qiita-image-store.s3.amazonaws.com/0/110436/c6f8bb72-a570-546c-9aba-5860f5f2716b.png">

なお、ご利用費用は、、、
Twilioは、1決済につき、15円。決済が成功した場合にのみ課金。チャージから引き落とし。
Stripeは、決済金額の3.6%が手数料として課金。1決済ごとの入金金額から差し引かれます。

#まとめ
いままで、電話決済を作ろうとすると、こんなに簡単に実装はできなかったはず。
TwilioPayとStripeでこの電話決済が非常に身近になったと思います。
日本円で決済できるようになったのも魅力的。
今後、Stripe以外も連携をすると思いますので、そちらにも期待ですね(個人の感想です)
調べてみたのですが、まだ、Twilio Studioにはなさそうだったので、そちらに導入されることも期待しています。TwilioFlexとの連携なども今後試してみたいです。


明日は@sh-ogawaさんの「Twilioに追加されたPolly連携が有用なのかをドキュメントからまとめた」です。
[Twilio Advent Calendar 2018](https://qiita.com/advent-calendar/2018/twilio)