""" Webhook endpoints for external service integrations. - Stripe payment webhooks - Future: Other payment providers, notification services, etc. """ import logging import os from datetime import datetime from fastapi import APIRouter, HTTPException, Request, Header, status from app.database import get_db from app.services.stripe_service import StripeService logger = logging.getLogger(__name__) router = APIRouter() @router.get("/stripe/test") async def test_stripe_webhook(): """ Test endpoint to verify webhook route is accessible. Use this to verify the webhook URL is correct. The actual Stripe webhook should POST to /api/v1/webhooks/stripe """ return { "status": "ok", "message": "Stripe webhook endpoint is accessible", "endpoint": "/api/v1/webhooks/stripe", "method": "POST", "stripe_configured": StripeService.is_configured(), "webhook_secret_set": bool(os.getenv("STRIPE_WEBHOOK_SECRET")), "timestamp": datetime.utcnow().isoformat(), } @router.post("/stripe") async def stripe_webhook( request: Request, stripe_signature: str = Header(None, alias="Stripe-Signature"), ): """ Handle Stripe webhook events. This endpoint receives events from Stripe when: - Payment succeeds or fails - Subscription is updated or cancelled - Invoice is created or paid The webhook must be configured in Stripe Dashboard to point to: https://pounce.ch/api/v1/webhooks/stripe Required Header: - Stripe-Signature: Stripe's webhook signature for verification """ logger.info("🔔 Stripe webhook received") if not stripe_signature: logger.error("❌ Missing Stripe-Signature header") raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Missing Stripe-Signature header", ) if not StripeService.is_configured(): logger.error("❌ Stripe not configured") raise HTTPException( status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="Stripe not configured", ) # Get raw body for signature verification payload = await request.body() logger.info(f" Payload size: {len(payload)} bytes") logger.info(f" Signature: {stripe_signature[:50]}...") try: async for db in get_db(): result = await StripeService.handle_webhook( payload=payload, sig_header=stripe_signature, db=db, ) logger.info(f"✅ Webhook processed successfully: {result}") return result except ValueError as e: logger.error(f"❌ Webhook validation error: {e}") raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=str(e), ) except Exception as e: logger.exception(f"❌ Webhook processing error: {e}") raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Webhook processing failed", )