python
42 lines · 7 steps
Handling Stripe webhooks in FastAPI
A FastAPI endpoint that verifies Stripe's signature, then routes each event type to the right billing action.
Explained by
highlit
1import stripe
2from fastapi import APIRouter, Request, Header, HTTPException
3
4from app.config import settings
5from app.services.billing import (
6 activate_subscription,
7 mark_payment_failed,
8 cancel_subscription,
9)
10
11router = APIRouter(prefix="/webhooks", tags=["webhooks"])
12
13
14@router.post("/stripe", status_code=200)
15async def handle_stripe_webhook(
16 request: Request,
17 stripe_signature: str = Header(..., alias="Stripe-Signature"),
18):
19 payload = await request.body()
20
21 try:
22 event = stripe.Webhook.construct_event(
23 payload=payload,
24 sig_header=stripe_signature,
25 secret=settings.STRIPE_WEBHOOK_SECRET,
26 )
27 except ValueError:
28 raise HTTPException(status_code=400, detail="Invalid payload")
29 except stripe.error.SignatureVerificationError:
30 raise HTTPException(status_code=400, detail="Invalid signature")
31
32 obj = event["data"]["object"]
33
34 match event["type"]:
35 case "checkout.session.completed":
36 await activate_subscription(obj["customer"], obj["subscription"])
37 case "invoice.payment_failed":
38 await mark_payment_failed(obj["customer"], obj["id"])
39 case "customer.subscription.deleted":
40 await cancel_subscription(obj["customer"])
41
42 return {"received": True}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Always verify a webhook's signature against a shared secret before trusting its contents.
- 2Read the raw request body for signature checks — parsed JSON won't match the signed bytes.
- 3Return 200 quickly and delegate the actual work so the provider considers the event delivered.
Related explainers
python
from operator import itemgetter def sort_employees(employees):
Multi-key sorting patterns in Python
sorting
tuple-keys
itemgetter
Intermediate
5 steps
javascript
const express = require('express'); const Stripe = require('stripe'); const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
Verifying Stripe webhooks in Express
webhooks
signature-verification
raw-body
Intermediate
7 steps
python
from itertools import islice from typing import Iterable, Iterator, TypeVar T = TypeVar("T")
Batching an iterable for bulk indexing
generators
batching
lazy-evaluation
Intermediate
7 steps
python
import time from dataclasses import dataclass, field from fastapi import Depends, FastAPI, HTTPException, Request, status
Token-bucket rate limiting in FastAPI
rate-limiting
token-bucket
dependency-injection
Advanced
10 steps
python
import argparse import sys from pathlib import Path
Building a subcommand CLI with argparse
cli
argparse
subcommands
Intermediate
6 steps
python
from collections.abc import Mapping from typing import Any, Iterator
Flattening nested config into dotted keys
recursion
generators
tree-traversal
Intermediate
7 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/handling-stripe-webhooks-in-fastapi-explained-python-c335/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.