Article

Stripe API連携の進め方|決済・Webhook・セキュリティ設計の基本を解説

Webサービスにクレジットカード決済や月額課金を導入するとき、有力な選択肢の一つがStripeです。

Stripe APIを利用すると、

  • 商品購入
  • サービス利用料の決済
  • 月額・年額のサブスクリプション
  • 支払い方法の保存
  • 請求管理
  • 返金

などをWebシステムへ組み込めます。

一方で、Stripe API連携は単純に、

「決済ボタンを押す」

「Stripe APIを呼ぶ」

「成功なら注文完了」

と実装すればよいものではありません。

実際には、

  • 決済処理はどこで行うのか
  • 金額をどこで確定するのか
  • 決済成功をどう判定するのか
  • Webhookをどう処理するのか
  • 同じ決済が2回実行されないか
  • カード決済に失敗したらどうするのか
  • APIキーをどう管理するのか
  • Stripeと自社DBの状態がずれたらどうするのか

まで設計する必要があります。

結論からいうと、Stripe API連携で重要なのは、画面上の「決済完了」だけを信用せず、サーバー側とWebhookを含めて決済状態を管理することです。

この記事では、Stripe APIを利用してWebサービスへ決済機能を安全に組み込むための基本設計から、Webhook、二重決済対策、テスト、本番運用まで分かりやすく解説します。

Stripe API連携とは

Stripe API連携とは、自社のWebシステムからStripeが提供するAPIを利用し、決済や顧客・契約情報などを管理する仕組みです。

例えばオンラインサービスで10,000円の商品を販売するとします。

概念的には、

ユーザー

商品を購入

自社Webシステム

Stripe

カード決済

決済結果

自社Webシステムで注文確定

という流れです。

自社でカード番号を直接処理するのではなく、Stripeが提供する決済機能を利用します。

そのため、ゼロから決済基盤を開発するよりも、決済機能をWebサービスへ組み込みやすくなります。

ただし、Stripeを利用すれば自社側で設計が不要になるわけではありません。

自社システムでは、

「Stripe上の決済」

と、

「自社サービス上の注文・契約」

を正しく紐付ける必要があります。

Stripe連携では自社システムとStripeの役割を分ける

Stripe API連携を理解するときは、

自社システム

  • ユーザー
  • 商品
  • 注文
  • 契約
  • 利用権限
  • サービス提供状況

Stripe

  • 決済処理
  • 支払い方法
  • Stripe上の顧客
  • PaymentIntent
  • Subscription
  • Invoice

というように役割を分けて考えると分かりやすくなります。

例えば商品購入なら、

自社注文ID:ORDER-12345

Stripe PaymentIntent ID:pi_xxxxx

のように紐付けます。

これにより、

「Stripe上では支払い済みだが、どの注文の支払いか分からない」

という状態を避けやすくなります。

Stripe API連携の代表的な方法

Stripeで決済画面を実装する方法は一つではありません。

Webサービスの要件に応じて選択します。

代表的には、

  • Stripe Checkout
  • Stripe Elements / Payment Element
  • PaymentIntents API

などがあります。

Stripe Checkout

Stripeが用意する決済フローを利用する方法です。

例えば、

商品ページ

購入ボタン

Stripeの決済画面

決済

自社サービスへ戻る

という流れを作れます。

自社で決済UIを細かく作り込む必要が少ないため、

「まず安全にオンライン決済を導入したい」

という場合に検討しやすい方法です。

Payment Elementなどを利用する方法

自社Webサービスの画面内へ決済フォームを組み込みたい場合は、Stripeが提供するUIコンポーネントを利用する方法があります。

例えば、

商品確認

同じ画面内で支払い方法を入力

決済

注文完了

というUIを作れます。

決済体験を自社サービスへより自然に組み込みたい場合に向いています。

PaymentIntentとは

Stripe決済を理解するときに重要なのがPaymentIntentです。

PaymentIntentは、一つの支払い処理の状態を管理するためのオブジェクトです。

例えば10,000円の注文について、

支払い処理開始

認証が必要

ユーザー認証

決済成功

と状態が変化する場合があります。

単純な、

paid = true / false

ではなく、決済処理自体に状態があると考えると分かりやすいでしょう。

