Skip to content

fix(billing): Stripe webhook 500 — normalize event to plain dict - #9

Merged
rryoung98 merged 2 commits into
mainfrom
fix/webhook-dict
Aug 12, 2026
Merged

fix(billing): Stripe webhook 500 — normalize event to plain dict#9
rryoung98 merged 2 commits into
mainfrom
fix/webhook-dict

Conversation

@rryoung98

Copy link
Copy Markdown
Contributor

Live Stripe test event (stripe trigger checkout.session.completed) hit prod and 500'd: construct_event returns a StripeObject whose .get lookup raises AttributeError in stripe>=15. Verifier now normalizes to plain JSON types. TDD: signed-payload regression test using stripe's own signature scheme.

Copilot AI lite review requested due to automatic review settings August 12, 2026 05:35
@rryoung98
rryoung98 merged commit eaa743e into main Aug 12, 2026
1 check passed
@rryoung98
rryoung98 deleted the fix/webhook-dict branch August 12, 2026 05:36

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses a production 500 caused by stripe.Webhook.construct_event() returning a Stripe object that is no longer dict-like in stripe-python v15+, by normalizing the verified event into plain Python types and adding a regression test that validates signed payload verification.

Changes:

  • Normalize the Stripe webhook event returned by the default verifier into plain JSON/Python types.
  • Add a regression test that builds a Stripe-signed payload and asserts the verifier returns a plain dict.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
gateway/src/declaude/app.py Updates the default Stripe webhook verifier to return plain Python types instead of a Stripe object.
gateway/tests/test_billing_webhook.py Adds a regression test covering signature verification and dict-normalization behavior.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +49 to +51
event = stripe.Webhook.construct_event(payload, sig_header, os.environ["STRIPE_WEBHOOK_SECRET"])
# StripeObject attribute access is unreliable across versions; normalize to plain JSON types.
return json.loads(str(event)) # StripeObject.__str__ is canonical JSON
Comment on lines +126 to +128
ts = int(time.time())
sig = stripe.WebhookSignature._compute_signature(f"{ts}.{payload.decode()}", secret)
event = default_webhook_verifier(payload, f"t={ts},v1={sig}")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants