Build a webhook receiver in FastAPI
A FastAPI endpoint that awaits the raw body for signature verification, compares digests safely, and offloads work to a background task.
FastAPI makes a webhook receiver a few lines, and Python’s hmac module handles
verification. The important part is awaiting the raw body before anything parses
it.
A minimal receiver
Read await request.body() for the raw bytes, compare the HMAC with hmac.compare_digest (constant-time), return 200, and offload work with BackgroundTasks. A bad signature returns 401.
import hmac, hashlib, os
from fastapi import FastAPI, Request, BackgroundTasks, HTTPException
app = FastAPI()
SECRET = os.environ["WEBHOOK_SECRET"].encode()
@app.post("/webhooks")
async def receive(request: Request, tasks: BackgroundTasks):
body = await request.body() # RAW bytes, not await request.json()
sig = request.headers.get("x-webhook-signature", "")
expected = hmac.new(SECRET, body, hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, sig): # constant-time
raise HTTPException(status_code=401, detail="bad signature")
tasks.add_task(process, body) # process asynchronously
return {"ok": True} # fast 2xx Acknowledge fast, process async
BackgroundTasks runs process after the response is sent, so the
provider gets its 200 quickly. For work that must survive
a restart, use a real task queue (Celery, RQ, arq) instead.
Point the provider’s webhook at a HookWatch endpoint and every delivery is captured with its response. When a handler raises, you can inspect the failure and replay the delivery once it’s fixed.
Keep reading
Start debugging your webhooks.
Point one endpoint at HookWatch, capture a failure, and replay it once it’s fixed. Free during beta.