# Receive + verify a CodeB webhook in Python (FastAPI). # Events include call.started, call.answered, call.ended, transcript.saved, # call.ice.connected, call.transferred, outbound-ai.finished, # sfu.publisher.connected, sfu.subscriber.connected. # European Digital Identity Wallet sign-in events flow through the same # dispatcher; verification is identical. # [webhooks-cookbook 2026-07-23] # pip install fastapi uvicorn import hmac, hashlib, os, json from fastapi import FastAPI, Request, Header, HTTPException SECRET = os.environ["CODEB_WEBHOOK_SECRET"].encode("utf-8") app = FastAPI() @app.post("/webhook") async def webhook( request: Request, x_codeb_signature: str | None = Header(None), x_codeb_event: str | None = Header(None), x_codeb_delivery_id: str | None = Header(None), ): raw = await request.body() # exact bytes; HMAC input mac = hmac.new(SECRET, raw, hashlib.sha256).hexdigest() want = f"sha256={mac}" if not x_codeb_signature or not hmac.compare_digest(x_codeb_signature, want): raise HTTPException(status_code=401, detail="bad signature") payload = json.loads(raw.decode("utf-8")) print(f"[{x_codeb_delivery_id}] {x_codeb_event}", payload) # ... process asynchronously; ACK within 5s. return {"ok": True} # Run: uvicorn webhook_receive:app --port 4000