55from pydantic import BaseModel
66
77from middleware .auth import get_current_user
8- from services .stripe_service import (
9- create_billing_portal_session ,
10- create_checkout_session ,
8+ from services .razorpay_service import (
9+ create_subscription ,
1110 get_subscription_status ,
1211 handle_webhook ,
1312)
1716
1817
1918class CheckoutRequest (BaseModel ):
20- # Accept either a direct price_id or a plan_id + interval combo
21- price_id : str | None = None
22- plan_id : str | None = None
23- interval : str = "monthly" # "monthly" | "yearly"
19+ plan_id : str # "pro" | "agency"
20+ interval : str = "monthly"
2421
2522
2623# ---------------------------------------------------------------------------
@@ -29,19 +26,19 @@ class CheckoutRequest(BaseModel):
2926
3027@router .get ("/status" )
3128async def billing_status (current_user : Annotated [dict , Depends (get_current_user )]):
32- """Return the current subscription plan and Stripe status ."""
29+ """Return the current subscription plan and usage ."""
3330 return await get_subscription_status (user_id = current_user ["id" ])
3431
3532
36- @router .get ("/stripe -check" )
37- async def stripe_config_check (current_user : Annotated [dict , Depends (get_current_user )]):
38- """Return which Stripe env vars are configured (values masked)."""
33+ @router .get ("/payment -check" )
34+ async def payment_config_check (current_user : Annotated [dict , Depends (get_current_user )]):
35+ """Return which Razorpay env vars are configured (values masked)."""
3936 from config import settings
4037 return {
41- "STRIPE_SECRET_KEY " : bool (settings .STRIPE_SECRET_KEY ),
42- "STRIPE_WEBHOOK_SECRET " : bool (settings .STRIPE_WEBHOOK_SECRET ),
43- "STRIPE_PRO_PRICE_ID " : settings .pro_monthly_price_id or "NOT SET" ,
44- "STRIPE_AGENCY_PRICE_ID " : settings .agency_monthly_price_id or "NOT SET" ,
38+ "RAZORPAY_KEY_ID " : bool (settings .RAZORPAY_KEY_ID ),
39+ "RAZORPAY_KEY_SECRET " : bool (settings .RAZORPAY_KEY_SECRET ),
40+ "RAZORPAY_PRO_PLAN_ID " : settings .RAZORPAY_PRO_PLAN_ID or "NOT SET" ,
41+ "RAZORPAY_AGENCY_PLAN_ID " : settings .RAZORPAY_AGENCY_PLAN_ID or "NOT SET" ,
4542 "FRONTEND_URL" : settings .FRONTEND_URL or "NOT SET" ,
4643 }
4744
@@ -52,86 +49,35 @@ async def create_checkout(
5249 current_user : Annotated [dict , Depends (get_current_user )],
5350):
5451 """
55- Create a Stripe Checkout Session and return the hosted payment URL.
52+ Create a Razorpay subscription and return the hosted checkout URL.
5653 """
57- from config import settings
58-
59- # Resolve price_id from plan_id + interval if needed
60- price_id = body .price_id
61- if not price_id and body .plan_id :
62- plan_to_price = {
63- "pro" : {"monthly" : settings .pro_monthly_price_id , "yearly" : settings .pro_yearly_price_id },
64- "agency" : {"monthly" : settings .agency_monthly_price_id , "yearly" : settings .agency_yearly_price_id },
65- }
66- price_id = plan_to_price .get (body .plan_id , {}).get (body .interval , "" )
67-
68- if not price_id :
69- logger .error (
70- "Checkout failed: no price_id resolved. plan_id=%s interval=%s — "
71- "set STRIPE_PRO_PRICE_ID / STRIPE_AGENCY_PRICE_ID in backend .env" ,
72- body .plan_id ,
73- body .interval ,
74- )
54+ if body .plan_id not in ("pro" , "agency" ):
7555 raise HTTPException (
7656 status_code = status .HTTP_400_BAD_REQUEST ,
77- detail = "No valid price_id or plan_id provided ." ,
57+ detail = "plan_id must be 'pro' or 'agency' ." ,
7858 )
7959
8060 try :
81- url = await create_checkout_session (
61+ url = await create_subscription (
8262 user_id = current_user ["id" ],
83- price_id = price_id ,
63+ plan_id = body . plan_id ,
8464 email = current_user .get ("email" , "" ),
8565 )
8666 except RuntimeError as exc :
8767 logger .error ("Checkout failed for user %s: %s" , current_user ["id" ], exc )
8868 raise HTTPException (status_code = status .HTTP_502_BAD_GATEWAY , detail = str (exc ))
89- return {"checkout_url" : url }
90-
91-
92- @router .get ("/portal" )
93- async def billing_portal (current_user : Annotated [dict , Depends (get_current_user )]):
94- """
95- Create a Stripe Customer Portal session and return the portal URL so
96- the user can manage/cancel their subscription.
97- """
98- from database import get_supabase
99-
100- supabase = get_supabase ()
101- result = (
102- supabase .table ("user_profiles" )
103- .select ("stripe_customer_id" )
104- .eq ("id" , current_user ["id" ])
105- .single ()
106- .execute ()
107- )
108- customer_id = (result .data or {}).get ("stripe_customer_id" )
109-
110- if not customer_id :
111- raise HTTPException (
112- status_code = status .HTTP_404_NOT_FOUND ,
113- detail = "No Stripe customer found. Please subscribe first." ,
114- )
11569
116- url = await create_billing_portal_session (customer_id = customer_id )
117- if not url :
118- raise HTTPException (
119- status_code = status .HTTP_502_BAD_GATEWAY ,
120- detail = "Failed to create billing portal session." ,
121- )
122- return {"portal_url" : url }
70+ return {"checkout_url" : url }
12371
12472
12573@router .post ("/webhook" , include_in_schema = False )
126- async def stripe_webhook (request : Request ):
74+ async def razorpay_webhook (request : Request ):
12775 """
128- Receive and process Stripe webhook events.
129-
130- This endpoint must be reachable by Stripe (public URL) and must NOT
131- require authentication.
76+ Receive and process Razorpay webhook events.
77+ Must be publicly reachable — no auth required.
13278 """
13379 payload = await request .body ()
134- sig_header = request .headers .get ("stripe -signature" , "" )
80+ sig_header = request .headers .get ("x-razorpay -signature" , "" )
13581
13682 try :
13783 result = await handle_webhook (payload = payload , sig_header = sig_header )
@@ -142,7 +88,7 @@ async def stripe_webhook(request: Request):
14288 detail = str (exc ),
14389 )
14490 except Exception as exc :
145- logger .error ("Stripe webhook processing error: %s" , exc )
91+ logger .error ("Razorpay webhook processing error: %s" , exc )
14692 raise HTTPException (
14793 status_code = status .HTTP_500_INTERNAL_SERVER_ERROR ,
14894 detail = "Webhook processing failed." ,
0 commit comments