From 4e90741d75bbeb8f9b1cd1c879304de0d8acdac7 Mon Sep 17 00:00:00 2001 From: Vadym Samoilenko Date: Mon, 25 May 2026 14:08:06 +0100 Subject: [PATCH] fix(billing): fix metadata access for Stripe SDK v5 StripeObject MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dict(session.metadata) fails with KeyError:0 — metadata is a StripeObject in SDK v5, not a plain dict. Use getattr() for all metadata fields. Co-Authored-By: Claude Sonnet 4.6 --- backend/app/routes/billing.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/backend/app/routes/billing.py b/backend/app/routes/billing.py index 5764bf41..1a52124f 100644 --- a/backend/app/routes/billing.py +++ b/backend/app/routes/billing.py @@ -147,11 +147,11 @@ async def stripe_webhook(): logger.info("Skipping unpaid checkout session %s", session.id) return jsonify({"status": "ok"}), 200 - # 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", "") + # metadata is a StripeObject in SDK v5 — use attribute access + meta = session.metadata + user_id = getattr(meta, "user_id", None) if meta else None + credits = int(getattr(meta, "credits", 0) or 0) if meta else 0 + pack_id = getattr(meta, "pack_id", "") if meta else "" # `or` so explicit null payment_intent falls through to session id payment_id = session.payment_intent or session.id