3Dセキュアなど追加認証が必要になるケースもあるため、決済状態を正しく確認してサービス側の注文状態へ反映する必要があります。

Stripe API連携の基本的な処理フロー

例えば単発決済のWebサービスなら、概念的には次のような流れになります。

  1. ユーザーが商品を選択
  2. 自社サーバーで注文を作成
  3. 自社サーバーからStripeへ決済処理を作成
  4. ユーザーが決済
  5. Stripe側で決済処理
  6. Webhookを受信
  7. 自社DBの注文を支払い済みに変更
  8. 商品・サービスを提供

ポイントは、決済成功後に自社サービス側の状態も更新する必要があることです。

Stripeで決済が完了していても、自社DBの注文が「未払い」のままではシステムとして整合していません。

Stripe API連携のポイント1.金額はサーバー側で確定する

決済システムで特に注意したいのが金額です。

例えばブラウザから、

amount = 10000

を送信し、その値をそのままStripeへ渡す設計を考えてみましょう。

ユーザーがブラウザ上の通信内容を変更し、

amount = 100

として送信できてしまう設計では問題があります。

そのため、

商品ID:PRODUCT-001

サーバー側で商品情報を取得

DBに登録された価格を確認

10,000円を決済

という流れにします。

つまり、

「いくら請求するか」は信頼できるサーバー側のデータから決定する

ことが重要です。

Stripe API連携のポイント2.Secret Keyをフロントエンドへ出さない

StripeではAPIキーを利用してAPIへアクセスします。

ここで重要なのが、クライアント側で利用できるキーと、サーバー側で厳重に管理すべきキーを区別することです。

Secret Keyを、

  • JavaScriptへ直接記述する
  • GitHubへコミットする
  • HTMLへ埋め込む
  • フロントエンド用の環境変数として公開する

といった状態にしてはいけません。

サーバー側の環境変数やシークレット管理サービスなどで管理します。

概念的には、

ブラウザ

自社バックエンド

Secret Keyを利用

Stripe API

という構成です。

機密性の高いAPIキーをブラウザへ渡さないことが基本です。

Stripe API連携のポイント3.決済完了画面だけを信用しない

Stripe連携で特に避けたいのが、

「決済完了ページへ遷移したから注文を支払い済みにする」

という設計です。

例えば、

/payment/success

へアクセスしただけで、

order.status = “paid”

になる設計では問題があります。

ユーザーがURLへ直接アクセスする可能性があるからです。

また、

決済自体は成功した

完了画面へ戻る途中で通信が切れた

というケースもあります。

そこで、最終的な決済状態はStripe側の情報やWebhookを利用してサーバー側で確認します。

Stripe API連携のポイント4.Webhookを利用する

Stripe API連携ではWebhookが重要です。

Webhookとは、Stripe側でイベントが発生したときに、自社システムへ通知を送ってもらう仕組みです。

例えば、

ユーザー

Stripeで決済

Stripe

決済成功

Stripe

Webhook

自社システム

注文を支払い済みに変更

という流れです。

Webhookを利用すると、ユーザーが決済完了後にブラウザを閉じても、自社システム側で決済結果を処理できます。

Webhookで処理するイベントを整理する

どのイベントを処理するかはサービスによって異なります。

例えば、

単発決済

  • 決済成功
  • 決済失敗

サブスクリプション

  • 契約開始
  • 請求成功
  • 請求失敗
  • 契約変更
  • 契約終了

などです。

すべてのStripeイベントを処理する必要はありません。

自社サービスの業務フローに必要なイベントを整理します。

Stripe API連携のポイント5.Webhookの署名を検証する

Webhook用のURLを公開すると、Stripe以外からHTTPリクエストを送信される可能性があります。

そのため、

「Webhook URLへリクエストが来たからStripeからの通知だろう」

と信用してはいけません。

Stripeから送られてきたWebhookであることを署名検証によって確認します。

署名検証に成功したイベントだけを処理することで、第三者による偽の決済成功通知などを防ぎます。

Stripe API連携のポイント6.Webhookの重複処理を防ぐ

Webhookは同じイベントを複数回受信する可能性を考慮して設計します。

例えば、

決済成功イベント

1回目受信

注文を支払い済みにする

その後、

同じイベント

2回目受信

となるケースです。

単純な注文状態変更なら問題が目立たないかもしれません。

しかし、

