98 lines
3.5 KiB
Python
98 lines
3.5 KiB
Python
"""
|
|
Webhook endpoints for handling payment provider events
|
|
These endpoints receive events from payment providers like Stripe
|
|
All event processing is handled by SubscriptionOrchestrationService
|
|
"""
|
|
|
|
import structlog
|
|
import stripe
|
|
from fastapi import APIRouter, Depends, HTTPException, status, Request
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.services.subscription_orchestration_service import SubscriptionOrchestrationService
|
|
from app.core.config import settings
|
|
from app.core.database import get_db
|
|
|
|
logger = structlog.get_logger()
|
|
router = APIRouter()
|
|
|
|
|
|
def get_subscription_orchestration_service(
|
|
db: AsyncSession = Depends(get_db)
|
|
) -> SubscriptionOrchestrationService:
|
|
"""Dependency injection for SubscriptionOrchestrationService"""
|
|
try:
|
|
return SubscriptionOrchestrationService(db)
|
|
except Exception as e:
|
|
logger.error("Failed to create subscription orchestration service", error=str(e))
|
|
raise HTTPException(status_code=500, detail="Service initialization failed")
|
|
|
|
|
|
@router.post("/webhooks/stripe")
|
|
async def stripe_webhook(
|
|
request: Request,
|
|
orchestration_service: SubscriptionOrchestrationService = Depends(get_subscription_orchestration_service)
|
|
):
|
|
"""
|
|
Stripe webhook endpoint to handle payment events
|
|
This endpoint verifies webhook signatures and processes Stripe events
|
|
"""
|
|
try:
|
|
# Get the payload and signature
|
|
payload = await request.body()
|
|
sig_header = request.headers.get('stripe-signature')
|
|
|
|
if not sig_header:
|
|
logger.error("Missing stripe-signature header")
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail="Missing signature header"
|
|
)
|
|
|
|
# Verify the webhook signature
|
|
try:
|
|
event = stripe.Webhook.construct_event(
|
|
payload, sig_header, settings.STRIPE_WEBHOOK_SECRET
|
|
)
|
|
except stripe.error.SignatureVerificationError as e:
|
|
logger.error("Invalid webhook signature", error=str(e))
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail="Invalid signature"
|
|
)
|
|
except ValueError as e:
|
|
logger.error("Invalid payload", error=str(e))
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail="Invalid payload"
|
|
)
|
|
|
|
# Get event type and data
|
|
event_type = event['type']
|
|
event_data = event['data']['object']
|
|
|
|
logger.info("Processing Stripe webhook event",
|
|
event_type=event_type,
|
|
event_id=event.get('id'))
|
|
|
|
# Use orchestration service to handle the event
|
|
result = await orchestration_service.handle_payment_webhook(event_type, event_data)
|
|
|
|
logger.info("Webhook event processed via orchestration service",
|
|
event_type=event_type,
|
|
actions_taken=result.get("actions_taken", []))
|
|
|
|
return {"success": True, "event_type": event_type, "actions_taken": result.get("actions_taken", [])}
|
|
|
|
except HTTPException:
|
|
raise
|
|
except Exception as e:
|
|
logger.error("Error processing Stripe webhook", error=str(e), exc_info=True)
|
|
# Return 200 OK even on processing errors to prevent Stripe retries
|
|
# Only return 4xx for signature verification failures
|
|
return {
|
|
"success": False,
|
|
"error": "Webhook processing error",
|
|
"details": str(e)
|
|
}
|