🐍
StripeのPayment LinkでSlackのチーム情報を紐付ける実装方法
StripeのPayment LinkでSlackのチーム情報を紐付ける実装方法 🚀
こんにちは!この記事では、StripeのPayment Link を使って、Slackアプリ側のチーム情報をうまく紐付ける方法を、ゆるっと考える。
Stripeの決済機能をSlackアプリに組み込もうとしている方にとって、少しでも実装のヒントになれば嬉しいです😊
はじめに
課題
-
Stripeの決済機能をSlackアプリに組み込む時の悩み
- どのチームからの決済なのか、どうやって管理・把握する?
- 決済情報とチーム情報をどのように紐付ける?
- 決済状態をどのように追跡する?
Payment Linkのメリット
- 導入が簡単
- カスタムフォームの作成が不要
- Slackアプリからスムーズに案内できる
この記事で解決すること
- Payment Linkを使いながら、チーム情報を安全に紐付ける方法
- トランザクション管理の実装例
- Slackアプリでの具体的な実装方法
ここでは、いろいろ試した結果、最終的に落ち着いた client_reference_id
を使う実装方法 をご紹介します!
実装方法をあれこれ検討 🤔
1. URLパラメータによる方法(最初の試み❌)
- 試したこと: URLにチーム情報を直接付与
stripe_url = "https://buy.stripe.com/test_xxx?team_id={team_id}&app_id={app_id}"
- メリット: 実装が比較的シンプル
-
デメリット:
- Webhookでメタデータとして取得できない
- StripeのPayment LinkのURLには、決められたパラメータ(
prefilled_email
、client_reference_id
など)しか追加できない
-
なぜダメだったのか:
- URLパラメータはStripeのメタデータに自動設定されない
- カスタムパラメータ(
team_id
、app_id
など)は無視される - データとして取り回しづらい
2. カスタムCheckoutページの作成(❌)
- 試したこと: Stripeチェックアウトページを独自に作成
- 結果: Payment Linkのメリット(手軽さ)が失われるため不採用
checkout_session = stripe.checkout.Session.create(
metadata={
"team_id": team_id,
"app_id": app_id
}
# ... その他の設定
)
- メリット: 完全にカスタマイズした画面が用意できる
- デメリット: Payment Linkの気軽さが失われる
- Slackアプリ内での使用を考慮: オーバーエンジニアリングになりがち
3. client_reference_idを使用(✅ 採用)
-
特徴:
- 決済前にチーム情報をDBに保存
- Webhookで状態管理が可能
- Payment Linkの手軽さを維持
StripeのSessionなどでよく使われる client_reference_id
を利用して、決済前にチーム情報をデータベースに保存 し、後からWebhookで最終的なステータスを更新する流れです。
トランザクションテーブルの定義
# トランザクションテーブルの定義(実装例)
class StripeTransaction(db.Model):
__tablename__ = 'stripe_transactions'
id = db.Column(db.Integer, primary_key=True)
client_reference_id = db.Column(db.String(255), unique=True, index=True)
team_id = db.Column(db.String(255), index=True)
app_id = db.Column(db.String(255))
status = db.Column(db.String(50), default='pending')
created_at = db.Column(db.DateTime, default=datetime.utcnow)
completed_at = db.Column(db.DateTime)
session_id = db.Column(db.String(255))
def __repr__(self):
return f'<StripeTransaction {self.client_reference_id}>'
Payment LinkのURL生成
# Payment LinkのURL生成処理(実装例)
def get_payment_url(email: str, team_id: str, app_id: str):
client_reference_id = str(uuid.uuid4())
# トランザクションをDBに記録
transaction = StripeTransaction(
client_reference_id=client_reference_id,
team_id=team_id,
app_id=app_id
)
db.session.add(transaction)
db.session.commit()
url = f"{STRIPE_URL}?prefilled_email={email}&client_reference_id={client_reference_id}"
return url
Webhook処理
# Webhook処理(実装例)
@app.route("/stripe/success", methods=["POST"])
def stripe_success():
# ... Webhookの検証処理 ...
if event['type'] == 'checkout.session.completed':
session = event['data']['object']
client_reference_id = session.get('client_reference_id')
if client_reference_id:
transaction = StripeTransaction.query.filter_by(
client_reference_id=client_reference_id
).first()
if transaction:
transaction.status = 'completed'
transaction.completed_at = datetime.utcnow()
transaction.session_id = session.get('id')
db.session.commit()
Slackアプリでの実装例 🤖
Slackのメッセージ内にPayment Linkのボタンを表示する実装例です。
この実装例では、Slackのメッセージに決済ボタンを設置し、ユーザーがボタンをクリックするとStripeのPayment Linkに遷移します。
Payment LinkのURLには、client_reference_id
が含まれており、これにより決済情報とSlackのチーム情報を紐付けます。
# メッセージ送信用の関数(実装例)
def send_payment_message(client, channel_id: str, price: str, team_id: str):
try:
# ボタン用のPayment Link URLを生成
payment_url = get_payment_url(
email="メールアドレス",
team_id=team_id,
app_id="YOUR_APP_ID"
)
# 決済ボタンを含むメッセージを送信
client.chat_postMessage(
channel=channel_id,
blocks=[
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": f"💰 料金: {price}円"
}
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "決済する",
"emoji": True
},
"url": payment_url, # 生成したPayment LinkのURLを直接セット
"style": "primary"
}
]
}
]
)
except Exception as e:
logger.error(f"Failed to send payment message: {str(e)}")
# エラー時の処理
使用例:
# Slashコマンドやイベントに応じて決済メッセージを送信
@app.command("/payment")
def handle_payment_command(ack, body, client):
ack()
channel_id = body["channel_id"]
team_id = body["team_id"]
send_payment_message(
client=client,
channel_id=channel_id,
price="1,000",
team_id=team_id
)
このように実装することで:
-
シンプルな動線:
- メッセージ内のボタンから直接Payment Linkへ遷移
- DMを介さずにスムーズな決済フローを実現
-
トラッキング:
- ボタン生成時にUUIDを発行し、トランザクションテーブルに記録
- team_idとclient_reference_idの紐付けが完了
- Webhookで決済状況を追跡可能
-
注意点:
- パブリックチャンネルで使用する場合、URLは誰でもアクセス可能
- 必要に応じて、コマンドの実行権限を制限することを推奨
採用した実装方法のポイント
-
セキュリティ
-
client_reference_id
にはUUIDのみを使用し、チーム情報を含めない - URLに含める情報を最小限に抑え、外部にデータ構造を露出させない
- Webhookの署名確認など、Stripe標準の機能で安全性を担保する
-
-
トレーサビリティ
- トランザクションテーブルを用いることで、支払いの進行状況を簡単に追跡
- ステータス管理や日時管理で支払い履歴を明確化
-
シンプルな実装
- Payment Linkの魅力である手軽さをそのまま活かす
- 必要最低限の要素だけを残して過剰実装を避ける
実装時の注意点
-
client_reference_idの生成
- UUIDなどの一意性が保証された値を利用
- 機密情報は一切含めない(URL上で他人に見られてしまう可能性を排除)
-
エラーハンドリング
- Webhookの検証に失敗した場合や署名不一致の場合の対応
- トランザクションテーブルとの整合性が取れない場合のログ・アラート
まとめ
- Payment Link の便利さを活かしながら、チーム情報の紐付けを実現
-
client_reference_id
+ トランザクションテーブルの組み合わせで、決済プロセスの追跡をスムーズに - 過剰に複雑化することなく、セキュリティや管理面を担保できる
Discussion