openclaw-meta-bridge / app /routes /meta_webhooks.py
Ordo
Initial public release
0e84a1f
import json
from datetime import datetime, timezone
from fastapi import APIRouter, Depends, Header, HTTPException, Request
from sqlmodel import Session
from ..config import get_settings
from ..db import get_session
from ..models import InboundEvent
from ..services.event_normalizer import normalize_meta_payload
from ..services.meta_signature import verify_meta_signature
from ..services.openclaw_client import send_event_to_openclaw
router = APIRouter(prefix="/meta", tags=["meta-webhooks"])
@router.get("/webhook")
async def verify_webhook(request: Request):
settings = get_settings()
params = dict(request.query_params)
if params.get("hub.mode") == "subscribe" and params.get("hub.verify_token") == settings.meta_webhook_verify_token:
challenge = params.get("hub.challenge")
return int(challenge) if challenge and challenge.isdigit() else challenge
raise HTTPException(status_code=403, detail="Webhook verification failed")
@router.post("/webhook")
async def receive_webhook(request: Request, session: Session = Depends(get_session), x_hub_signature_256: str | None = Header(default=None)):
raw = await request.body()
verify_meta_signature(raw, x_hub_signature_256)
try:
payload = json.loads(raw.decode("utf-8"))
normalized_events = normalize_meta_payload(payload)
except HTTPException:
raise
except Exception as exc:
raise HTTPException(status_code=400, detail=f"Could not normalize payload: {exc}")
stored = []
for event in normalized_events:
db_event = InboundEvent(**event.model_dump(), raw_payload=payload)
session.add(db_event)
session.commit()
session.refresh(db_event)
try:
await send_event_to_openclaw(event, db_event.id or 0)
db_event.forwarded_at = datetime.now(timezone.utc)
except Exception as exc:
db_event.forward_error = str(exc)[:1000]
session.add(db_event)
session.commit()
stored.append(db_event.id)
return {"status": "ok", "stored_event_ids": stored}