From 24e17189df2b35f3445b3967de6375d03319706f Mon Sep 17 00:00:00 2001 From: David Brownman Date: Tue, 16 Dec 2025 14:50:47 -0800 Subject: [PATCH 1/2] Add EventNotificationHandler example --- CHANGELOG.md | 1 + .../EventNotificationHandlerEndpoint.java | 92 +++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 src/main/java/com/stripe/examples/EventNotificationHandlerEndpoint.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b8461103c8..b107b8827e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ This release changes the pinned API version to `2025-12-15.preview`. * [#2104](https://github.com/stripe/stripe-java/pull/2104) 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 * [#2117](https://github.com/stripe/stripe-java/pull/2117) 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` diff --git a/src/main/java/com/stripe/examples/EventNotificationHandlerEndpoint.java b/src/main/java/com/stripe/examples/EventNotificationHandlerEndpoint.java new file mode 100644 index 00000000000..ad09c7d2094 --- /dev/null +++ b/src/main/java/com/stripe/examples/EventNotificationHandlerEndpoint.java @@ -0,0 +1,92 @@ +package com.stripe.examples; + +import com.stripe.StripeClient; +import com.stripe.StripeEventNotificationHandler; +import com.stripe.StripeEventNotificationHandler.UnhandledNotificationDetails; +import com.stripe.events.V1BillingMeterErrorReportTriggeredEventNotification; +import com.stripe.exception.StripeException; +import com.stripe.model.billing.Meter; +import com.stripe.model.v2.core.EventNotification; +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; +import java.io.IOException; +import java.io.InputStream; +import java.net.InetSocketAddress; +import java.nio.charset.StandardCharsets; + +/** + * Receive and process event notifications (AKA thin events) like + * "v1.billing.meter.error_report_triggered" using EventNotificationHandler. + * + *

In this example, we: + * + *

+ */ +public class EventNotificationHandlerEndpoint { + private static final String API_KEY = System.getenv("STRIPE_API_KEY"); + private static final String WEBHOOK_SECRET = System.getenv("WEBHOOK_SECRET"); + + private static final StripeClient client = new StripeClient(API_KEY); + private static final StripeEventNotificationHandler handler = + client.notificationHandler( + WEBHOOK_SECRET, EventNotificationHandlerEndpoint::fallbackCallback); + + public static void main(String[] args) throws IOException { + handler.onV1BillingMeterErrorReportTriggered( + EventNotificationHandlerEndpoint::handleMeterErrors); + + HttpServer server = HttpServer.create(new InetSocketAddress(4242), 0); + server.createContext("/webhook", new WebhookHandler()); + server.setExecutor(null); + server.start(); + } + + private static void fallbackCallback( + EventNotification notif, StripeClient client, UnhandledNotificationDetails details) { + System.out.println("Received unhandled event notification type: " + notif.getType()); + } + + private static void handleMeterErrors( + V1BillingMeterErrorReportTriggeredEventNotification notif, StripeClient client) { + Meter meter; + try { + meter = notif.fetchRelatedObject(); + } catch (StripeException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return; + } + System.out.println("Handling meter error for meter: " + meter.getDisplayName()); + } + + static class WebhookHandler implements HttpHandler { + @Override + public void handle(HttpExchange exchange) throws IOException { + if ("POST".equals(exchange.getRequestMethod())) { + InputStream requestBody = exchange.getRequestBody(); + String webhookBody = new String(requestBody.readAllBytes(), StandardCharsets.UTF_8); + String sigHeader = exchange.getRequestHeaders().getFirst("Stripe-Signature"); + + try { + handler.handle(webhookBody, sigHeader); + + exchange.sendResponseHeaders(200, -1); + } catch (StripeException e) { + exchange.sendResponseHeaders(400, -1); + } + } else { + exchange.sendResponseHeaders(405, -1); + } + exchange.close(); + } + } +} From c9658e0310adf20b9ccc5219cc9e8e5c164dcda5 Mon Sep 17 00:00:00 2001 From: David Brownman Date: Tue, 16 Dec 2025 15:01:04 -0800 Subject: [PATCH 2/2] fix compiler --- .../EventNotificationHandlerEndpoint.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/stripe/examples/EventNotificationHandlerEndpoint.java b/src/main/java/com/stripe/examples/EventNotificationHandlerEndpoint.java index ad09c7d2094..195420e022d 100644 --- a/src/main/java/com/stripe/examples/EventNotificationHandlerEndpoint.java +++ b/src/main/java/com/stripe/examples/EventNotificationHandlerEndpoint.java @@ -10,6 +10,7 @@ import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.InetSocketAddress; @@ -69,11 +70,25 @@ private static void handleMeterErrors( } static class WebhookHandler implements HttpHandler { + // For Java 1.8 compatibility + public static byte[] readAllBytes(InputStream inputStream) throws IOException { + final int bufLen = 1024; + byte[] buf = new byte[bufLen]; + int readLen; + + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + + while ((readLen = inputStream.read(buf, 0, bufLen)) != -1) + outputStream.write(buf, 0, readLen); + + return outputStream.toByteArray(); + } + @Override public void handle(HttpExchange exchange) throws IOException { if ("POST".equals(exchange.getRequestMethod())) { InputStream requestBody = exchange.getRequestBody(); - String webhookBody = new String(requestBody.readAllBytes(), StandardCharsets.UTF_8); + String webhookBody = new String(readAllBytes(requestBody), StandardCharsets.UTF_8); String sigHeader = exchange.getRequestHeaders().getFirst("Stripe-Signature"); try {