Webhookを使ってStripeの決済結果をSalesforceで管理しよう

Webサイト上で商品を購入したり、イベントに申し込んだりした経験がありますよね。

今回はいくら決済されたのかSalesforceに記録を残してみようと思います。Apex初挑戦です!

決済サービスもいくつかありますが今回はStripeを利用します。

Stiripeとは

120ヵ国、数百万の企業が導入しているオンライン決済システムです。

135を超える通貨に対応し、クレジットカードやウォレットなど複数の決済方法にも対応しています。

クレジットカード決済の場合、日本 のユーザーは、Visa, Mastercard, American Express, Discover, JCB, Diners Club、デビットカードに対応しています。

実現イメージ

Salesforce 
」 ava ・ C # な ど で 
作 成 さ れ た 決 済 亘 面 
决 済 
本 記 事 の 対 応 部 分 
Stri pe 
W e b h 00 k 
決 済 結 果 
Salesforce

今回はStripeでの決済完了後にSalesforceのケースを1件登録する処理を実現します。

決済機能は任意の環境で構築します。

SalesforceのExperience Cloudでも、JavaでもC#でもOKです。

Stripeでは2種類の構築方法があります。

  1. 構築済みのCheckoutページ
  2. カスタム決済フロー

どちらも複数の言語でサンプルが提供されています。

  メリット デメリット
構築済みのCheckoutページ開発期間が短い画面デザインのカスタマイズができない 機能面はある程度のカスタマイズのみ
カスタム決済フロー 画面デザインや機能の自由度が高い一から構築が必要なため時間がかかる

決済画面の構築は割愛しますが、「構築済みのCheckoutページ」を利用しました。

Webhookで通知する

今回の目的である決済結果をSalesforceで取得するためにWebhookを利用します。

WebhookとはWebアプリケーションで特定のイベントが発生した際に別のWebアプリケーションにHTTPで通知する仕組みです。

その通知をキャッチして様々な処理を実行することができます。

①Salesforce側の受け口を作成

Apexを利用してWebhookの通知を受け取って実行するクラスを作成します。

Trailheadの「Apex Web サービス」「Apex REST コールアウト」を参考にしました。

決済が成功したらケースを作成します。

Stiripeの返却値から支払金額を取得して、ケースのタイトルに登録します。

 @RestResource(urlMapping='/Cace/*')
 global without sharing class CheckoutResult{    
         
     @HttpPost
     global static void doPost(){
       
         RestRequest req = RestContext.request;
         Map<String, Object> requestParams = (Map<String, Object>)JSON.deserializeUntyped(req.requestBody.ToString());
         //階層ごとにデータを抽出
         Map<String, Object> paramData = (Map<String, Object>)requestParams.get('data');    
         Map<String, Object> paramObject = (Map<String, Object>)paramData.get('object');
         Integer amount = (Integer)paramobject.get('amount');
  
         //ケースに登録
        Case thisCase = new Case(
              Subject=amount +'円の入金がありました',  
                     Priority='Medium',
                     Status='New',
                     Origin='Email');
    insert thisCase;
    }
 } 

テストクラス

Webhookで返されるbodyのテスト値は静的リソースを利用しました。

SrtipeのWebhookページで、どのようなbodyが返されるか確認できます。

 @isTest
 Public class TestCheckoutResult {
     @isTest
     static void testCheckoutResult() {
                 
         StaticResource sr = [SELECT Id, Body FROM StaticResource WHERE Name = 'GetWebhookResource' LIMIT 1];
         String body = sr.Body.toString();
         RestRequest req = new RestRequest();
         RestResponse res = new RestResponse();
         
         req.requestURI = '/services/apexrest/Checkout/';  //Request URL
         req.httpMethod = 'POST'; //HTTP Request Type
         req.requestBody = Blob.valueof(body);
         
         RestContext.request = req;
         RestContext.response= res;
         
         Test.startTest();
         CheckoutResult.doPost();
         Test.StopTest();   
     }
 }

※静的リソースに使用したbodyのサンプルは、下記「bodyの確認方法」に記載します。

②Salesforceのサイトを作成

