Stripe Payment Linksの参照IDとWebhookで、顧客の注文を追跡可能にする方法 （LINEとの連携サンプル付）

Stripe Payment Linksを利用した支払いリンクでは、コードを書くことなく決済ページを作成・埋め込みすることができます。

https://stripe.com/jp/payments/payment-links

その一方で、１つのURLから複数の注文を受け付けるため、「どの顧客からの注文か」を特定する方法が限定される問題も存在します。

この記事では、LINEやBubbleなどのシステムのユーザー情報と支払いのセッションを紐づける方法の１つとして、「**URLに参照IDを設定する方法**」を紹介します。

## Payment Linksの参照IDとは？

Payment Linksで発行した支払いリンクのURLには、クエリ文字列を追加できます。

サポートしている文字列のうち、`client_reference_id`を利用することで、注文内容を参照しやすくできます。

## URLに`client_reference_id`を設定する

参照IDの設定方法はとても簡単です。

`?client_reference_id=任意の文字列`と設定しましょう。
`https://buy.stripe.com/test_xxxxx?client_reference_id=id_1234`

複数のクエリを設定する場合は、`&`でつなぎます。
`https://buy.stripe.com/test_xxxxx??prefilled_email=jenny%40example.com&client_reference_id=id_1234`

このURLを顧客がアクセスすると、WebhookやAPIから受け取る値に`client_reference_id`が追加されます。

### 利用可能な文字列
「**英数字・ダッシュ(`-`)・アンダースコア(`_`)**」で「**200文字以内**」が利用可能です。

以下の例では、`client_reference_id`は認識されませんのでご注意ください。

- 200文字より多い例
`https://buy.stripe.com/test_xxxx?client_reference_id=Loremipsumdolorsitamet_consecteturadipisicingelit_seddoeiusmodtemporincididuntutlaboreetdoloremagnaaliqua-Utenimadminimveniam_quisnostrudexercitationullamcolaborisnisiutaliquipexeacommodoconsequat-Duisauteiruredolorinreprehenderitinvoluptatevelitessecillumdoloreeufugiatnullapariatur-Excepteursintoccaecatcupidatatnonproident_suntinculpaqu`
- 日本語など、サポートしていない文字列を含む例
`https://buy.stripe.com/test_xxxx?client_reference_id=test_日本語のテキスト`


## 設定した`client_reference_id`を取得する

設定した`client_reference_id`はシステム側で利用します。
今回はWebhookのイベントで取得するケースと、APIを利用して取得するケースを紹介します。

### Webhookで取得する

Webhookは、`checkout.session.completed`や`checkout.session.async_payment_succeeded`などの`checkout.session.xxx`イベントで取得できます。

*コンビニ決済など、「その場で決済が完了しない支払い」では`checkout.session.async_payment_succeeded`イベントを処理する必要がある点に注意しましょう。

```js
const clientReferenceId = event.data.object.client_reference_id
```

複数の支払いリンクを利用する場合などを考慮すると、`client_reference_id`が`null`になるケースも考慮が必要です。

```js
const clientReferenceId = event.data.object.client_reference_id
if (clientReferenceId) {
  // ここに処理を書く
}
```

作成した支払いリンクのIDで分岐することも可能です。ただしこの場合、テスト・本番両環境のIDをサポートする必要があります。

```js
if (['plink_test', 'plink_prod'].includes(event.data.object.payment_link)) {
  const clientReferenceId = event.data.object.client_reference_id
}
```

### Stripe APIで取得する

Webhookを利用せずにデータを取得したい場合、Stripe APIを利用します。

```js
const Stripe = require('stripe')

const stripe = new Stripe(process.env.STRIPE_API_KEY, {
  apiVersion: '2020-08-27'
})

stripe.checkout.sessions.retrieve('cs_test_xxxxxx')
.then(data => {
  console.log(data.client_reference_id)
})
```


## 実装例: LIFFでLINEのUser IDを取得し、参照IDとして利用する



組み込みの例として、LIFFで利用する方法を紹介します。

以下のコードでは、[LIFFのSDK](https://www.npmjs.com/package/@line/liff)を利用してLINEのユーザーIDを取得しています。

```js
    liff.init({
      liffId: import.meta.env.LIFF_ID,
    }).then(() => {
      // ログインしていない
      if (!liff.isLoggedIn()) {
        return liff.login()
      }

      return liff.getProfile()
        .then(profile => {
          window.open(`https://buy.stripe.com/test_xxxxx?client_reference_id=${profile.userId}`)
        })
    }).catch(e => {
      console.log(e)
    })
```

Webhook側で[bot-sdk](https://www.npmjs.com/package/@line/bot-sdk)を利用すると、「どのLINEユーザーが注文したか」をシステムが把握できます。

```js
    if (event.type === 'checkout.session.completed' && event.data.client_reference_id) {
      const line = require('@line/bot-sdk');
      const client = new line.Client({
        channelSecret: '*****',
        channelAccessToken: '*****'
      });
      const profile = await client.getProfile(event.data.client_reference_id);
    }
```

こちらは未検証ですが、以下のようにLINEで注文内容を通知するなどの実装も理論上可能です。

```js
  if (
    event.type !== 'checkout.session.completed' &&
    event.type !== 'checkout.session.async_payment_succeeded'
  ) {
    return response.status(200).end();
  }

  if (event.data.client_reference_id) {
    const items = await stripe.checkout.sessions.listLineItems(event.data.id);
    const line = require('@line/bot-sdk');
    const client = new line.Client({
      channelSecret: '*****',
      channelAccessToken: '*****'
    });
    client.pushMessage(event.data.client_reference_id, {
      type: 'text',
      text: [
        '注文内容',
        items.data.map(item => `${item.description} * ${item.quantity}`)
      ].join(','),
    })
  }
```

## おわりに

参照ID(`client_reference_id`)を利用することで、Payment Linksをシステムにより深く連携させることができます。

今回のサンプルではLINEでしたが、「どのSNSからの注文が多いか」などの計測にも利用できるかと思います。

ぜひ様々な利用法をお試しの上、Qiitaなどにシェアしてください。

## 参考ドキュメント
https://stripe.com/docs/payments/payment-links#url-parameters