Stripe Checkoutで簡単な通販ページを作った話

この記事は、[マイナビ Advent Calendar 2019](https://qiita.com/advent-calendar/2019/mynavi) 24日目の記事です。
アドベントカレンダー2本目は、様々な決済プラットフォームの中からStripe Checkoutを使って通販ページを作成した話をします。実装の話だけ読みたい方は[こちら](https://qiita.com/hidetom/private/612b28334a3df81955d5#%E5%AE%9F%E8%A3%85)。

# 背景
最近、友人と一緒に同人誌を作りました。
[大阪の社会主義的な風景を映し出した写真集『OSAKAN SOCIALISM』](https://osakansocialism.h1den.com/)
即売会や書店で売るだけでなく通販もやってみたいよねという話で盛り上がり、色々と決済の方法を検討してみました。

# 比較検討
通販をするにあたって、まずはいくつかの決済プラットフォームの比較を行いました。月間決済回数100件以下、決済単価1500円程度を想定。選定基準は、`1.画面遷移が少ないこと 2.手数料が安く、料金体系がシンプルであること 3.準備（≒実装）が容易であること`の3点です。
事前に調べて良さそうだったのは、PayPal、PAY.JP、Stripeの3サービスでした。BASEやSTORES.jpのようなオンラインストアの利用も考えましたが、なるべくシンプルな動線を実現したいと思ったので、今回は候補から外しています（取扱商品が増えたら検討したいです）。

|  | PayPal | PAY.JP | Stripe |
| :--- | :---: | :---: | :---: |
| 画面遷移 | 5ステップ | 3ステップ | 2ステップ |
| 手数料 | 3.6％+40円 | 3.0％ | 3.6％ |
| 準備 | ◎ | ○ | ○ |


## PayPal
決済手数料は商品価格の3.6％+40円、少額決済（1回の取引あたり2,357円以下）の申請をすると5％+7円と、他2サービスに比べて割高。
PayPalはさまざまなサービスを展開していますが、今回は最もスタンダードな[ウェブペイメントスタンダード](https://www.paypal.com/jp/webapps/mpp/merchant/solutions/paypal-button)を検討しました。画面遷移は最低5ステップ。動線を短縮できる[ページ埋め込み](https://www.paypal.com/jp/webapps/mpp/developer/wpp)も用意されていますが、別途利用料と審査が必要だったので今回は導入を見送りました。

```
自サイト→PayPalで会員登録（中で2,3ステップ）→PayPal決済画面→確認画面→支払い完了
```

準備は3ステップ。価格や商品名などの入力項目を埋めるとコードが生成されるので、ほとんど実装の必要はありません。

```
ビジネスアカウント登録→決済ボタンの作成→HTML内へ埋込
```
[- 決済ボタンの作成方法｜開発者向け-PayPal(ペイパル)](https://www.paypal.com/jp/webapps/mpp/developer/paypal-button/integration)

## PAY.JP
決済手数料は商品価格の3.0％と今回比較するサービスの中でもっとも安価です。
PAY.JPの中でも導入コストが低く、画面遷移を少なくできる[Checkout](https://pay.jp/docs/checkout)を検討しました。ですが、さらに調査した結果、Checkoutには配送先住所など住所に関わるパラメータが用意されておらず、決済前後に住所の入力ページが必要なようだったので、こちらも導入を見送りました。

```
自サイト内のフォームで顧客情報を入力→自サイト内でカード情報を入力→決済完了
```
ちなみに準備は2ステップ。アカウント登録をしてHTML内にコードを埋め込めば、基本はOK。

```
アカウント登録→コードを生成してHTML内へ埋込
```

## Stripe
決済手数料は商品価格の3.6%、料金体系もシンプルで分かりやすいです。
[- Stripe: 料金体系 | 日本](https://stripe.com/jp/pricing?utm_campaign=paid_brand-JP_ja_Search_Brand_Stripe-1608207349&utm_medium=cpc&utm_source=google&ad_content=394124470280&utm_term=stripe%20%E6%B1%BA%E6%B8%88%E6%89%8B%E6%95%B0%E6%96%99&utm_matchtype=e&utm_adposition=1t1&utm_device=c&gclid=EAIaIQobChMI0fGjhaiJ5gIVyGkqCh221ggPEAAYASABEgJXcfD_BwE#pricing-details)
動線をもっとも短くできる[Stripe Checkout](https://stripe.com/jp/payments/checkout)を検討しました。画面遷移は2ステップ。PAY.JP Checkoutと異なり、`stripeShippingAddress`という住所に関するパタメータが用意されています。

```
自サイト内で住所とカード情報を入力→決済完了
```

準備は3ステップ。ドキュメントやライブラリが十分に整備されているので、ハードルは高くありません。ただ、今回は諸事情からCheckoutのlegacy versionを採用したので、サーバー側の決済処理の実装があり何度か嵌りました。なお、new versionではサーバー側の実装が必要ないようです。

```
アカウント登録→クライアント側のコードを生成してHTML内へ埋込→サーバー側の実装
```

ということで、画面遷移が他サービスよりも少ない点、手数料や実装コストを踏まえて、Stripe Checkoutを導入することにしました。

# 実装
- [公式ドキュメント(legacy-checkout)](https://stripe.com/docs/legacy-checkout)
- [APIリファレンス](https://stripe.com/docs/api)
- [ライブラリ](https://github.com/stripe/stripe-php)

さっそくフォームの埋め込みから。

```html
<form action="./checkout.php" method="POST">
  <script src="https://checkout.stripe.com/checkout.js"
  class="stripe-button"
  data-key="pk_test_xxxxxxxxxxxxxxx"
  data-amount="7777"
  data-description="OSAKAN SOCIALISM"
  data-image="https://osakansocialism.h1den.com/images/favicon.png"
  data-locale="ja"
  data-currency="jpy"
  data-shippingAddress="true"
  data-zip-code="true"
  data-allow-remember-me="false"
  data-label="WEBでの購入">
  </script>
</form>
```

HTML内に上記のコードを埋め込んで決済を走らせてみたら、決済がダッシュボードに反映されず…どうやらトークンがStripeに飛んでいるだけのようです。

> あくまでCheckoutを用いたフォーム部分だけの話で、そこで得たトークン情報を使ってSDKつないで支払い処理するのは別の話のようでした。
[JavaScript - Stripe Checkoutでテスト決済が通らない｜teratail](https://teratail.com/questions/124038)

実はこの時まで、てっきりHTMLの埋め込みだけで動くものと思い込んでました… 既に上では書きましたが、Stripe Checkoutは”legacy”と”new”の2バージョンがあり、legacyではサーバー側の実装が[別途必要](https://stripe.com/docs/legacy-checkout)です。
気を取り直して、ここからは公式ドキュメントを参照しながらバックエンドの実装をPHPでやっていきます。

まずは[Composerを導入](https://getcomposer.org/)。その後、StripeのPHP向けのライブラリをインストール。

```terminal
$ composer require stripe/stripe-php
```

ライブラリがインストールできたら、checkout.phpを実装していく。

```php

ini_set( 'display_errors', 1 );
ini_set( 'error_reporting', E_ALL );

require_once( dirname(__FILE__).'/stripe/init.php');
\Stripe\Stripe::setApiKey("sk_test_xxxxxxxxxxxxxxx");

$token = $_POST['stripeToken'];
$email = $_POST['stripeEmail'];

$customer = \Stripe\Customer::create([
    'email' => $email,
    'source'  => $token,
]);

$charge = \Stripe\Charge::create([
  'customer' => $customer->id,
  'amount'   => 7777,
  'currency' => 'jpy',
  'description' => "OSAKAN SOCIALISM",
]);

header('Location: https://osakansocialism.h1den.com/');
exit;
```

こんな感じ。`$customer`で顧客が、`$charge`で決済が作成されます。

途中、上のドキュメントの存在に気づかず実装してて、領収書が送れず嵌りましたが、最後はちゃんと送れるようになりました。良かった…
![スクリーンショット 2019-11-27 14.24.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536692/cdd13469-1874-f34a-9f6f-b542bcee1c9c.png)
こんな感じ。

![スクリーンショット 2019-11-27 17.30.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536692/59eb3a41-5c91-50f5-4b2e-0b8c4dea2634.png)
ダッシュボードの開発者ログでは、トークンの送信、顧客の作成、請求が正常に行われている様子が見れます。

そして実際はこういう動きをします。よさそう！
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536692/5443f256-676a-1459-5a98-f01976fbad59.gif" width=960>

# まとめ
途中、自分の理解不足による嵌りもありましたが、総じてスムーズに導入することができました。上で挙げたメリットのほかに、管理画面が使いやすかったり、定期支払いやクーポンの適用に対応していたりと良い感じなので、個人で制作活動をしている方は、オンラインストアと並行して導入検討してみてはいかがでしょうか。

# 謝辞
[nagaramen](https://github.com/nagaramen/)、ありがとうございました。途中でいろいろと無茶言ってすいませんでした…