aethex-forge/api/nexus/payments/webhook.ts
Builder.io 932b4bd491 Update imports batch 28
cgen-c1da95dc141849ea909b37399f09c90c
2025-11-16 05:03:40 +00:00

180 lines
5.6 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-11-20",
});
const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET || "";
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();
const sig = req.headers["stripe-signature"] as string;
let event: Stripe.Event;
try {
if (!sig || !webhookSecret) {
return res
.status(400)
.json({ error: "Missing webhook signature or secret" });
}
const body =
typeof req.body === "string" ? req.body : JSON.stringify(req.body);
event = stripe.webhooks.constructEvent(body, sig, webhookSecret);
} catch (error: any) {
console.error("Webhook signature verification failed:", error.message);
return res
.status(400)
.json({ error: "Webhook signature verification failed" });
}
try {
switch (event.type) {
case "payment_intent.succeeded": {
const paymentIntent = event.data.object as Stripe.PaymentIntent;
const { opportunityId, creatorId, clientId } = paymentIntent.metadata;
// Find contract by payment intent ID
const { data: contract } = await admin
.from("nexus_contracts")
.select("*")
.eq("stripe_payment_intent_id", paymentIntent.id)
.single();
if (contract) {
// Update contract status
await admin
.from("nexus_contracts")
.update({
status: "active",
start_date: new Date().toISOString(),
})
.eq("id", contract.id);
// Create payment record if not already created
const { data: existingPayment } = await admin
.from("nexus_payments")
.select("id")
.eq("stripe_payment_intent_id", paymentIntent.id)
.single();
if (!existingPayment) {
await admin.from("nexus_payments").insert({
contract_id: contract.id,
amount: contract.total_amount,
creator_payout: contract.creator_payout_amount,
aethex_commission: contract.aethex_commission_amount,
payment_method: "stripe",
payment_status: "completed",
payment_date: new Date().toISOString(),
stripe_payment_intent_id: paymentIntent.id,
});
}
// Update creator earnings
const { data: creatorProfile } = await admin
.from("nexus_creator_profiles")
.select("total_earnings")
.eq("user_id", creatorId)
.single();
const newEarnings =
(creatorProfile?.total_earnings || 0) +
contract.creator_payout_amount;
await admin
.from("nexus_creator_profiles")
.update({ total_earnings: newEarnings })
.eq("user_id", creatorId);
// Update opportunity status
await admin
.from("nexus_opportunities")
.update({ status: "filled", selected_creator_id: creatorId })
.eq("id", opportunityId);
// Update application status
await admin
.from("nexus_applications")
.update({ status: "hired" })
.eq("opportunity_id", opportunityId)
.eq("creator_id", creatorId);
}
break;
}
case "payment_intent.payment_failed": {
const paymentIntent = event.data.object as Stripe.PaymentIntent;
// Find and update contract
const { data: contract } = await admin
.from("nexus_contracts")
.select("*")
.eq("stripe_payment_intent_id", paymentIntent.id)
.single();
if (contract) {
// Update contract to cancelled
await admin
.from("nexus_contracts")
.update({ status: "cancelled" })
.eq("id", contract.id);
// Create failed payment record
await admin.from("nexus_payments").insert({
contract_id: contract.id,
amount: contract.total_amount,
creator_payout: 0,
aethex_commission: 0,
payment_method: "stripe",
payment_status: "failed",
stripe_payment_intent_id: paymentIntent.id,
});
}
break;
}
case "charge.refunded": {
const charge = event.data.object as Stripe.Charge;
// Find payment by stripe charge ID
const { data: payment } = await admin
.from("nexus_payments")
.select("*")
.eq("stripe_charge_id", charge.id)
.single();
if (payment) {
// Update payment status
await admin
.from("nexus_payments")
.update({ payment_status: "refunded" })
.eq("id", payment.id);
// Update contract status
await admin
.from("nexus_contracts")
.update({ status: "cancelled" })
.eq("id", payment.contract_id);
}
break;
}
default:
console.log(`Unhandled event type: ${event.type}`);
}
return res.status(200).json({ received: true });
} catch (error: any) {
console.error("Webhook processing error:", error);
return res
.status(500)
.json({ error: error?.message || "Webhook processing failed" });
}
}