Initial commit - production deployment
This commit is contained in:
97
services/tenant/app/api/webhooks.py
Normal file
97
services/tenant/app/api/webhooks.py
Normal file
@@ -0,0 +1,97 @@
|
||||
"""
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user