java 42 lines · 7 steps

How a Stripe webhook controller works in Spring

A Spring REST controller that verifies Stripe webhook signatures and dispatches events to fulfillment.

Explained by highlit
1@RestController
2@RequestMapping("/webhooks/stripe")
3public class StripeWebhookController {
4 
5 private static final Logger log = LoggerFactory.getLogger(StripeWebhookController.class);
6 
7 private final String webhookSecret;
8 private final OrderFulfillmentService fulfillmentService;
9 
10 public StripeWebhookController(@Value("${stripe.webhook-secret}") String webhookSecret,
11 OrderFulfillmentService fulfillmentService) {
12 this.webhookSecret = webhookSecret;
13 this.fulfillmentService = fulfillmentService;
14 }
15 
16 @PostMapping
17 public ResponseEntity<String> handle(@RequestBody String payload,
18 @RequestHeader("Stripe-Signature") String signature) {
19 final Event event;
20 try {
21 event = Webhook.constructEvent(payload, signature, webhookSecret);
22 } catch (SignatureVerificationException e) {
23 log.warn("Rejected Stripe webhook with invalid signature", e);
24 return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Invalid signature");
25 }
26 
27 switch (event.getType()) {
28 case "checkout.session.completed" -> {
29 Session session = (Session) event.getDataObjectDeserializer()
30 .getObject()
31 .orElseThrow(() -> new IllegalStateException("Unable to deserialize session"));
32 fulfillmentService.fulfill(session.getClientReferenceId(), session.getPaymentIntent());
33 }
34 case "payment_intent.payment_failed" ->
35 log.info("Payment failed for event {}", event.getId());
36 default ->
37 log.debug("Ignoring unhandled Stripe event type {}", event.getType());
38 }
39 
40 return ResponseEntity.ok("");
41 }
42}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Always verify a webhook's signature against a shared secret before trusting its payload.
  2. 2Return a clear 4xx for tampered requests and a 2xx for accepted events so the sender stops retrying.
  3. 3Branch on the event type so you only act on the events your system actually cares about.

Related explainers

Share this explainer

Here's the card — post it anywhere.

How a Stripe webhook controller works in Spring — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code