決済成功

ポイント10,000ポイント付与

という処理なら、

同じイベントを2回処理

20,000ポイント付与

となる可能性があります。

そこで、

event_id

処理済みか確認

未処理なら実行

処理済みならスキップ

という設計を行います。

Stripe API連携のポイント7.Webhookの順番に依存しすぎない

Webhookでは、複数のイベントが必ず業務上期待した順番で到着するとは限らないことも考慮します。

例えばサブスクリプション処理で、

契約作成

請求作成

支払い完了

というイベントが発生しても、自社側が必ずその順番で受信する前提にすると不具合の原因になる可能性があります。

必要に応じてStripe APIから最新状態を取得し、

「現在のStripe上の状態はどうなっているか」

を確認できる設計にしておくと安全です。

Stripe API連携のポイント8.Webhookでは重い処理を同期実行しすぎない

Webhookを受信したあとに、

決済成功

PDF作成

メール送信

会計システム連携

在庫更新

Webhookへレスポンス

という処理をすべて同期的に行うと、レスポンスまで時間がかかる場合があります。

例えば、

Webhook受信

署名検証

イベント保存

正常レスポンス

バックグラウンド処理

という形にする方法があります。

特に処理量が多い場合は、キューなどを利用して非同期処理する設計を検討します。

Stripe API連携のポイント9.二重決済を防ぐ

決済処理では、同じ購入に対して複数の決済を作らないことが重要です。

例えばユーザーが、

「購入する」

ボタンを連続で2回押したとします。

1回目

決済開始

2回目

もう一度決済開始

となれば、二重決済につながる可能性があります。

対策として、

  • ボタンの連打防止
  • 注文IDによる処理管理
  • PaymentIntentの再利用
  • Idempotency Keyの利用

などを検討します。

Idempotency Keyとは

Idempotency Keyは、同じ操作が重複実行されることを防ぐために利用できる仕組みです。

例えば、

注文ID:ORDER-12345

を基に一意なキーを設定し、同じ注文に対するAPIリクエストを重複処理しないようにします。

ただし、Idempotency Keyを利用すればシステム全体の重複処理対策が不要になるわけではありません。

自社DB側でも、

注文

決済

サービス提供

という一連の処理に対して冪等性を考えることが重要です。

Stripe API連携のポイント10.自社の注文状態と決済状態を分ける

例えば注文テーブルに、

status = paid

だけを持たせる設計では、状態管理が難しくなる場合があります。

実際には、

注文状態

  • 作成済み
  • 処理中
  • 完了
  • キャンセル

決済状態

  • 未決済
  • 決済処理中
  • 支払い済み
  • 決済失敗
  • 返金済み

を分けて考えたほうがよいケースがあります。

例えば、

支払いは成功

商品発送はまだ

という状態があります。

決済と業務処理を同じステータスだけで管理すると、複雑になりやすくなります。

Stripe API連携のポイント11.Stripe IDを自社DBへ保存する

Stripeでは、

  • Customer ID
  • PaymentIntent ID
  • Subscription ID
  • Invoice ID

などのIDが発行されます。

これらを必要に応じて自社DBへ保存しておくと、後からStripe上のデータと照合しやすくなります。

例えば、

orders

  • id
  • user_id
  • amount
  • payment_status
  • stripe_payment_intent_id

という構成です。

問い合わせ対応でも、

「自社の注文12345はStripeのどの決済か」

を特定しやすくなります。

Stripeのmetadataも活用できる

逆にStripe側のオブジェクトへ、

order_id

tenant_id

など、自社システム上の識別情報をmetadataとして設定する方法もあります。

例えば、

自社注文ID:ORDER-12345

をStripe側にも紐付けておけば、Stripe Dashboardから該当注文を探しやすくなります。

ただし、metadataへカード情報などの機密情報や不要な個人情報を保存しないよう注意します。

Stripe API連携のポイント12.カード情報を自社サーバーで直接扱わない

カード番号、

有効期限、

セキュリティコード

などを自社サーバーへ直接送信・保存する設計は、決済セキュリティ上の責任範囲を大きくする可能性があります。

Stripe CheckoutやStripeが提供する決済コンポーネントを利用し、自社サーバーがカード情報そのものを直接保持しない構成を検討します。

特に、

「カード番号を自社DBへ保存する」

