aethex-forge/api/nexus/payments/payout-setup.ts
sirpiglr 312072a869 Fix various type errors in API files to ensure proper functionality
Resolves TypeScript errors across multiple API files, including Stripe API version mismatches and incorrect type assertions for request data, enabling successful Vercel builds.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 9203795e-937a-4306-b81d-b4d5c78c240e
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: c124cc2e-6c8d-4ca4-80d3-5d34ca7aed66
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/7c94b7a0-29c7-4f2e-94ef-44b2153872b7/9203795e-937a-4306-b81d-b4d5c78c240e/qPXTzuE
Replit-Helium-Checkpoint-Created: true
2025-12-08 01:29:26 +00:00

129 lines
3.8 KiB
TypeScript

import type { VercelRequest, VercelResponse } from "@vercel/node";
import Stripe from "stripe";
import { getAdminClient } from "../../_supabase.js";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY || "", {
apiVersion: "2024-04-10",
});
const apiBase = process.env.VITE_API_BASE || "https://aethex.dev";
export default async function handler(req: VercelRequest, res: VercelResponse) {
if (req.method !== "POST") {
return res.status(405).json({ error: "Method not allowed" });
}
const admin = getAdminClient();
// Only authenticated requests
const authHeader = req.headers.authorization;
if (!authHeader) {
return res.status(401).json({ error: "Unauthorized" });
}
const token = authHeader.replace("Bearer ", "");
const {
data: { user },
error: authError,
} = await admin.auth.getUser(token);
if (authError || !user) {
return res.status(401).json({ error: "Invalid token" });
}
try {
const { type } = req.body;
if (!type || !["create", "complete"].includes(type)) {
return res.status(400).json({
error: "Invalid type. Must be 'create' or 'complete'",
});
}
if (type === "create") {
// Check if creator already has a Stripe Connect account
const { data: creatorProfile } = await admin
.from("nexus_creator_profiles")
.select("stripe_connect_account_id")
.eq("user_id", user.id)
.single();
let accountId = creatorProfile?.stripe_connect_account_id;
if (!accountId) {
// Create a new Stripe Connect account
const account = await stripe.accounts.create({
type: "express",
country: "US",
email: user.email || "",
metadata: {
aethex_user_id: user.id,
},
});
accountId = account.id;
// Save account ID
await admin
.from("nexus_creator_profiles")
.update({ stripe_connect_account_id: accountId })
.eq("user_id", user.id);
}
// Create onboarding link
const onboardingLink = await stripe.accountLinks.create({
account: accountId,
type: "account_onboarding",
refresh_url: `${apiBase}/dashboard/nexus?tab=profile&stripe_refresh=true`,
return_url: `${apiBase}/dashboard/nexus?tab=profile&stripe_complete=true`,
});
return res.status(200).json({
onboardingUrl: onboardingLink.url,
accountId,
});
}
if (type === "complete") {
// Verify onboarding is complete
const { data: creatorProfile } = await admin
.from("nexus_creator_profiles")
.select("stripe_connect_account_id")
.eq("user_id", user.id)
.single();
if (!creatorProfile?.stripe_connect_account_id) {
return res
.status(400)
.json({ error: "No Stripe Connect account found" });
}
const account = await stripe.accounts.retrieve(
creatorProfile.stripe_connect_account_id,
);
if (!account.charges_enabled || !account.payouts_enabled) {
return res.status(400).json({
error:
"Account setup not complete. Please complete all required steps.",
chargesEnabled: account.charges_enabled,
payoutsEnabled: account.payouts_enabled,
});
}
// Update creator profile to mark as verified
await admin
.from("nexus_creator_profiles")
.update({ verified: true, stripe_account_verified: true })
.eq("user_id", user.id);
return res.status(200).json({
success: true,
verified: true,
message: "Stripe Connect account setup complete",
});
}
} catch (error: any) {
console.error("Payout setup error:", error);
return res.status(500).json({ error: error?.message || "Server error" });
}
}