はじめに
これは、2019/03/21(木・祝)開催 JP_Stripes Connect 2019のワークショップ『「電話でペイ!」(Twilio Pay)を試してみよう!』で使用する資料です。
- Twilio <Pay> を使って電話決済を体験する(初級編)
- Twilio <Pay> を使って電話決済を体験する(中級編) ←こちら
- Twilio <Pay> を使って電話決済を体験する(上級編)
Twilio を使って電話決済を体験する(中級編)では、電話決済時のクレジットカード情報入力状況を、Webページにリアルタイムに表示させるWebアプリケーションを作成します。
以下のような電話決済の様子を確認できるWebページを作ります。
前提
こちらは、Twilio <Pay> を使って電話決済を体験する(初級編)にて、StripeやTwilioの設定・構築ができていることが前提となります。
注意事項
Twilio <Pay> を使って電話決済を体験する(初級編)の注意事項に記載した費用が発生します。
また、TwilioFunctions、TwilioSyncを利用します。ワークショップでは、無料枠の範囲内で作業ができますが、それを超えると費用が発生します。
得られるもの
- Twilio<Pay>の状況通知(StatusCallback)の動作を体験できる
ざっくり構成
Twilio\は、状況が変化するたびに、指定したURLに通知をする機能(statusCallback)が用意されています。- Webhook:<Pay>は、予めTwilioFunctionsで作成した通知用URLに対し状況通知をする。
- ステータス保存:TwilioFuncitonにて、TwilioSyncというものを利用し、状況を保存します。
- ステータス通知:TwilioAssetに登録してある状況確認ページは、TwilioSyncから状況の通知を受ける。
- 閲覧:画面が更新される。
事前準備
Twilio <Pay> を使って電話決済を体験する(初級編)を実施していること。
ワークショップ
以下の手順になります。
- 決済の進捗状態を保存するためTwilioSyncを設定する
- Twilio<Pay>の決済状況をTwilioSyncに保存する処理を作成する
- 決済状況を表示させるWebページを作成する
- テストする。
進捗状態を保存するためTwilioSyncを設定する
Twilioにはリアルタイムに複数のデバイスに渡って状態を維持するためのAPIが用意されています。それがTwilioSyncです。今回は、TwilioSyncを利用して、決済の進捗状況を保存します。
TwilioSyncで新しいServiceを作成
Twilioの管理コンソールからSyncを選択します。※下の方にあります。
Servicesを選択します。
TwilioSyncは初期状態で、Default ServiceというServiceが登録されています。今回は、Twilio<Pay>のために、新規のServiceを作成します。画面上部の赤いプラスボタンをクリックします。
以下の画面が表示されるので、「PaySyncService」と入力します。※わかりやすい任意の名前でよいです。
作成に成功すると以下の画面が表示されますので、SESRVICE SIDをテキストエディタなどにメモしておきます。※後でPAY_SYNC_SERVICE_SIDとして使います。
メモできたら**< Back**で戻ります。
TwilioSyncにアクセスするためのAPI Keyを作成する
ツール → 新しいAPIキーを作成するをクリックします。
わかりやすい名前に「PayStatus API Key」と入力します。※わかりやすい任意の名前で良いです。
入力が終わったら、APIキーを作成するをクリックします。
APIキーの作成に成功すると、以下の画面が表示されます。
表示されているSIDとSECRETをテキストエディタなどにメモしてきます。※後でSIDはPAY_TWILIO_API_KEYとして、SECRETはPAY_TWILIO_API_SECRETとして使います。この画面から遷移するとSECRETは二度と表示されません。必ずメモしてください。
メモができたら**完了しました!**にチェックを入れて、終了をクリックします。
TwilioSyncへのAccessToken生成用のFunctionを作成
TwilioSyncを利用するためには、APIキーを使って、AccessTokenを動的に生成する必要があります。TwilioFunctionsを使って、TwilioSyncのAccessTokenを生成します。
まず、Function内で利用可能な環境変数に、さきほどのAPIキーなどを登録します。
Twilioの管理コンソールからRuntime → Functions → 設定を選択します。
Environmental Variablesにある赤いボタンをクリックし、以下のKEY-VALUEを追加します。※上記でそれぞれメモした値になります。
入力が終わったら、画面下のSaveをクリックします。
KEY | VALUE |
---|---|
PAY_SYNC_SERVICE_SID | ISから始まるSyncサービスのSID |
PAY_TWILIO_API_KEY | SKから始まるAPIキー |
PAY_TWILIO_API_SECRET | APIキーとセットで設定されたSECRET |
また、Enable ACCOUNT_SID and AUTH_TOKENにはチェックを入れておきます。 |
AccessToken生成用のFunctionを作成します。左のメニューからFunctionsを選択し、赤色のプラスボタンをクリックします。
以下の画面が表示されるのでBlankを選択し、Createをクリックします。
表示された画面で、以下のように入力し、Saveをクリックします。
項目名 | 設定値 |
---|---|
FUNCTION NAME | PayStatusSyncToken |
PATH | /pay-status-sync-token |
ACCESS CONTROL | チェックなし |
EVENT | (未選択) |
CODE | 以下参照 |
exports.handler = function(context, event, callback) {
const ACCOUNT_SID = context.ACCOUNT_SID;
const SERVICE_SID = context.PAY_SYNC_SERVICE_SID;
const API_KEY = context.PAY_TWILIO_API_KEY;
const API_SECRET = context.PAY_TWILIO_API_SECRET;
const IDENTITY = context.DOMAIN_NAME;
const AccessToken = Twilio.jwt.AccessToken;
const SyncGrant = AccessToken.SyncGrant;
const syncGrant = new SyncGrant({
serviceSid: SERVICE_SID
});
const accessToken = new AccessToken(
ACCOUNT_SID,
API_KEY,
API_SECRET
);
accessToken.addGrant(syncGrant);
accessToken.identity = IDENTITY;
callback(null, {
token: accessToken.toJwt()
});
};
保存できたら、PATHの後ろにあるコピーボタンでURLをコピー、ブラウザを別ダブで開き、そのURLにアクセスしてみてください。JSON形式のtokenが取得できていればOKです。
Twilio<Pay>の決済状況をTwilioSyncに保存する処理を作成する
Twilio<Pay>には statusCallbackというものがあり、こちらにURLを指定しておくと、状態が変わるたびに指定したURLに通知をしてくれます。
まずは、statusCallbackを受けて決済状況をTwilioSyncに保存する処理をTwilioFunctionsで作成します。
statusCallbackを受けるFunctionを作成
Twilioの管理コンソールからRuntime → Functionsを選択します。
赤色のプラスボタンをクリックします。
以下の画面が表示されるのでBlankを選択し、Createをクリックします。
表示された画面で、以下のように入力し、Saveをクリックします。
項目名 | 設定値 |
---|---|
FUNCTION NAME | PayStatus |
PATH | /pay-status |
ACCESS CONTROL | チェックなし |
EVENT | (未選択) |
CODE | 以下参照 |
exports.handler = function(context, event, callback) {
let payload = {
PaymentCardNumber : event.PaymentCardNumber,
ExpirationDate : event.ExpirationDate,
SecurityCode : event.SecurityCode,
Status : 'in-progress',
};
let sync = Runtime.getSync({serviceName: context.PAY_SYNC_SERVICE_SID});
sync.documents("PayStatus")
.update({
data: payload,
}).then(response => {
callback(null, 'OK');
}).catch(error => {
sync.documents.create({
uniqueName: "PayStatus",
data: payload
}).then(response => {
callback(null, 'OK');
}).catch(error => {
console.log(error);
callback(error);
});
});
};
保存できたらPATHの横にあるコピーボタンでURLをコピしておきます。
statusCallbackを受ける
<Pay>のstatusCallbackパラメーターに、先程のFunctionのURLを設定します。
Twilioの管理コンソールからRuntime → TwiML Binsを選択します。
Twilio を使って電話決済を体験する(初級編)にて作成したTwiML Binsをクリックします。今回は「stripe_demo」です。
4行目の<Pay>にstatusCallbackパラメータの設定を追加します。
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say language="ja-JP" voice="Polly.Mizuki">こんにちは。クレジットカード決済にようこそ。料金は100円です。</Say>
<Pay chargeAmount="100" currency='jpy' action="[stripe-result用FunctionのURL" postalCode="false" paymentConnector="stripe_test" statusCallback="[pay-status用FunctionのURL]" >
<Prompt for="payment-card-number">
<Say language="ja-JP" voice="Polly.Mizuki">クレジットカード番号を入力してください。</Say>
</Prompt>
<Prompt for="expiration-date">
<Say language="ja-JP" voice="Polly.Mizuki">有効期限を、月と年のそれぞれ2桁の数字で入力してください。</Say>
</Prompt>
<Prompt for="security-code">
<Say language="ja-JP" voice="Polly.Mizuki">セキュリティーコードを入力してください。カードの裏に記載されています。</Say>
</Prompt>
</Pay>
</Response>
決済状況を表示させるWebページを作成する
ブラウザに表示するHTMLを作成します。
TwilioにはAssetsというファイルを保存、Webサイトとして公開できる機能があります。今回はこちらを利用します。
アップロードするファイルを作成します。
今回は、以下にアップロードするファイルを用意しています。以下のファイルをダウンロードし、zipを展開してください。
https://heady-sea-5045.twil.io/assets/paystatus.zip
Assetsにアップロードする
Twilioの管理コンソールからRuntime → Assetsを選択します。
Add an Assetsをクリックし、上記zipファイルを展開したものをアップロードします。
そのままUploadをクリックします。
アップロード後、htmlファイルの方の、PATHのコピーボタンをクリックします。
テストする
新しくブラウザのタブを開き、上記htmlファイルのURLにアクセスします。
Twilio を使って電話決済を体験する(初級編)にて作成した決済用電話番号に電話をかけます。
入力する毎に、画面の表示が変わっていることを確認します。
おまけ
決済が完了したら、Webページの表示を「completed」にしたいと思います。
Twilioの管理コンソールからRuntime → Functionsを選択します。
Twilio を使って電話決済を体験する(初級編)で作成した、決済完了後に呼び出されるFunction(今回は「stripeResult)を選択します。
FunctionのCODEを以下の内容に書き換えます。
※処理の最後に、TwilioSyncを更新する処理を追加しました。
exports.handler = function(context, event, callback) {
let twiml = new Twilio.twiml.VoiceResponse();
switch (event.Result) {
case "success":
status_text = "completed";
text = "100円の決済が完了しました。ご利用ありがとうございました。";
break;
case "payment-connector-error":
status_text = "error";
text = "エラーが発生しました。決済に失敗しました。";
console.log(decodeURIComponent(event.PaymentError));
break;
default:
status_text = "error";
text = "決済に失敗しました。";
}
twiml.say({ language: 'ja-JP', voice: 'Polly.Mizuki' },text);
let payload = {
PaymentCardNumber : event.PaymentCardNumber,
ExpirationDate : event.ExpirationDate,
SecurityCode : event.SecurityCode,
Status : status_text,
};
let sync = Runtime.getSync({serviceName: context.PAY_SYNC_SERVICE_SID});
sync.documents("PayStatus")
.update({
data: payload,
}).then(response => {
callback(null, twiml);
}).catch(error => {
sync.documents.create({
uniqueName: "PayStatus",
data: payload
}).then(response => {
callback(null, twiml);
}).catch(error => {
console.log(error);
callback(error);
});
});
};
決済番号に電話をかけ、決済後、StatusがCompletedになることを確認します。
時間がある人は
Twilio を使って電話決済を体験する(上級編)をお試しください。
お礼
今回の資料を作成するにあたり、以下を参考にさせていただきました。ありがとうございます。
https://qiita.com/mobilebiz/items/89d8c0aa6a80dac1793f
追記
こちらについて、複数同時着信対応をしたものをつくりました。
https://qiita.com/takeshifurusato/items/2fd5fc09ebaeca666677
よろしければ、こちらもどうぞ。