といった独自実装は避けるべきです。

Stripe API連携のポイント13.決済失敗を正常な業務フローとして設計する

カード決済は必ず成功するわけではありません。

例えば、

  • 利用限度額
  • 有効期限切れ
  • カード停止
  • 認証失敗
  • 処理エラー

などによって失敗する可能性があります。

そのため、

決済開始

成功

注文完了

だけでなく、

決済開始

失敗

エラー表示

別の支払い方法を案内

という流れを用意します。

決済失敗は「想定外の障害」ではなく、通常発生しうる業務状態として設計することが重要です。

3Dセキュアなど追加認証も考慮する

カード決済によっては、ユーザーが追加認証を求められる場合があります。

そのため、

カード入力

即決済成功

だけを想定せず、

カード入力

追加認証

認証成功

決済完了

というフローにも対応できる構成が必要です。

PaymentIntentなどの状態を正しく扱う理由の一つです。

Stripe API連携でサブスクを実装する場合

月額・年額課金では、単発決済よりさらに状態管理が増えます。

例えば、

ユーザー

プラン選択

StripeでSubscription作成

初回決済

サービス利用開始

毎月自動更新

という流れです。

考える必要があるのは、

  • 契約開始
  • 自動更新
  • プラン変更
  • 支払い失敗
  • 再決済
  • 解約予約
  • 契約終了

などです。

StripeのSubscriptionと自社サービスの契約を分ける

サブスクリプションでも、

Stripe上のSubscription

と、

自社Webサービス上の契約状態

を分けて考えると設計しやすくなります。

例えば自社DBに、

subscriptions

  • id
  • tenant_id
  • plan_id
  • status
  • stripe_subscription_id
  • current_period_end

などを管理します。

Stripe側の状態をWebhookなどで自社DBへ反映します。

支払い失敗時に即利用停止するとは限らない

月額課金でカード決済に失敗した場合、

支払い失敗

即サービス停止

とするか、

支払い失敗

ユーザーへ通知

一定期間は利用可能

再決済

失敗が続けば停止

とするかはサービス設計によって異なります。

Stripe側の設定だけでなく、自社サービスとして、

「どの状態なら何の機能を利用できるのか」

を整理する必要があります。

Stripe API連携で返金をどう扱うか

決済後にキャンセルが発生するサービスでは、返金処理も設計します。

例えば、

注文キャンセル

返金申請

Stripeで返金

自社DBの返金状態更新

という流れです。

ここでも、

注文キャンセル

と、

返金完了

は同じタイミングとは限りません。

例えば、

order_status = canceled

payment_status = refund_pending

のように分けて管理する方法があります。

Stripe API連携のエラーハンドリング

Stripe APIを呼び出すときは、

「失敗したら500エラーを表示する」

だけでは不十分です。

例えば、

  • 入力エラー
  • カード決済失敗
  • 認証エラー
  • API通信エラー
  • 一時的なStripe側エラー

など、原因によって対応が異なります。

ユーザー入力・カード関連

ユーザーへ内容を伝え、修正や別のカードを案内する。

一時的な通信障害

再試行を検討する。

APIキーなどの設定ミス

管理者へ通知する。

というように整理します。

APIエラーをそのまま利用者へ見せない

バックエンドの詳細なエラーメッセージや内部情報を、そのまま一般ユーザーへ表示する必要はありません。

例えばユーザーには、

「決済を完了できませんでした。支払い方法をご確認ください。」

など必要な情報を表示します。

一方、管理者向けログには、

  • Stripe上のオブジェクトID
  • エラー種別
  • 処理日時
  • 自社注文ID

など、調査に必要な情報を残します。

Stripe API連携のテスト方法

決済機能は、本番環境でいきなり確認するのではなくテスト環境を利用します。

Stripeではテスト用のAPIキーやテスト用支払い情報を利用し、実際のお金を動かさずに決済フローを確認できます。

確認したいのは、単純な決済成功だけではありません。

正常系

  • 通常決済が成功する
  • 正しい金額になる
  • 注文とStripe決済が紐付く
  • Webhookを受信する
  • 注文が支払い済みになる

決済失敗

  • カード拒否
  • 残高・利用枠不足相当
  • 有効期限関連
  • CVC関連
  • 認証失敗

