import structlog from fastapi import APIRouter, Request, Response router = APIRouter() logger = structlog.get_logger("aoc.webhooks") @router.post("/webhooks/graph") async def graph_webhook(request: Request): """ Receive Microsoft Graph change notifications. Handles the validation handshake by echoing validationToken. """ validation_token = request.query_params.get("validationToken") if validation_token: return Response(content=validation_token, media_type="text/plain") try: body = await request.json() except Exception as exc: logger.warning("Invalid webhook payload", error=str(exc)) return Response(status_code=400) for notification in body.get("value", []): logger.info( "Received Graph notification", change_type=notification.get("changeType"), resource=notification.get("resource"), client_state=notification.get("clientState"), ) return {"status": "accepted"}