Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
This release changes the pinned API version to `2025-12-15.preview`.

* [#1653](https://github.com/stripe/stripe-python/pull/1653) Add EventNotificationHandler
* This is a new, simplified way to handle event notifications (AKA thin event webhooks). Learn more in the docs: https://docs.stripe.com/webhooks/event-notification-handlers
* [#1680](https://github.com/stripe/stripe-python/pull/1680) Update generated code for beta
* Add support for new resources `reserve.Hold`, `reserve.Plan`, and `reserve.Release`
* Add support for `list` and `retrieve` methods on resources `reserve.Hold` and `reserve.Release`
Expand Down
55 changes: 55 additions & 0 deletions examples/event_notification_handler_endpoint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
"""
event_notification_handler_endpoint.py - receive and process event notifications (AKA thin events) like "v1.billing.meter.error_report_triggered" using EventNotificationHandler.

In this example, we:
- write a fallback callback to handle unrecognized event notifications
- create a StripeClient called client
- Initialize an EventNotificationHandler with the client, webhook secret, and fallback callback
- register a specific handler for the "v1.billing.meter.error_report_triggered" event notification type
- use handler.handle() to process the received notification webhook body
"""

import os
from flask import Flask, request, jsonify

from stripe import StripeClient, UnhandledNotificationDetails
from stripe.v2.core import EventNotification
from stripe.events import V1BillingMeterErrorReportTriggeredEventNotification

app = Flask(__name__)
api_key = os.environ.get("STRIPE_API_KEY", "")
webhook_secret = os.environ.get("WEBHOOK_SECRET", "")


def fallback_callback(
notif: EventNotification,
client: StripeClient,
details: UnhandledNotificationDetails,
):
print(f"Got an unhandled event of type {notif.type}!")


client = StripeClient(api_key)
handler = client.notification_handler(webhook_secret, fallback_callback)


# can be anywhere in your codebase
@handler.on_v1_billing_meter_error_report_triggered
def handle_meter_error(
notif: V1BillingMeterErrorReportTriggeredEventNotification,
client: StripeClient,
):
event = notif.fetch_event()
print(f"Err! No meter found: {event.data.developer_message_summary}")


@app.route("/webhook", methods=["POST"])
def webhook():
webhook_body = request.data
sig_header = request.headers.get("Stripe-Signature")

try:
handler.handle(webhook_body, sig_header)
return jsonify(success=True), 200
except Exception as e:
return jsonify(error=str(e)), 500

Check warning

Code scanning / CodeQL

Information exposure through an exception Medium

Stack trace information
flows to this location and may be exposed to an external user.

Copilot Autofix

AI 13 days ago

To fix the information exposure, we should avoid returning internal error messages or exception details (like str(e)) to API clients. Instead, log the actual exception—including the traceback if desired—using server-side logging (for example, using Python's standard logging module), and return a generic error message to the client.
The fix requires:

  • Importing logging at the top of the file if not already present.
  • Optionally configuring the logger if desired, or just using the root logger.
  • In the exception handler, log the full exception and traceback using logging.exception() (or similar).
  • Return a generic message in the response, such as "An internal error has occurred.", rather than user-facing exception details.

The code to change is in the exception handler in the webhook() function, specifically on lines 54–55. Logging should be done inside the except block, before returning the generic message.

Suggested changeset 1
examples/event_notification_handler_endpoint.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/examples/event_notification_handler_endpoint.py b/examples/event_notification_handler_endpoint.py
--- a/examples/event_notification_handler_endpoint.py
+++ b/examples/event_notification_handler_endpoint.py
@@ -11,7 +11,7 @@
 
 import os
 from flask import Flask, request, jsonify
-
+import logging
 from stripe import StripeClient, UnhandledNotificationDetails
 from stripe.v2.core import EventNotification
 from stripe.events import V1BillingMeterErrorReportTriggeredEventNotification
@@ -52,4 +52,5 @@
         handler.handle(webhook_body, sig_header)
         return jsonify(success=True), 200
     except Exception as e:
-        return jsonify(error=str(e)), 500
+        logging.exception("Exception occurred while handling webhook")
+        return jsonify(error="An internal error has occurred."), 500
EOF
@@ -11,7 +11,7 @@

import os
from flask import Flask, request, jsonify

import logging
from stripe import StripeClient, UnhandledNotificationDetails
from stripe.v2.core import EventNotification
from stripe.events import V1BillingMeterErrorReportTriggeredEventNotification
@@ -52,4 +52,5 @@
handler.handle(webhook_body, sig_header)
return jsonify(success=True), 200
except Exception as e:
return jsonify(error=str(e)), 500
logging.exception("Exception occurred while handling webhook")
return jsonify(error="An internal error has occurred."), 500
Copilot is powered by AI and may make mistakes. Always verify output.