Webhook

  • 正常受信
  • 署名不正
  • 同一イベントの重複
  • イベント順序が変わる
  • 処理中にエラーになる

操作

  • 決済ボタンを連打する
  • 決済途中でブラウザを閉じる
  • 決済完了後に戻るボタンを押す
  • 成功ページへ直接アクセスする

こうした異常系まで確認します。

本番環境とテスト環境を混在させない

Stripe連携ではテスト用と本番用の設定を明確に分けます。

例えば環境変数として、

開発環境

テスト用APIキー

本番環境

本番用APIキー

という形にします。

Webhookのエンドポイントシークレットなども環境ごとに管理します。

「テスト環境から本番決済を呼び出してしまう」といった事故を防ぐため、環境設定を整理することが重要です。

Webhookのローカル開発ではStripe CLIも利用できる

ローカルPC上で開発している場合、そのままではStripeからlocalhostへWebhookを送れません。

開発時にはStripe CLIなどを利用してイベントをローカル環境へ転送し、Webhook処理を確認する方法があります。

例えば、

Stripeイベント

Stripe CLI

localhostのWebhookエンドポイント

という構成です。

決済成功だけでなく、さまざまなイベントを発生させて確認できます。

Stripe API連携で用意したい管理画面

Stripeを導入すると、利用者向けの決済画面だけでなく運営者向け画面も重要になります。

例えば、

  • 注文一覧
  • 決済状態
  • Stripe PaymentIntent ID
  • 契約状態
  • 支払い失敗
  • 返金状態
  • Webhook処理状態

などです。

サービス開始後には、

「このユーザーの決済は成功していますか?」

「Stripeでは支払い済みなのに利用できません」

「返金処理は完了していますか?」

といった問い合わせが発生する可能性があります。

自社管理画面から状態を確認できると、運用負荷を減らしやすくなります。

Stripeと自社DBの不整合をどう検知するか

例えば、

Stripe
→ 決済成功

Webhook
→ 自社システムへの送信に失敗

自社DB
→ 未決済のまま

という状態が発生する可能性があります。

そのため、

  • Webhook再送
  • 定期的な整合性確認
  • 管理画面からの再同期
  • Stripe APIから最新状態取得

など、復旧手段も考えておくことが重要です。

「通常時に動くか」だけでなく、「ずれたときに戻せるか」が実運用では重要です。

【チェックリスト】Stripe API連携の要件整理

StripeをWebサービスへ組み込む前に、次の項目を整理してみてください。

決済方式

  • 単発決済:
  • 月額課金:
  • 年額課金:
  • 無料トライアル:
  • 請求書払いとの併用:

決済UI

  • Stripe Checkout:
  • 自社画面内に組み込む:
  • スマートフォン対応:

自社データ

  • 注文ID:
  • ユーザーID:
  • Stripe Customer ID:
  • PaymentIntent ID:
  • Subscription ID:

決済状態

  • 未決済:
  • 処理中:
  • 支払い済み:
  • 失敗:
  • 返金済み:

Webhook

  • 決済成功:
  • 決済失敗:
  • 契約開始:
  • 契約変更:
  • 契約終了:
  • 署名検証:
  • 重複防止:

異常系

  • カード決済失敗:
  • 3Dセキュア:
  • API通信エラー:
  • タイムアウト:
  • Webhook失敗:
  • 二重決済:

セキュリティ

  • Secret Key管理:
  • 本番・テスト環境分離:
  • 金額のサーバー側検証:
  • Webhook署名検証:
  • ログへの機密情報出力防止:

運用

  • 決済確認画面:
  • 返金:
  • 契約変更:
  • Webhook再処理:
  • 問い合わせ対応:
  • Stripeとのデータ照合:

Stripe API連携でよくある設計ミス

1.フロントエンドから送られた金額を信用する

ユーザー側で変更される可能性があります。

商品IDなどからサーバー側で正しい金額を確定しましょう。

2.決済完了ページを表示しただけで支払い済みにする

成功ページへ直接アクセスされる可能性があります。

Stripe側の決済状態をサーバー側で確認します。

3.Webhookの署名を確認しない

Webhook URLへStripe以外からリクエストされる可能性があります。

正しい署名を検証したイベントだけ処理します。

4.Webhookを1回しか来ない前提で作る

