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

127 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",
});
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 { opportunityId, creatorId, amount, contractType } = req.body;
if (!opportunityId || !creatorId || !amount || !contractType) {
return res.status(400).json({
error:
"Missing required fields: opportunityId, creatorId, amount, contractType",
});
}
// Verify the user is the client who posted the opportunity
const { data: opportunity, error: oppError } = await admin
.from("nexus_opportunities")
.select("posted_by, title")
.eq("id", opportunityId)
.single();
if (oppError || !opportunity || opportunity.posted_by !== user.id) {
return res.status(403).json({
error: "Not authorized to post contracts for this opportunity",
});
}
// Verify the creator has applied
const { data: application, error: appError } = await admin
.from("nexus_applications")
.select("id, status")
.eq("opportunity_id", opportunityId)
.eq("creator_id", creatorId)
.single();
if (appError || !application || application.status !== "accepted") {
return res
.status(400)
.json({ error: "Creator application not accepted" });
}
// Calculate commission (20% to AeThex)
const commissionPercent = 20;
const commissionAmount = Math.round((amount * commissionPercent) / 100);
const creatorPayout = Math.round(amount - commissionAmount);
// Create Stripe payment intent
const paymentIntent = await stripe.paymentIntents.create({
amount: Math.round(amount * 100), // Convert to cents
currency: "usd",
metadata: {
opportunityId,
creatorId,
clientId: user.id,
contractType,
},
description: `NEXUS Contract: ${opportunity.title}`,
});
// Create contract record
const { data: contract, error: contractError } = await admin
.from("nexus_contracts")
.insert({
opportunity_id: opportunityId,
creator_id: creatorId,
client_id: user.id,
title: opportunity.title,
contract_type: contractType,
total_amount: amount,
aethex_commission_percent: commissionPercent,
aethex_commission_amount: commissionAmount,
creator_payout_amount: creatorPayout,
status: "pending",
})
.select()
.single();
if (contractError) {
return res.status(500).json({ error: contractError.message });
}
// Store payment intent ID in contract
await admin
.from("nexus_contracts")
.update({ stripe_payment_intent_id: paymentIntent.id })
.eq("id", contract.id);
return res.status(200).json({
clientSecret: paymentIntent.client_secret,
contractId: contract.id,
paymentIntentId: paymentIntent.id,
amount,
commissionAmount,
creatorPayout,
});
} catch (error: any) {
console.error("Payment intent error:", error);
return res.status(500).json({ error: error?.message || "Server error" });
}
}