Stripe x Postman Flowsでつくるかんたん決済ワークフロー

これは[Stripe/JP_Stripes Advent Calendar 2024](https://qiita.com/advent-calendar/2024/stripe)の19日目の記事です。

StripeとPostman Flowsを活用して、ローコードでかんたんな決済ワークフローを作成しました。本ブログでは、その内容と実行の流れについて解説します。

# 概要

商品を購入した際の決済フローを、StripeとPostman Flowsで実現します。内容はシンプルで、商品購入のための支払い処理を行い、支払いが完了したらその通知をSlackに送信するというものです。

これらのサービスに馴染みがない方のために、簡単に説明します。Stripeは、オンライン決済サービスを提供するプラットフォームで、ウェブサイトやアプリに決済機能を簡単に組み込むための便利なAPIやツールを提供しています。一方、Postman Flowsは、ビジュアルエディターを使用してローコードでAPIリクエストやレスポンスを視覚的に繋げてワークフローを構築できるPostmanの機能です。

https://stripe.com/

https://www.postman.com/product/flows/

今回つくったワークフローにおけるStripe、Postman Flowsの役割はそれぞれ次のとおりです。

- Stripe
  - 支払い用ホステッドページ
  - 支払処理
  - 支払完了後にWebhook イベント送信
- Postman Flows
  - Webhookイベント受信
  - Webhookの内容を元にSlack通知

少々ざっくりとしていますが、全体の処理の流れは次のとおりです。

![Screenshot 2024-12-18 at 12.38.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103420/d5f096af-99aa-efd9-0c0a-ab8a5a5595f6.png)

上記フローのポイントは下記のとおりです。

- 支払いページはStripeホステッドの[Checkoutページ](https://stripe.com/en-jp/payments/checkout)を活用
- Stripe APIの`Checkout - Create Session` ([API詳細](https://docs.stripe.com/api/checkout/sessions/create))で1回限りの購入支払いを行うセッションを作成すると、支払いページが作成される
- 支払い完了後のイベント発生は、Stripeの[Webhook機能](https://docs.stripe.com/payments/handling-payment-events)を活用。Webhookにより支払いイベントを外部に飛ばして、外部の処理をキックできる。ここでは、支払いの成功 (`payment_intent.succeeded`)イベントをトリガーとする
- WebhookのPOSTリクエスト先には今回作成したPostman FlowsのSlack通知用フロー (後半で処理内容を解説)のWebhookエンドポイントを設定
- Slack通知用フローは、Stripeより送信されたイベントの内容にもとづきSlackメッセージを通知

# Postman側のフローの解説

Postman Flowsで作成したフローの内容について簡単に解説します。

:::note info
ここで紹介するフローは公開しています。関連するコレクションや環境変数などのコンポーネントも合わせて公開しているので、興味のある方はぜひご覧ください。また、実際にフローを実行してみたい方は、ご自分の**パーソナルワークスペース**にフォークしてお試しください。

[StripeCheckoutEventProcessフロー](https://www.postman.com/what-is-api-first/stripe-x-postman-flows/flow/676280771edfa4003ce77315)
:::

![Screenshot 2024-12-18 at 12.40.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103420/a6465ebb-a587-d7d8-9ce6-94ab58b97046.png)

上図の起点のところからフローの処理が開始します。フローにPOSTされてくるStripeの支払いの成功 (payment_intent.succeeded)イベントのペイロードは次のようなJSON構造になっており、支払いにまつわる金額やcustomer IDなどの情報が含まれています。

```json
{
  "id": "evt_3QX9N7RvM14sgid50rd4XXXX",
  "object": "event",
  "data": {
    "object": {
      "id": "pi_3QX9N7RvM14sgid50GGVaJXX",
      "amount": 30000,
      "amount_received": 30000,
      "currency": "jpy",
      "customer": "cus_RPxGQMURi0OZXXX",
      "status": "succeeded",
      "transfer_group": null
    }
  },
  "type": "payment_intent.succeeded"
}
```

イベントの構造について詳しくは次のページが参考になります。

https://docs.stripe.com/api/events/object

なお、このフローはクラウド公開 (Publish)されており、外部からWebhookエンドポイント経由で実行できるようになっていることを前提とします。

以下、フローについて①〜③のパートに分けて解説します。

## ① Webhookの内容チェック
![Screenshot 2024-12-18 at 11.08.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103420/df4ee5a3-35e5-0115-60da-2bf67436f56a.png)

- Ifブロックの中で、Selectブロックを活用してWebhookペイロード (上記ペイロード構造を参照) の中のtypeプロパティをフィルターして、その値をtypeという名前の変数に格納
- Ifブロックでの中で、変数typeの値が "payment_intent.succeeded"であるかを比較。Trueであれば、処理は②にすすみ、FalseであればWebhookペイロードの内容をLogブロックでコンソール出力して処理を終了

## ② Customer情報取得

![Screenshot 2024-12-18 at 11.09.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103420/35a04415-5011-4e6e-65ad-4d64ed55c9c8.png)

- Send Requestブロックで、Selectブロックを活用してWebhookペイロードの中の`data.object.customer`部分を取得して、その値をcustomerIdという名前の変数に格納
- Send Requestブロックでは、Customer情報取得のAPIにリクエストを送信。このAPIリクエスト設定は、Stripe API コレクションの中で設定しているものを指定。このコレクションのAPIリクエスト設定の中で、上記で取得したcustomerId変数を参照。また、Send RequestブロックではStripe APIの利用に必要なAPIキー情報を格納している環境変数を指定
- Send RequestブロックでのCustomer情報取得のAPIリクエストが成功すると同ブロックのSuccess()にオレンジドットが付与され、クリックするとレスポンス内容が表示される。尚、もしリクエストが失敗するとFail()にオレンジドットが付与され、レスポンス内容はLogブロックでコンソール出力して処理を終了

## ③ Slack通知

![Screenshot 2024-12-18 at 11.09.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103420/6869a150-2278-63dd-f148-b741b9cb699b.png)

- Templateブロック、Displayブロック、Send Requestブロックの3種類のブロックで構成
- Templateブロックでは、Selectブロックを活用して次の4つの変数にフィルターした内容を格納
  - amount_received: Webhookペイロードの中の`data.object.amount_received`部分を取得して変数に格納
  - currency: Webhookペイロードの中の`data.object.currency`部分を取得して変数に格納
  - customer_name: ②のレスポンスから`body.name`部分を取得して変数に格納
  - customer_email: ②のレスポンスから`body.email`部分を取得して変数に格納
- Templateブロックで、上記で取得した変数を元にSlackメッセージ本文を作成。作成されたメッセージはOutput部分に表示される。また、その内容はOutput部分と接続されたDisplayブロックでメッセージ内容が表示される
- Send Requestブロックで、Templateブロックで作成された文字列をmessageという名前の変数に格納
- Send Requestブロックで、Slack通知用のAPIにリクエストを送信。このAPIリクエスト設定は、Slack通知用 コレクションの中で設定しているものを指定。このコレクションのAPIリクエスト設定の中で、上記で取得したmessage変数を参照。また、Send RequestブロックではSlack通知に必要なWebhook URL情報を格納している環境変数を指定
 
上記で解説の中で登場するPostman Flowsの各ブロックについて、詳しくは次の記事が参考になります。

https://qiita.com/nagix/items/2ebedd0273e7eb13c2cf



# 実行手順

ここでは、Stripeをテストモードで実行します。Stripe API利用に必要な[APIキー](https://docs.stripe.com/keys)が事前に取得済みであることを前提とします。また、Stripe APIへのリクエスト送信に関して、Postmanを活用して解説します。

## 事前準備

### Stripe API用の公式Postmanコレクションと環境変数をフォーク

Stripe公式のPostman[ワークスペース](https://www.postman.com/stripedev/stripe-developers)にあるStriep APIコレクションを自分の作業用のパーソナルワークスペース（自分しかアクセスできない）にフォークします。ここでは、2024年12月現在で最新のコレクション ([Stripe API [2024-04-10]](https://www.postman.com/stripedev/stripe-developers/collection/v4lose6/stripe-api-2024-04-10
))をフォークします。

![Screenshot 2024-12-18 at 15.42.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103420/505e47f4-af63-0133-c673-d6d8468f9e61.png)

また、同様にStripe公式ワークスペースにある[環境](https://www.postman.com/stripedev/stripe-developers/environment/665823-fd03c411-50c3-4d60-81fa-1820e820eeb3)もフォークします。

![Screenshot 2024-12-18 at 15.49.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103420/f74e51c3-7419-5dc0-41aa-d78887ff968f.png)

### Stripe APIコレクションの認可設定

上記でフォークした環境の`secret_key`変数の初期値と現在値の両方にStripe APIキーを設定します。

![Screenshot 2024-12-18 at 15.54.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103420/4abb46ee-10f7-132e-ec32-c0edc851ccf1.png)

次に、Stripe APIコレクションに上記で設定した環境を右上の箇所で指定します。そして、Stripe APIコレクションの認可設定に環境変数`{{secret_key}}`を設定します。これで同コレクション共通のAPI認可設定が完了です。

![Screenshot 2024-12-18 at 17.16.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103420/b27b3835-7c0c-8452-8a8f-5bbe7b034728.png)


### Stripe APIでCustomerを作成

フォークしたStripe APIコレクションの`Customer - Create Customer` API ([API詳細](https://docs.stripe.com/api/customers/create))を実行します。まずは、上記で設定した環境を右上の箇所で指定します。ボディに下記プロパティを入力して送信します。これでCustomerが作成されます。

- email
- name

作成された、CustomerのIDは`customerId`という名前のコレクション変数に格納されます。以後、Customer IDは、`{{customerId}}`で参照できます。

![Screenshot 2024-12-18 at 15.59.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103420/20b29b71-e144-2665-0e1c-d13aede8d034.png)

これで準備完了です。

## 決済ワークフローの実行

次の流れで決済ワークフローを実行していきます。

### 1. Stripe APIでPayment linkを作成

フォークしたStripe APIコレクションの`Checkout - Create Session` API ([API詳細](https://docs.stripe.com/api/checkout/sessions/create))を実行して、Payment linkを作成します。Customer作成と同様に、Stripe用の環境を右上の箇所で指定します。ボディに下記プロパティを入力して送信します。

- customer: Customer IDを入れる。既にcustomerId変数がされているはずなので、`{{customerId}}`でOK 
- line_items[0][price_data][currency]: `JPY`
- line_items[0][price_data][product]: もし既にProductIDがあればそれを入力。なければ`line_items[0][price_data][product_data][name]`に任意の購入対象プロダクトの名前をいれる
- line_items[0][price_data][product_data][name]: 金額
- line_items[0][quantity]: 購入数
- payment_method_types[0]: `card`
- mode: `payment`
    
![Screenshot 2024-12-18 at 16.14.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103420/d73b65df-06ae-d995-b6cf-5ae4cc9d3008.png)


APIリクエストが無事成功すると、レスポンスボディのurlプロパティがpayment linkとなる。リンクをクリックすると、次のようなページが表示されます。

![Screenshot 2024-12-19 at 11.08.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103420/a7e6f58c-ba5a-1a84-0e3f-7a6576fdd067.png)


### 2. Stripe CLIでWebhook用イベントListenの設定

次のように、Stripe CLIでログインしてからWebhook用イベントListenの設定をします。ここでは、イベントを`payment_intent.succeeded`に限定します。

```sh
# ログイン
stripe login
# なお、APIキーを指定してログインも可能
# stripe login --api-key ＜APIキー＞

# イベントを絞ってListen
stripe listen --events payment_intent.succeeded \
  --forward-to ＜PostmanフローのWebhook URL>
```

### 3. Payment linkページで支払処理実行

1のPayment linkページでカード情報など必要な情報を入力して、Payボタンをクリックします。問題なければこれで支払処理が完了して、2で指定したURLに`payment_intent.succeeded`のイベントが送信されます。

2のコンソールを見ると次のような出力が確認できるはずです。

![Screenshot 2024-12-18 at 16.26.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103420/e496febe-c9b9-3774-7236-e61bdf24ff1c.png)

そして、無事Postmanフローにてイベント処理が実行されると次のようなSlackが送信されます :tada: 

![Screenshot 2024-12-18 at 11.09.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103420/15c2b91a-cfef-c4ec-cf45-d9b051417a20.png)

# さいごに

StripeとPostman Flowsを活用したローコードの決済ワークフローを紹介しました。Stripeの柔軟なAPIとPostman Flowsの視覚的な操作を組み合わせることで、簡単かつ効率的に決済フローを実現できます。ぜひ皆さんも試してみてください！