同じイベントを複数回受信しても二重処理にならない設計が必要です。

5.決済成功しかテストしない

本番ではカード拒否、追加認証、通信障害なども発生します。

異常系までテストしましょう。

6.Secret KeyをGitへコミットする

Secret Keyなどの機密情報はコードへ直接書かず、環境変数やシークレット管理機能を利用します。

7.Stripe側の状態だけを見て自社契約を管理する

Stripeは決済基盤ですが、自社サービスには独自の契約・利用権限があります。

決済状態とサービス利用状態を分けて設計することが重要です。

8.Webhook失敗後の復旧方法がない

決済は成功したのに自社DBだけ更新されていない場合に、再同期できる方法を考えておきます。

Stripe API連携に関するよくある質問

Stripe APIを使えばWebサイトにクレジットカード決済を追加できますか?

可能です。

Stripe Checkoutなどを利用する方法や、自社Webサービス内に決済UIを組み込む方法があります。

必要なデザイン・決済フロー・契約形態に応じて選択します。

Stripe CheckoutとPaymentIntentは何が違いますか?

Checkoutは決済画面を含む決済フローを構築しやすくする仕組みです。

PaymentIntentは支払い処理自体の状態を管理する重要なオブジェクトです。

利用するStripeの構成によって両者の関わり方は変わるため、サービス要件に合わせて公式ドキュメントを確認して設計します。

Stripe APIのSecret Keyをフロントエンドで使ってもよいですか?

Secret Keyはブラウザ側へ公開せず、サーバー側で安全に管理する必要があります。

フロントエンドで利用するキーとは役割を分けます。

Webhookは必須ですか?

サービス内容によりますが、決済結果やサブスクリプション状態を確実に自社システムへ反映するために重要な仕組みです。

ユーザーが決済後にブラウザを閉じる可能性もあるため、画面遷移だけに依存しない設計が適しています。

Stripeのテスト環境では実際に課金されますか?

テスト用APIキーとテスト用の支払い情報を利用することで、実際のお金を動かさずに決済フローを確認できます。

本番用とテスト用の設定を混在させないよう注意します。

Stripeで月額課金も実装できますか?

サブスクリプション機能を利用して月額・年額などの継続課金を構築できます。

ただし、自社サービス側でもプラン、契約状態、利用権限、解約などを設計する必要があります。

Stripeで決済が成功したらDBを更新すればよいですか?

基本的には自社側の注文・契約状態を更新する必要があります。

ただし、どのイベントを根拠に更新するか、Webhookが重複した場合にどうするか、更新失敗時にどう復旧するかまで設計することが重要です。

hiro-dev-labではStripe API連携を含むWebサービス開発から相談できます

Stripeを導入すると、決済処理そのものをゼロから構築する必要はありません。

一方で、自社Webサービス側では、

注文

決済

Webhook

契約

利用権限

返金・解約

まで一連の処理として設計する必要があります。

hiro-dev-labでは、Webシステム・Webサービス開発の観点から、

  • 決済要件のヒアリング
  • 要求整理
  • 要件定義
  • Stripe API連携
  • Stripe Checkoutを利用した決済導入
  • PaymentIntentを考慮した決済設計
  • Webhook設計
  • サブスクリプション設計
  • 料金プラン・契約管理
  • 認証・権限設計
  • データベース設計
  • 管理画面開発
  • API連携テスト

など、必要な段階から相談できます。

例えば、

「Webサービスへクレジットカード決済を追加したい」

「月額課金のSaaSを作りたい」

「Stripeを導入したいが、Webhookや契約管理をどう設計すればよいか分からない」

「決済は実装済みだが、二重決済や決済失敗時の処理が不安」

といった段階でも、まず決済・契約の業務フローを整理することで必要なシステム構成が見えてきます。

Stripe API連携で重要なのは、決済ボタンを動かすことだけではありません。

決済成功・失敗・重複・Webhook障害などが発生しても、自社の注文・契約データとStripe上の決済状態を安全に一致させ続けられる仕組みを作ることが重要です。

Contact

お問い合わせ

システム導入、Webアプリ開発、AI導入、業務委託での開発支援などのご相談を受け付けています。

要件が固まっていなくても大丈夫です。使う方・運用する方の視点で整理し、分かりやすく進めます。

まずはお気軽にお問い合わせください。