57 lines
1.8 KiB
Python
57 lines
1.8 KiB
Python
"""Payments router — Stripe payment intent creation and webhook."""
|
|
from __future__ import annotations
|
|
|
|
from fastapi import APIRouter, Depends, Header, HTTPException, Request
|
|
from pydantic import BaseModel
|
|
|
|
import stripe
|
|
|
|
from dependencies import get_current_user_or_401, get_payment_service, get_admin_token
|
|
from services.payment_service import PaymentService
|
|
|
|
router = APIRouter(prefix='/api', tags=['payments'])
|
|
|
|
|
|
class CreateIntentRequest(BaseModel):
|
|
pack: str # 'starter' | 'studio' | 'agency'
|
|
|
|
|
|
@router.post('/payments/create-intent')
|
|
async def create_payment_intent(
|
|
body: CreateIntentRequest,
|
|
user=Depends(get_current_user_or_401),
|
|
service: PaymentService = Depends(get_payment_service),
|
|
):
|
|
"""Create a Stripe PaymentIntent for the selected credit pack.
|
|
|
|
Returns the client_secret needed to confirm payment in the frontend.
|
|
"""
|
|
try:
|
|
return service.create_payment_intent(body.pack, user['id'])
|
|
except ValueError as e:
|
|
raise HTTPException(400, str(e))
|
|
|
|
|
|
@router.post('/payments/webhook')
|
|
async def stripe_webhook(
|
|
request: Request,
|
|
stripe_signature: str = Header(None, alias='stripe-signature'),
|
|
service: PaymentService = Depends(get_payment_service),
|
|
admin_token: str = Depends(get_admin_token),
|
|
):
|
|
"""Receive Stripe webhook events.
|
|
|
|
Stripe sends payment_intent.succeeded here after a successful payment.
|
|
FastAPI verifies the signature before processing.
|
|
"""
|
|
payload = await request.body()
|
|
if not stripe_signature:
|
|
raise HTTPException(400, 'Missing stripe-signature header')
|
|
|
|
try:
|
|
await service.handle_webhook(payload, stripe_signature, admin_token)
|
|
except stripe.error.SignatureVerificationError:
|
|
raise HTTPException(400, 'Invalid Stripe webhook signature')
|
|
|
|
return {'received': True}
|