Stripe Connect onboarding for creator payouts
cgen-ae9d1b4d6da44948955ebc6432921f89
This commit is contained in:
parent
8409c0fbcf
commit
8d86a493f0
1 changed files with 128 additions and 0 deletions
128
api/nexus/payments/payout-setup.ts
Normal file
128
api/nexus/payments/payout-setup.ts
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
import type { VercelRequest, VercelResponse } from "@vercel/node";
|
||||
import Stripe from "stripe";
|
||||
import { getAdminClient } from "../../_supabase";
|
||||
|
||||
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY || "", {
|
||||
apiVersion: "2024-11-20",
|
||||
});
|
||||
|
||||
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" });
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue