Stripe checkout: products created, signup flow with plan selection, API endpoints
This commit is contained in:
@@ -4,7 +4,8 @@ module.exports = {
|
||||
script: '/var/www/autojobs/backend/start_server.py',
|
||||
interpreter: 'python3',
|
||||
env: {
|
||||
DB_PATH: '/var/www/autojobs/autojobs.db'
|
||||
DB_PATH: '/var/www/autojobs/autojobs.db',
|
||||
STRIPE_SECRET_KEY: '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'
|
||||
},
|
||||
autorestart: true,
|
||||
watch: false,
|
||||
|
||||
+107
-2
@@ -1,8 +1,10 @@
|
||||
"""
|
||||
AutoJobs API — FastAPI Backend
|
||||
Multi-user job search with per-user API keys + subscription plans
|
||||
import os
|
||||
import stripe
|
||||
"""
|
||||
from fastapi import FastAPI, HTTPException, Depends, APIRouter
|
||||
from fastapi import FastAPI, HTTPException, Depends, APIRouter, Request
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
|
||||
from pydantic import BaseModel
|
||||
@@ -926,4 +928,107 @@ def admin_reset_usage(user_id: str = None):
|
||||
|
||||
if __name__ == "__main__":
|
||||
import uvicorn
|
||||
uvicorn.run(app, host="0.0.0.0", port=8000)
|
||||
uvicorn.run(app, host="0.0.0.0", port=8000)
|
||||
# --- Stripe Price IDs ---
|
||||
STRIPE_PRICE_IDS = {
|
||||
"free": None,
|
||||
"starter": "price_1TLp9OEqqBlW1z4N8zXPHPjM",
|
||||
"pro": "price_1TLp9PEqqBlW1z4NmP5sVrA1",
|
||||
"ultra": "price_1TLp9QEqqBlW1z4NpjjV13Kb",
|
||||
"unlimited": "price_1TLp9REqqBlW1z4NR2c92fmM",
|
||||
"agency_starter": "price_1TLp9SEqqBlW1z4Ny9MabLz3",
|
||||
"agency_growth": "price_1TLp9TEqqBlW1z4N2t2noudV",
|
||||
"agency_scale": "price_1TLp9UEqqBlW1z4NgWPSg7nr",
|
||||
"agency_pro": "price_1TLp9VEqqBlW1z4NgtQWlUnv",
|
||||
"agency_enterprise": None,
|
||||
}
|
||||
|
||||
# --- Stripe Checkout Endpoint ---
|
||||
@app.post("/autojobs/api/create-checkout")
|
||||
async def create_checkout(request: Request):
|
||||
try:
|
||||
body = await request.json()
|
||||
plan_id = body.get("plan_id")
|
||||
user_id = body.get("user_id")
|
||||
user_type = body.get("user_type", "private")
|
||||
|
||||
if not plan_id or not user_id:
|
||||
return JSONResponse({"error": "Missing plan_id or user_id"}, status_code=400)
|
||||
|
||||
price_id = STRIPE_PRICE_IDS.get(plan_id)
|
||||
if price_id is None and plan_id != "agency_enterprise":
|
||||
return JSONResponse({"error": "Invalid plan"}, status_code=400)
|
||||
|
||||
user = db.get("SELECT * FROM users WHERE id = ?", (user_id,))
|
||||
if not user:
|
||||
return JSONResponse({"error": "User not found"}, status_code=404)
|
||||
|
||||
if plan_id == "free":
|
||||
# Free plan - just update and return
|
||||
db.run("UPDATE users SET plan = ?, user_type = ? WHERE id = ?", (plan_id, user_type, user_id))
|
||||
return JSONResponse({"success": True, "plan": plan_id})
|
||||
|
||||
if plan_id == "agency_enterprise":
|
||||
return JSONResponse({"error": "Contact us for enterprise pricing"}, status_code=400)
|
||||
|
||||
# Get or create Stripe customer
|
||||
stripe.api_key = os.environ.get("STRIPE_SECRET_KEY")
|
||||
customer = stripe.Customer.create(
|
||||
email=user["email"],
|
||||
name=user["name"],
|
||||
metadata={"autojobs_user_id": str(user_id)}
|
||||
)
|
||||
|
||||
checkout_session = stripe.checkout.Session.create(
|
||||
customer=customer.id,
|
||||
payment_method_types=["card"],
|
||||
line_items=[{"price": price_id, "quantity": 1}],
|
||||
mode="subscription",
|
||||
success_url="https://hostpioneers.com/autojobs/dashboard?session_id={CHECKOUT_SESSION_ID}",
|
||||
cancel_url="https://hostpioneers.com/autojobs/pricing?canceled=true",
|
||||
metadata={"user_id": str(user_id), "plan_id": plan_id, "user_type": user_type},
|
||||
subscription_data={"metadata": {"user_id": str(user_id), "plan_id": plan_id}}
|
||||
)
|
||||
|
||||
return JSONResponse({"checkout_url": checkout_session.url})
|
||||
|
||||
except Exception as e:
|
||||
import traceback
|
||||
return JSONResponse({"error": str(e), "trace": traceback.format_exc()}, status_code=500)
|
||||
|
||||
# --- Stripe Webhook ---
|
||||
@app.post("/autojobs/api/stripe-webhook")
|
||||
async def stripe_webhook(request: Request):
|
||||
stripe.api_key = os.environ.get("STRIPE_SECRET_KEY")
|
||||
payload = await request.body()
|
||||
sig = request.headers.get("stripe-signature", "")
|
||||
webhook_secret = os.environ.get("STRIPE_WEBHOOK_SECRET", "")
|
||||
|
||||
try:
|
||||
if webhook_secret:
|
||||
event = stripe.Webhook.construct_event(payload, sig, webhook_secret)
|
||||
else:
|
||||
event = json.loads(payload)
|
||||
|
||||
event_type = event.get("type", "")
|
||||
|
||||
if event_type == "checkout.session.completed":
|
||||
session = event["data"]["object"]
|
||||
user_id = session["metadata"]["user_id"]
|
||||
plan_id = session["metadata"]["plan_id"]
|
||||
stripe_sub_id = session.get("subscription")
|
||||
|
||||
db.run("UPDATE users SET plan = ?, stripe_subscription_id = ?, stripe_customer_id = ? WHERE id = ?",
|
||||
(plan_id, stripe_sub_id, session.get("customer"), user_id))
|
||||
|
||||
elif event_type == "customer.subscription.deleted":
|
||||
sub = event["data"]["object"]
|
||||
customer_id = sub.get("customer")
|
||||
db.run("UPDATE users SET plan = 'free' WHERE stripe_customer_id = ?", (customer_id,))
|
||||
|
||||
return JSONResponse({"received": True})
|
||||
|
||||
except Exception as e:
|
||||
import traceback
|
||||
return JSONResponse({"error": str(e), "trace": traceback.format_exc()}, status_code=400)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user