api-commerce-stripe について
`stripe` npm パッケージを使った TypeScript のサーバーサイド連携を案内するコーディングスキルです。決済、請求、Webhook、Connect を扱い、安全なリクエスト処理を重視します。
主な機能
- 01型付き Stripe クライアントの初期化
- 02Checkout Sessions と Payment Intents の作成
- 03Webhook イベントの検証と処理
- 04顧客、サブスクリプション、商品、価格の管理
- 05冪等性キーと型付きエラー処理
活用シーン
- 01単発または定期決済の実装
- 02カスタム決済フローの構築
- 03非同期決済イベントの処理
- 04Stripe Connect によるマーケットプレイス決済
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ agents-inc/ skills --skill api-commerce-stripeインストール後、Claude Code で/api-commerce-stripeを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
metadata.yamlreference.mdexamples/connect.mdcore.mdsubscriptions.mdwebhooks.md詳細
Stripe パターン
クイックガイド: サーバー側のすべての Stripe 操作には、
stripenpm パッケージを使用します。Webhook の署名は必ず、生のリクエストボディを使ってconstructEvent()で検証してください。解析済みのボディは使用しないでください。変更を伴うすべてのリクエストには、冪等性キーを使用します。シークレットキーはサーバー側だけに置いてください。エラーはinstanceof Stripe.errors.StripeErrorで処理します。金額は必ず通貨の最小単位(例:USD ならセント)で指定します。
<critical_requirements>
重要:このスキルを使用する前に
すべてのコードは、CLAUDE.md のプロジェクト規約に従う必要があります(kebab-case、名前付きエクスポート、インポート順序、
import type、名前付き定数)。
(STRIPE_SECRET_KEY をクライアント側のコードで公開してはいけません。サーバー側だけに置いてください)
(stripe.webhooks.constructEvent() を使い、生のリクエストボディでWebhookの署名を検証する必要があります。解析済みの JSON は使用しないでください)
(二重請求を防ぐため、変更を伴うすべての(POST)リクエストで冪等性キーを使用する必要があります)
(すべての Stripe エラーを instanceof Stripe.errors.StripeError で処理する必要があります。決済エラーを握りつぶしてはいけません)
(金額は通貨の最小単位で表す必要があります。USD ならドルではなくセントです)
</critical_requirements>
自動検出: Stripe、stripe、stripe.checkout.sessions、stripe.paymentIntents、stripe.customers、stripe.subscriptions、stripe.webhooks、constructEvent、PaymentIntent、CheckoutSession、STRIPE_SECRET_KEY、STRIPE_WEBHOOK_SECRET、stripe.prices、stripe.products、stripe.refunds、stripe.transfers、stripe.accounts、Stripe.errors、idempotencyKey、payment_intent.succeeded、checkout.session.completed
使用する場面:
- 単発決済またはサブスクリプション決済の Checkout Session を作成する
- Payment Intents を使ってカスタム決済フローを構築する
- 非同期の決済ライフサイクルに関するWebhookイベントを処理する
- 顧客、決済手段、サブスクリプションを管理する
- Stripe Connect を使ってマーケットプレイスプラットフォームを構築する
- 返金を処理し、異議申し立てに対応する
- カタログ用の商品と価格を設定する
対象となる主なパターン:
- TypeScript の型を使った Stripe クライアントの初期化
- Checkout Sessions(単発決済、サブスクリプション、セットアップモード)
- Payment Intents(カスタムフロー、確定、キャプチャ)
- Webhook の署名検証とイベント処理
- 顧客の作成・更新と決済手段の関連付け
- サブスクリプションのライフサイクル(作成、更新、キャンセル、トライアル、日割り計算)
- Products と Prices(カタログ管理)
- Stripe Connect(アカウント作成、送金、送金先指定決済)
- Stripe の型付きエラーによるエラー処理
- 安全なリトライのための冪等性キー
使用しない場面:
- クライアント側の Stripe.js または Stripe Elements(フロントエンドフレームワークのスキルを使用してください)
- Stripe CLI コマンドまたはダッシュボードの設定
- Stripe 以外の決済プロセッサ(専用のスキルを使用してください)
詳細リソース:
- 判断のフレームワークとアンチパターンについては、reference.md を参照してください
コアのセットアップと決済:
- examples/core.md — クライアントのセットアップ、Checkout Sessions、Payment Intents、エラー処理
Webhook とイベント:
- examples/webhooks.md — 署名検証、イベント処理、冪等性のある処理
サブスクリプションと請求:
- examples/subscriptions.md — サブスクリプションのライフサイクル、トライアル、日割り計算、従量課金
Connect とプラットフォーム:
- examples/connect.md — 接続済みアカウント、送金、送金先指定決済、プラットフォーム手数料
## 設計思想
Stripeは決済インフラストラクチャプラットフォームです。stripe npmパッケージは、Stripe APIと連携するためのサーバーサイドSDKです。セキュリティを確保するため、すべての決済処理はサーバーサイドで行われます。
基本原則:
- サーバーサイドのみ — シークレットキーと、決済を作成するすべての操作をブラウザー上で実行してはいけません。クライアントサイドでは、決済情報の収集にのみStripe.js(別の領域)を使用します。
- 金額は最小通貨単位で指定 — すべての金額は、通貨の最小単位(USDならセント、GBPならペンス)を整数で指定します。
1000は1,000ドルではなく、10.00ドルを意味します。 - 安全性のための冪等性 — ネットワーク再試行による二重請求を防ぐため、すべての変更リクエストに冪等性キーを含めてください。StripeのSDKは再試行時にキーを自動生成しますが、アプリケーションレベルで再試行する場合は、明示的なキーを指定してください。
- Webhookを信頼できる情報源とする — 決済ステータスはポーリングではなく、Webhookで確認してください。決済の成功、失敗、または追加対応の必要性を示す信頼できる情報は、Webhookイベントのみです。
- 型付き例外としてのエラー — Stripeエラーは値として返されず、スローされます。
instanceof Stripe.errors.StripeErrorで捕捉し、適切なユーザー向け応答を行うために、種類に応じて処理してください。 - APIバージョンは重要 — APIバージョンを固定してください。型は最新のAPIバージョンを反映します。動作を固定するには、コンストラクターで
apiVersionを使用してください。
Stripeを使用する場面:
- 決済の受け付け(単発、定期、マーケットプレイスでの分割)
- サブスクリプション課金システムの構築
- Connectを使ったプラットフォーム/マーケットプレイスでの決済分割
- 将来の請求に備えた支払い方法の保存
使用しない場面:
- クライアントサイドでの決済フォームの表示(Stripe.js/Elementsは別の領域です)
- サーバーを使わない決済処理(Stripeではサーバーサイドのシークレットキーが必要です)
- シンプルな寄付ボタン(コードを使わず、Stripe Payment Linksで十分な場合があります)
基本パターン
パターン 1:Stripeクライアントの初期化
Stripeクライアントをシングルトンとして作成します。シークレットキーは環境変数から取得し、APIバージョンを固定します。セットアップの全体像については、examples/core.mdを参照してください。
export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
apiVersion: "2026-02-25.clover",
});
シークレットキーをハードコードしたり、apiVersionを省略したりしないでください(Stripe APIのアップグレード時に、動作が予告なく変わるためです)。
パターン 2:Checkout Session
単発の決済にはmode: "payment"を、定期決済にはmode: "subscription"を使用します。決済ページはStripeがホストします。成功URLには必ず{CHECKOUT_SESSION_ID}を含めてください(Stripeがこのテンプレートを自動的に置換します)。例の全体像については、examples/core.mdを参照してください。
const session = await stripe.checkout.sessions.create({
mode: "payment", // or "subscription" or "setup"
line_items: [{ price: priceId, quantity }],
success_url: `${process.env.APP_URL}/success?session_id={CHECKOUT_SESSION_ID}`,
cancel_url: `${process.env.APP_URL}/cancel`,
});
パターン 3:Payment Intents(カスタムフロー)
決済UIを完全に制御する必要がある場合(例:Stripe Elements)は、Payment Intentsを使用します。必ずautomatic_payment_methodsを使い(旧式のpayment_method_types配列は使用しないでください)、冪等性キーを含めてください。例の全体像については、examples/core.mdを参照してください。
const paymentIntent = await stripe.paymentIntents.create(
{
amount: amountInCents,
currency,
automatic_payment_methods: { enabled: true },
},
{ idempotencyKey: `pi_${orderId}` },
);
return { clientSecret: paymentIntent.client_secret };
ドルとセントの混同を避けるため、パラメーター名にはamountInCentsを使用してください。フロントエンドにはclient_secretを返します。
パターン 4:顧客管理
重複を防ぐため、メールアドレスを基にした冪等性キーを使って顧客を作成します。支払い方法は、まずアタッチし、次にinvoice_settings.default_payment_methodでデフォルトに設定するという2段階で登録します。例の全体像については、examples/core.mdを参照してください。
パターン 5:商品と価格
Stripeのデータモデルでは、商品と価格は別々のリソースです。サブスクリプション価格の場合にのみ、recurring: { interval }を追加します。金額のパラメーター名にはamountInCentsを使用してください。例の全体像については、examples/core.mdを参照してください。
パターン 6:返金
全額返金の場合はamountを省略します。chargeよりも推奨されるpayment_intentを使用してください。返金金額ごとに一意となる冪等性キーを必ず含めてください。例の全体像については、examples/core.mdを参照してください。
パターン 7:エラー処理
instanceof Stripe.errors.StripeCardError(およびその他のエラーサブクラス)を使ってエラーを捕捉します。StripeCardError は、ユーザーに表示しても安全なメッセージを decline_code とともに返します。StripeInvalidRequestError は開発者のバグです。StripeConnectionError と StripeRateLimitError は再試行できます。エラー処理パターンの全容については、examples/core.md を参照してください。
if (error instanceof Stripe.errors.StripeCardError) {
return { success: false, message: error.message, code: error.code };
}
<red_flags>
重大な警告
優先度の高い問題:
- クライアント側コードにシークレットキーが含まれている —
STRIPE_SECRET_KEYがブラウザーバンドルに含まれることは絶対に避けてください。クライアント側の Stripe.js でのみ、STRIPE_PUBLISHABLE_KEY(pk_で始まるキー)を使用してください。 - Webhook の署名が検証されていない —
constructEvent()による検証を行わないと、攻撃者が偽のイベントを送信して、注文の履行、アクセス権の付与、レコードの変更を行う可能性があります。 - Webhook で生のリクエストボディを使用していない — 生のリクエストボディ文字列/バッファーではなく、
req.body(解析済みの JSON)を使うと、署名検証がエラーを出さずに失敗します。Express では、Webhook のルートにexpress.raw({ type: "application/json" })を使用してください。 - 冪等性キーが設定されていない — 冪等性キーがないと、ネットワークの再試行によって二重請求が発生する可能性があります。作成/更新操作では常に
{ idempotencyKey }を渡してください。 - ドル単位の金額を指定している —
amount: 10は 10.00 ドルではなく、0.10 ドルの請求になります。常に 100 を掛けるか、変数名にamountInCentsを使用してください。
優先度が中程度の問題:
- API バージョンを固定していない — コンストラクターで
apiVersionを指定しないと、Stripe はアカウントのデフォルトバージョンを使用します。API の変更によって、連携が気付かないうちに動作しなくなる可能性があります。 automatic_payment_methodsではなくpayment_method_typesを使用している — 従来の配列方式では、新しい決済方法が利用可能になるたびに手動で更新する必要があります。現在はautomatic_payment_methods: { enabled: true }を使用するのが標準的な方法です。- Stripe のエラーを無視している — 空の
catchブロックは決済の失敗を隠してしまいます。Stripe サポートに問い合わせる際のデバッグ用に、エラーのrequestIdを必ずログに記録してください。 requires_actionステータスに対応していない — Payment Intents では、3D セキュア認証が必要になる場合があります。確認後にpaymentIntent.statusをチェックしてください。- Webhook ではなくポーリングを使用している — ループ内で決済ステータスを確認する方法は信頼性が低く、API 呼び出しを無駄に消費します。すべての非同期決済イベントには Webhook を使用してください。
よくある間違い:
- Webhook を同期的に処理している — Webhook ハンドラー内で時間のかかる処理を行うと、タイムアウトが発生します。すぐに
200を返し、その後、非同期で処理してください。 - Webhook イベントの重複に対応していない — Stripe は同じイベントを複数回配信することがあります。処理済みのイベント ID を記録して、冪等に処理できるようにしてください。
- 本番環境でテストキーを使用している —
sk_test_およびpk_test_で始まるキーは、テストデータでのみ機能します。環境設定を確認してください。 - ネストされたオブジェクトの取得に
expandを指定していない — Stripe は関連オブジェクトの ID をデフォルトで返します。オブジェクト全体を取得するには、expand: ["latest_invoice.payment_intent"]を使用してください。
注意点とエッジケース:
- Stripe のイベントは順不同で届く —
invoice.createdより先にinvoice.paidが届く場合があります。順序に依存しないハンドラーを設計してください。 - Checkout Session の
{CHECKOUT_SESSION_ID}はリテラルのテンプレートです — Stripe はsuccess_url内のこのプレースホルダーを置き換えます。URL エンコードしないでください。 - サブスクリプションの按分計算はデフォルトで有効です — 期間の途中でプランをアップグレードすると、自動的に按分計算されます。無効にするには
proration_behavior: "none"を渡してください。 - 冪等性キーは 24 時間後に期限切れになります — 期限切れ後は、同じキーを使っても新しいリクエストが作成されます。長期間にわたって再試行する場合は、新しいキーを生成してください。
- 小数単位のない通貨 — JPY、KRW などには小数の補助単位がありません。JPY の
amount: 500は 5 円ではなく 500 円を意味します。Stripe.ZERO_DECIMAL_CURRENCIESを確認してください。 - Connect の送金には
transfers機能が必要です — 送金を受け取るには、連結アカウントでcard_paymentsおよびtransfersの機能を有効にする必要があります。 - Webhook シークレットはエンドポイントごとに異なります — 各 Webhook エンドポイントには、それぞれ固有の署名シークレットがあります。誤ったシークレットを使用すると、署名検証はすべて失敗します。
</red_flags>
<critical_reminders>
重要な注意事項
すべてのコードは、CLAUDE.md のプロジェクト規約(kebab-case、名前付きエクスポート、import の順序、
import type、名前付き定数)に従う必要があります。
(クライアント側のコードで STRIPE_SECRET_KEY を絶対に公開しないでください。サーバー側だけで使用します。)
(stripe.webhooks.constructEvent() を使用して、RAW リクエストボディで webhook の署名を必ず検証してください。解析済みの JSON は絶対に使用しないでください。)
(二重請求を防ぐため、すべての変更を伴うリクエスト(POST)で、必ず冪等性キーを使用してください。)
(すべての Stripe エラーを instanceof Stripe.errors.StripeError で処理してください。決済エラーを絶対に握りつぶさないでください。)
(金額は最小の通貨単位で表してください。USD の場合はドルではなくセントを使用します。)
これらのルールを守らないと、セキュリティ上の脆弱性、二重請求、気付かない決済失敗につながります。