fix(billing): use Stripe SDK v5 attribute access in webhook handler

stripe.Webhook.construct_event() now returns StripeObject instances that
do not support .get()/__getitem__ — must use attribute access.
event["type"] → event.type, session.get("x") → session.x, etc.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Vadym Samoilenko 2026-05-25 14:04:58 +01:00
parent 1361e42837
commit afd44408e0

View file

@ -139,20 +139,21 @@ async def stripe_webhook():
logger.warning(f"Webhook signature invalid: {e}")
return jsonify({"message": "Invalid signature"}), 400
if event["type"] == "checkout.session.completed":
session = event["data"]["object"]
if event.type == "checkout.session.completed":
session = event.data.object
# Only process confirmed payments — never grant credits for unpaid sessions
if session.get("payment_status") != "paid":
logger.info("Skipping unpaid checkout session %s", session.get("id"))
if session.payment_status != "paid":
logger.info("Skipping unpaid checkout session %s", session.id)
return jsonify({"status": "ok"}), 200
meta = session.get("metadata", {})
# metadata is a plain dict in the Stripe SDK
meta = dict(session.metadata) if session.metadata else {}
user_id = meta.get("user_id")
credits = int(meta.get("credits", 0))
pack_id = meta.get("pack_id", "")
# `or` so explicit null payment_intent falls through to session id
payment_id = session.get("payment_intent") or session.get("id", "")
payment_id = session.payment_intent or session.id
if not user_id or credits <= 0 or not payment_id:
return jsonify({"status": "ok"}), 200