stripe-integration
Stripe の決済処理を実装し、チェックアウト・サブスクリプション・Webhook を含む堅牢でPCIに準拠した支払いフローを構築します。Stripe 決済の統合、サブスクリプションシステムの構築、または安全なチェックアウトフローの実装が必要な際に使用してください。
description の原文を見る
Implement Stripe payment processing for robust, PCI-compliant payment flows including checkout, subscriptions, and webhooks. Use when integrating Stripe payments, building subscription systems, or implementing secure checkout flows.
SKILL.md 本文
Stripe統合
チェックアウト、サブスクリプション、webhook、返金を含む堅牢でPCI準拠の決済フローのためのStripe決済処理統合をマスターします。
このスキルを使用する場合
- Webアプリケーションやモバイルアプリケーションへの決済処理の実装
- サブスクリプション請求システムの構築
- 1回限りの支払いと定期的な請求の処理
- 返金と紛争の処理
- 顧客の支払い方法の管理
- ヨーロッパの決済用SCA(Strong Customer Authentication)の実装
- Stripe Connectを使用したマーケットプレイス決済フローの構築
コアコンセプト
1. 決済フロー
チェックアウトセッション
- ほとんどの統合に推奨
- すべてのUIパスをサポート:
- Stripeがホストするチェックアウトページ
- 埋め込みチェックアウトフォーム
ui_mode='custom'を使用したElements(Payment Element、Express Checkout Element)でのカスタムUI
- ビルトインチェックアウト機能(行項目、割引、税金、送料、住所収集、保存済み支払い方法、チェックアウトライフサイクルイベント)を提供
- Payment Intentsより低い統合・保守負担
Payment Intents(自由度の高い制御)
- 税金、割引、サブスクリプション、通貨換算を含む最終額を自分で計算
- より複雑な実装と長期的な保守負担
- PCI準拠にはStripe.jsが必要
Setup Intents(支払い方法の保存)
- 課金なしで支払い方法を収集
- サブスクリプションと将来の支払いに使用
- 顧客の確認が必要
2. Webhook
重要なイベント:
payment_intent.succeeded: 支払い完了payment_intent.payment_failed: 支払い失敗customer.subscription.updated: サブスクリプション変更customer.subscription.deleted: サブスクリプションキャンセルcharge.refunded: 返金処理完了invoice.payment_succeeded: サブスクリプション支払い成功
3. サブスクリプション
コンポーネント:
- Product: 販売しているもの
- Price: 金額と頻度
- Subscription: 顧客の定期支払い
- Invoice: 各請求サイクルで生成
4. 顧客管理
- 顧客レコードの作成と管理
- 複数の支払い方法の保存
- 顧客メタデータの追跡
- 請求詳細の管理
クイックスタート
import stripe
stripe.api_key = "sk_test_..."
# チェックアウトセッションの作成
session = stripe.checkout.Session.create(
line_items=[{
'price_data': {
'currency': 'usd',
'product_data': {
'name': 'Premium Subscription',
},
'unit_amount': 2000, # $20.00
'recurring': {
'interval': 'month',
},
},
'quantity': 1,
}],
mode='subscription',
success_url='https://yourdomain.com/success?session_id={CHECKOUT_SESSION_ID}',
cancel_url='https://yourdomain.com/cancel'
)
# ユーザーをsession.urlにリダイレクト
print(session.url)
決済実装パターン
パターン1: 1回限りの支払い(ホストされたチェックアウト)
def create_checkout_session(amount, currency='usd'):
"""1回限りの支払いチェックアウトセッションを作成します。"""
try:
session = stripe.checkout.Session.create(
line_items=[{
'price_data': {
'currency': currency,
'product_data': {
'name': 'Blue T-shirt',
'images': ['https://example.com/product.jpg'],
},
'unit_amount': amount, # 金額はセント単位
},
'quantity': 1,
}],
mode='payment',
success_url='https://yourdomain.com/success?session_id={CHECKOUT_SESSION_ID}',
cancel_url='https://yourdomain.com/cancel',
metadata={
'order_id': 'order_123',
'user_id': 'user_456'
}
)
return session
except stripe.error.StripeError as e:
# エラーを処理
print(f"Stripe error: {e.user_message}")
raise
パターン2: Elementsを使用したチェックアウトセッション
def create_checkout_session_for_elements(amount, currency='usd'):
"""Payment Elementに対応したチェックアウトセッションを作成します。"""
session = stripe.checkout.Session.create(
mode='payment',
ui_mode='custom',
line_items=[{
'price_data': {
'currency': currency,
'product_data': {'name': 'Blue T-shirt'},
'unit_amount': amount,
},
'quantity': 1,
}],
return_url='https://yourdomain.com/complete?session_id={CHECKOUT_SESSION_ID}'
)
return session.client_secret # フロントエンドに送信
const stripe = Stripe("pk_test_...");
const appearance = { theme: "stripe" };
const checkout = stripe.initCheckout({
clientSecret,
elementsOptions: { appearance },
});
const loadActionsResult = await checkout.loadActions();
if (loadActionsResult.type === "success") {
const { actions } = loadActionsResult;
const session = actions.getSession();
const button = document.getElementById("pay-button");
const checkoutContainer = document.getElementById("checkout-container");
const emailInput = document.getElementById("email");
const emailErrors = document.getElementById("email-errors");
const errors = document.getElementById("confirm-errors");
// 合計金額をフォーマットして表示
checkoutContainer.append(`Total: ${session.total.total.amount}`);
// Payment Elementをマウント
const paymentElement = checkout.createPaymentElement();
paymentElement.mount("#payment-element");
// メールアドレスを送信時に保存
emailInput.addEventListener("blur", () => {
actions.updateEmail(emailInput.value).then((result) => {
if (result.error) emailErrors.textContent = result.error.message;
});
});
// フォーム送信を処理
button.addEventListener("click", () => {
actions.confirm().then((result) => {
if (result.type === "error") errors.textContent = result.error.message;
});
});
}
パターン3: Elementsを使用したPayment Intents
パターン2(ElementsとチェックアウトセッションMを使用)はStripeの推奨アプローチですが、代替案としてPayment Intentsを使用することもできます。
def create_payment_intent(amount, currency='usd', customer_id=None):
"""Payment Elementを使用したカスタムチェックアウトUIのためのpayment intentを作成します。"""
intent = stripe.PaymentIntent.create(
amount=amount,
currency=currency,
customer=customer_id,
automatic_payment_methods={
'enabled': True,
},
metadata={
'integration_check': 'accept_a_payment'
}
)
return intent.client_secret # フロントエンドに送信
// Payment ElementをマウントしてPayment Intentsで確認
const stripe = Stripe("pk_test_...");
const appearance = { theme: "stripe" };
const elements = stripe.elements({ appearance, clientSecret });
const paymentElement = elements.create("payment");
paymentElement.mount("#payment-element");
document.getElementById("pay-button").addEventListener("click", async () => {
const { error } = await stripe.confirmPayment({
elements,
confirmParams: {
return_url: "https://yourdomain.com/complete",
},
});
if (error) {
document.getElementById("errors").textContent = error.message;
}
});
パターン4: サブスクリプション作成
def create_subscription(customer_id, price_id):
"""顧客のサブスクリプションを作成します。"""
try:
subscription = stripe.Subscription.create(
customer=customer_id,
items=[{'price': price_id}],
payment_behavior='default_incomplete',
payment_settings={'save_default_payment_method': 'on_subscription'},
expand=['latest_invoice.payment_intent'],
)
return {
'subscription_id': subscription.id,
'client_secret': subscription.latest_invoice.payment_intent.client_secret
}
except stripe.error.StripeError as e:
print(f"Subscription creation failed: {e}")
raise
パターン5: 顧客ポータル
def create_customer_portal_session(customer_id):
"""顧客がサブスクリプションを管理するためのポータルセッションを作成します。"""
session = stripe.billing_portal.Session.create(
customer=customer_id,
return_url='https://yourdomain.com/account',
)
return session.url # 顧客をここにリダイレクト
Webhookハンドリング
セキュアなWebhookエンドポイント
from flask import Flask, request
import stripe
app = Flask(__name__)
endpoint_secret = 'whsec_...'
@app.route('/webhook', methods=['POST'])
def webhook():
payload = request.data
sig_header = request.headers.get('Stripe-Signature')
try:
event = stripe.Webhook.construct_event(
payload, sig_header, endpoint_secret
)
except ValueError:
# ペイロードが無効
return 'Invalid payload', 400
except stripe.error.SignatureVerificationError:
# 署名が無効
return 'Invalid signature', 400
# イベントを処理
if event['type'] == 'payment_intent.succeeded':
payment_intent = event['data']['object']
handle_successful_payment(payment_intent)
elif event['type'] == 'payment_intent.payment_failed':
payment_intent = event['data']['object']
handle_failed_payment(payment_intent)
elif event['type'] == 'customer.subscription.deleted':
subscription = event['data']['object']
handle_subscription_canceled(subscription)
return 'Success', 200
def handle_successful_payment(payment_intent):
"""成功した支払いを処理します。"""
customer_id = payment_intent.get('customer')
amount = payment_intent['amount']
metadata = payment_intent.get('metadata', {})
# データベースを更新
# 確認メールを送信
# 注文を実行
print(f"Payment succeeded: {payment_intent['id']}")
def handle_failed_payment(payment_intent):
"""失敗した支払いを処理します。"""
error = payment_intent.get('last_payment_error', {})
print(f"Payment failed: {error.get('message')}")
# 顧客に通知
# 注文ステータスを更新
def handle_subscription_canceled(subscription):
"""サブスクリプションキャンセルを処理します。"""
customer_id = subscription['customer']
# ユーザーアクセスを更新
# キャンセルメールを送信
print(f"Subscription canceled: {subscription['id']}")
Webhookのベストプラクティス
import hashlib
import hmac
def verify_webhook_signature(payload, signature, secret):
"""Webhook署名を手動で検証します。"""
expected_sig = hmac.new(
secret.encode('utf-8'),
payload,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected_sig)
def handle_webhook_idempotently(event_id, handler):
"""webhookが正確に1回処理されることを確認します。"""
# イベントが既に処理されているかを確認
if is_event_processed(event_id):
return
# イベントを処理
try:
handler()
mark_event_processed(event_id)
except Exception as e:
log_error(e)
# Stripeが失敗したwebhookを再試行します
raise
顧客管理
def create_customer(email, name, payment_method_id=None):
"""Stripe顧客を作成します。"""
customer = stripe.Customer.create(
email=email,
name=name,
payment_method=payment_method_id,
invoice_settings={
'default_payment_method': payment_method_id
} if payment_method_id else None,
metadata={
'user_id': '12345'
}
)
return customer
def attach_payment_method(customer_id, payment_method_id):
"""支払い方法を顧客にアタッチします。"""
stripe.PaymentMethod.attach(
payment_method_id,
customer=customer_id
)
# デフォルトとして設定
stripe.Customer.modify(
customer_id,
invoice_settings={
'default_payment_method': payment_method_id
}
)
def list_customer_payment_methods(customer_id):
"""顧客のすべての支払い方法をリストアップします。"""
payment_methods = stripe.PaymentMethod.list(
customer=customer_id,
type='card'
)
return payment_methods.data
返金処理
def create_refund(payment_intent_id, amount=None, reason=None):
"""返金を作成します。"""
refund_params = {
'payment_intent': payment_intent_id
}
if amount:
refund_params['amount'] = amount # 部分返金
if reason:
refund_params['reason'] = reason # 'duplicate', 'fraudulent', 'requested_by_customer'
refund = stripe.Refund.create(**refund_params)
return refund
def handle_dispute(charge_id, evidence):
"""紛争を証拠で更新します。"""
stripe.Dispute.modify(
charge_id,
evidence={
'customer_name': evidence.get('customer_name'),
'customer_email_address': evidence.get('customer_email'),
'shipping_documentation': evidence.get('shipping_proof'),
'customer_communication': evidence.get('communication'),
}
)
テスト
# テストモードキーを使用
stripe.api_key = "sk_test_..."
# テストカード番号
TEST_CARDS = {
'success': '4242424242424242',
'declined': '4000000000000002',
'3d_secure': '4000002500003155',
'insufficient_funds': '4000000000009995'
}
def test_payment_flow():
"""完全な決済フローをテストします。"""
# テスト顧客を作成
customer = stripe.Customer.create(
email="test@example.com"
)
# Payment intentを作成
intent = stripe.PaymentIntent.create(
amount=1000,
automatic_payment_methods={
'enabled': True
},
currency='usd',
customer=customer.id
)
# テストカードで確認
confirmed = stripe.PaymentIntent.confirm(
intent.id,
payment_method='pm_card_visa' # テスト支払い方法
)
assert confirmed.status == 'succeeded'
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- wshobson
- リポジトリ
- wshobson/agents
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/wshobson/agents / ライセンス: MIT
関連スキル
superfluid
Superfluidプロトコルおよびそのエコシステムに関するナレッジベースです。Superfluidについて情報を検索する際は、ウェブ検索の前にこちらを参照してください。対応キーワード:Superfluid、CFA、GDA、Super App、Super Token、stream、flow rate、real-time balance、pool(member/distributor)、IDA、sentinels、liquidation、TOGA、@sfpro/sdk、semantic money、yellowpaper、whitepaper
civ-finish-quotes
実質的なタスクが真に完了した際に、文明風の儀式的な引用句を追加します。ユーザーやエージェントが機能追加、リファクタリング、分析、設計ドキュメント、プロセス改善、レポート、執筆タスクといった実際の成果物を完成させるときに、明示的な依頼がなくても使用します。短い返信や小さな修正、未完成の作業には適用しません。
nookplot
Base(Ethereum L2)上のAIエージェント向け分散型調整ネットワークです。エージェントがオンチェーンアイデンティティを登録する、コンテンツを公開する、他のエージェントにメッセージを送る、マーケットプレイスで専門家を雇う、バウンティを投稿・請求する、レピュテーションを構築する、共有プロジェクトで協業する、リサーチチャレンジを解くことでNOOKをマイニングする、キュレーションされたナレッジを備えたスタンドアロンオンチェーンエージェントをデプロイする、またはアグリーメントとリワードで収益を得る場合に利用できます。エージェントネットワーク、エージェント調整、分散型エージェント、NOOKトークン、マイニングチャレンジ、ナレッジバンドル、エージェントレピュテーション、エージェントマーケットプレイス、ERC-2771メタトランザクション、Prepare-Sign-Relay、AgentFactory、またはNookplotが言及された場合にトリガーされます。
web3-polymarket
Polygon上でのPolymarket予測市場取引統合です。認証機能(L1 EIP-712、L2 HMAC-SHA256、ビルダーヘッダー)、注文発注(GTC/GTD/FOK/FAK、バッチ、ポストオンリー、ハートビート)、市場データ(Gamma API、Data API、オーダーブック、サブグラフ)、WebSocketストリーミング(市場・ユーザー・スポーツチャネル)、CTF操作(分割、統合、償却、ネガティブリスク)、ブリッジ機能(入金、出金、マルチチェーン)、およびガスレスリレイトランザクションに対応しています。AIエージェント、自動マーケットメーカー、予測市場UI、またはPolygraph上のPolymarketと統合するアプリケーション構築時に活用できます。
ethskills
Ethereum、EVM、またはブロックチェーン関連のリクエストに対応します。スマートコントラクト、dApps、ウォレット、DeFiプロトコルの構築、監査、デプロイ、インタラクションに適用されます。Solidityの開発、コントラクトアドレス、トークン規格(ERC-20、ERC-721、ERC-4626など)、Layer 2ネットワーク(Base、Arbitrum、Optimism、zkSync、Polygon)、Uniswap、Aave、Curveなどのプロトコルとの統合をカバーします。ガスコスト、コントラクトのデシマル設定、オラクルセキュリティ、リエントランシー、MEV、ブリッジング、ウォレット管理、オンチェーンデータの取得、本番環境へのデプロイ、プロトコル進化(EIPライフサイクル、フォーク追跡、今後の変更予定)といったトピックを含みます。
xxyy-trade
このスキルは、ユーザーが「トークン購入」「トークン売却」「トークンスワップ」「暗号資産取引」「取引ステータス確認」「トランザクション照会」「トークンスキャン」「フィード」「チェーン監視」「トークン照会」「トークン詳細」「トークン安全性確認」「ウォレット一覧表示」「マイウォレット」「AIスキャン」「自動スキャン」「ツイートスキャン」「オンボーディング」「IP確認」「IPホワイトリスト」「トークン発行」「自動売却」「損切り」「利益確定」「トレーリングストップ」「保有者」「トップホルダー」「KOLホルダー」などをリクエストした場合、またはSolana/ETH/BSC/BaseチェーンでXXYYを経由した取引について言及した場合に使用します。XXYY Open APIを通じてオンチェーン取引とデータ照会を実現します。