python 46 lines · 7 steps

Handling Stripe webhooks in Django

A Django view that verifies Stripe webhook signatures and fulfills paid orders idempotently.

Explained by highlit
1import json
2import logging
3 
4import stripe
5from django.conf import settings
6from django.http import HttpResponse, HttpResponseBadRequest
7from django.views.decorators.csrf import csrf_exempt
8from django.views.decorators.http import require_POST
9 
10from .models import Order
11from .tasks import send_receipt_email
12 
13logger = logging.getLogger(__name__)
14 
15 
16@csrf_exempt
17@require_POST
18def stripe_webhook(request):
19 payload = request.body
20 sig_header = request.META.get("HTTP_STRIPE_SIGNATURE")
21 
22 try:
23 event = stripe.Webhook.construct_event(
24 payload=payload,
25 sig_header=sig_header,
26 secret=settings.STRIPE_WEBHOOK_SECRET,
27 )
28 except ValueError:
29 logger.warning("Stripe webhook received malformed payload")
30 return HttpResponseBadRequest("Invalid payload")
31 except stripe.error.SignatureVerificationError:
32 logger.warning("Stripe webhook signature verification failed")
33 return HttpResponseBadRequest("Invalid signature")
34 
35 if event.type == "checkout.session.completed":
36 session = event.data.object
37 order = Order.objects.filter(
38 stripe_session_id=session.id, status=Order.Status.PENDING
39 ).first()
40 if order is not None:
41 order.mark_paid(payment_intent=session.payment_intent)
42 send_receipt_email.delay(order.pk)
43 else:
44 logger.info("Ignoring unhandled Stripe event %s", event.type)
45 
46 return HttpResponse(status=200)
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Always verify webhook signatures against a shared secret before trusting the payload.
  2. 2Filtering on a pending status makes fulfillment idempotent against duplicate webhook deliveries.
  3. 3Offload slow side effects like email to a background task and return 200 promptly.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Handling Stripe webhooks in Django — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code