「設定」からクイック検索に「サイト」と入力します。

「新規」ボタンからサイトを作成します。

つ 
ま 殳 定 
ホ - ム 
0 サ イ ト 
、 ・ 物 設 定 
オ フ ラ エ ク ト マ ネ - ジ ? 、 ′ 
サ イ ト 
ロ 
は 定 ー を 櫁 
第 0 用 1 イ ト 
釶 物 と 誉 ′ 口 ま 1 ゴ 
第 ■ 元 同 「 4 ジ の み で 1 レ ム に を ド 可 当 ー 
国 
~ れ て い ー ん 
0 
、 ′ ェ ラ タ ル エ ク ス ペ リ エ ン ス 
す べ て の サ イ ト 
、 ・ ユ - サ イ ン タ フ ェ - ス 
、 ′ サ イ ト お よ び ト メ イ ン 
カ ス タ ム し 社 
、 ・ セ キ ュ リ テ ィ 
CSV 億 、 第 み り イ ト 
リ モ ー ト サ イ ト の 設 
探 し て い る も の が 見 つ プ り ま せ ん カ リ 
ク ロ - バ ル 様 を お し く た さ い . 
StnpeWebl-cok 
、 ト の 画 ⅲ 当 パ ル 
り イ ト の 製 ・ 
物 ・ 0 り イ ト の 第 - ム ペ - 当 
当 ・ 0 り イ ト の 第 - ム ペ - ジ 
ま 第 ] ド 
支 、 へ の を ス ト ア う を ス 
デ ) ー 、 ト 新 し 」 - ト 務 物 ・ 
カ ス タ ム ー 州 
イ : 名 
ス ト ー ~ リ の L ・ 、 ・ 第 
1 ) う が 田 ス イ ト ス リ 1 れ 保 ・ を 有 第 第 
こ の サ イ ト に 第 要 な C 、 ・ ・ め ・ を 可 
第 ト 、 、 の を ス ト ア ケ を 
れ ス h 1 : ( リ ー イ し う ト 
5 、 “ - 勢 1 ・ 1 イ ン 
加 当 ム ー R 、 い

「公開アクセス設定」から「有効な Apex クラス」に①で作成したCheckoutResultを設定します。

③Stripe側のWebhook設定

REST サービスをコールするために使用されるエンドポイントで、

@RestResource(urlMapping=’/Cace/*’)で指定したCaceをURL末尾に指定します。

https://yourInstance.my.salesforce.com/services/apexrest/Case/

「yourInstance.my.salesforce.com」には②で作成したサイトのカスタムURLのドメイン名が入ります

0 
サ イ ト 
StripeWebhook 
サ イ ト の 詳 細 
リ イ ト の & 示 ) •R を 
サ イ ト の 明 
朴 。 用 づ イ ト 
石 効 な サ イ ト の ホ - ム 一 ジ 
を 第 員 罅 卩 レ 物 
第 な リ イ ト の 悪 ー ム ー ラ 
サ イ ト テ ン ) し 、 - ト 
鼬 ! 野 壘 些 ロ ヨ 
わ ) ラ ド つ う 保 第 し 、 
懲 関 元 冐 [ - ジ の で ] レ - ム 化 を 評 可 儼 ) 
コ ン ′ : つ 議 を を 物 に 
元 [ - の 保 第 
ま 払 疑 1 、 の ス ト ア ク セ ス 
デ ) 1 ル ト の レ ] ー ト 物 石 考 
公 望 、 - 滝 ( 第 ペ ー ラ を キ 第 0 シ ュ 
カ ス タ ム URL 
イ : 
第 ル ロ 参 ー 管 理 ヒ し て 1 レ ど 1-

URLが確認できたら、Stripeの開発者画面のWebhookページを開きます(画面は既に設定済み)

I Web hook 
WEBHOOK 
https:/ 
2021/11/15 
API 
2020-08-27 0 
tent 5 
. «cæded 
succæded 
succeeded 
.force.com/services/apexrest/Case/ 
payment_intent.succeeded 
2031-43 
202624 
2018-24 
2012:07 
Response 
Request 
NO response body

エンドポイントの編集画面を開き、エンドポイントURLに先ほどのURLを設定し、送信したいイベントを指定します。

今回は決済成功時に送信したいので、「payment_intent.succeeded」を選択します。

工 ン ト ホ イ ン ト の 編 集 
小 ポ イ ン ト UR し 
明 
[ ン ド ホ イ ン ト *URL 
ー 信 イ ベ ン ト 
イ ベ ン ト を 選 択 し て く だ さ い .. 
payment-intent.succeeded 
1 件 の イ ベ ン ト 
キ ャ ン セ ル 
ク リ ア 
X 
I ン ド ホ イ ン ト を 更 新

決済してみよう

「構築済みのCheckoutページ」を利用して作成した決済画面に必要事項を入力して支払うボタンをクリックします。

← : 株 式 会 社 エ ヌ デ ー デ ー 
参 考 書 
\ 10 , 000 
PO い r を d 靆 れ pe 
TEST MODE 
1 ラ イ バ シ - 
カ ー ド で 支 払 い 
メ ー ル ア ト レ ス 
カ ー ト 情 報 
12 ヨ 412 ヨ 412341234 
M M 第 リ YY ( 年 〕 
カ ー ト 所 有 者 名 
国 ま た は 地 域 
日 本 
こ V こ 
支 払 う

支払い金額10,000円をタイトルに含んだケースが作成されました!

10000 円 の 入 金 が あ り ま し た 
状 況 
Medium 
ケ ー ス 番 号 
00001028

※bodyの確認方法

テストで使用したbodyのサンプルの取得方法です。

Stripeの開発者画面のWebhookページから「テストイベントを送信」を選択します。

開 発 者 
概 要 
A 円 キ ー 
ー Webhook 
イ ベ ン ト 
ロ グ 
、 、 EBHOOK 
https:/ 
工 ン ド ボ イ ン ト 用 URL 
API バ ー ジ 三 ン 
2020 ・ 08 ・ 27 ① 
署 名 シ ー ク レ ッ ト 
表 示 
. fo 「 ( e. ( 0 m/services/apexrest/Case/ 
設 定 
ロ グ を 表 示 
> テ ス ト イ ベ ン ト を 送 信 
ス テ ー タ ス 
リ ッ ス ン 対 象 
payment_intent . 5 ( に に d ご d

「payment_intent.succeeded」を指定して「テストのWebhookを送信」をクリックします。

テ ス ト の イ ベ ン ト を Webhook の エ ン ド ホ イ ン ト に 送 信 
イ ベ ン ト タ イ プ payment_intent.succeeded 0 
キ ャ ン セ ル 
プ ス ト の Webhook を 送 信

リクエスト部分にbodyが表示されます。

こちらを静的リソースに登録します。

最初はbodyから取得をせず、決済したら固定文字でケースを作成するところから始めると良いと思います。

テ ス ト の イ ベ ン ト を Webhook の エ ン ド ホ イ ン ト に 送 信 
イ ベ ン ト タ イ フ 
リ ク エ ス ト 
false, 
" 2 0 2 0 - 0 8 - 2 7 " 
レ ス ホ ン ス 
テ ス ト の Webhook の 送 信 に 成 功 
ま 当 な し 
payment_intent.succeeded 
キ ャ ン セ ル 
プ ス ト の Webhook を 送 信

最後に

ずっと避けていたApexさん…

Apexは一度セミナーを受けた程度で、一から構築するのが初めてでしたので結構苦戦しました。

StripeもWebhookも初めてだったので、もっとシンプルなところから入れば良かったのですが…

初めてでもTrailheadを駆使してなんとかここまでできました!サンプルがあるのは有難いですね。

Stripeもサンプルが充実しているので、ある程度プログラム経験があればサクッと導入できて良いなと思いました。

今回はケースのタイトルに金額を登録するシンプルなものでしたが、Stripeからの返却値を使って、日付や数量をレコードに登録して、集計、グラフ化などしてみるのも良いですね。

これを機にApexもパッとできるように頑張ります!

ではまた…!

参考

https://stripe.com/docs/payments/integration-builder