aethex-forge/api/nexus/payments/webhook.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

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-04-10",
});
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" });
}
}