WIP: pending changes — docs, webhook, nav/footer (committed per Sami request, not yet reviewed)
This commit is contained in:
@@ -1,74 +1,5 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import Stripe from "stripe";
|
||||
|
||||
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
|
||||
apiVersion: "2026-03-25.dahlia",
|
||||
});
|
||||
|
||||
const PRICE_IDS: Record<string, string | undefined> = {
|
||||
monthly: process.env.STRIPE_PRICE_MONTHLY,
|
||||
yearly: process.env.STRIPE_PRICE_YEARLY,
|
||||
};
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const body = await request.json();
|
||||
const { plan, email } = body;
|
||||
|
||||
if (!plan || !PRICE_IDS[plan]) {
|
||||
return NextResponse.json(
|
||||
{ error: "Invalid plan. Choose 'monthly' or 'yearly'." },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
const priceId = PRICE_IDS[plan];
|
||||
if (!priceId) {
|
||||
return NextResponse.json(
|
||||
{ error: "Price not configured. Please contact support." },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
|
||||
const appUrl = process.env.NEXT_PUBLIC_APP_URL || "https://dashcaddy.net";
|
||||
|
||||
const sessionParams: Stripe.Checkout.SessionCreateParams = {
|
||||
mode: "subscription",
|
||||
payment_method_types: ["card"],
|
||||
line_items: [
|
||||
{
|
||||
price: priceId,
|
||||
quantity: 1,
|
||||
},
|
||||
],
|
||||
success_url: `${appUrl}/success?session_id={CHECKOUT_SESSION_ID}`,
|
||||
cancel_url: `${appUrl}/pricing`,
|
||||
allow_promotion_codes: true,
|
||||
billing_address_collection: "required",
|
||||
subscription_data: {
|
||||
trial_period_days: 14,
|
||||
metadata: {
|
||||
plan,
|
||||
source: "dashcaddy-website",
|
||||
},
|
||||
},
|
||||
metadata: {
|
||||
plan,
|
||||
},
|
||||
};
|
||||
|
||||
// Pre-fill email if provided
|
||||
if (email) {
|
||||
sessionParams.customer_email = email;
|
||||
}
|
||||
|
||||
const session = await stripe.checkout.sessions.create(sessionParams);
|
||||
|
||||
return NextResponse.json({ url: session.url });
|
||||
} catch (error) {
|
||||
console.error("Stripe checkout error:", error);
|
||||
const message =
|
||||
error instanceof Error ? error.message : "Internal server error";
|
||||
return NextResponse.json({ error: message }, { status: 500 });
|
||||
}
|
||||
}
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
return NextResponse.json({ error: 'Checkout disabled for static export' }, { status: 503 });
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
return NextResponse.json({ error: 'Webhooks disabled for static export' }, { status: 503 });
|
||||
}
|
||||
@@ -1,99 +1,4 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import Stripe from "stripe";
|
||||
|
||||
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
|
||||
apiVersion: "2026-03-25.dahlia",
|
||||
});
|
||||
|
||||
const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET!;
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
const body = await request.text();
|
||||
const signature = request.headers.get("stripe-signature");
|
||||
|
||||
if (!signature) {
|
||||
return NextResponse.json(
|
||||
{ error: "Missing stripe-signature header" },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
let event: Stripe.Event;
|
||||
|
||||
try {
|
||||
event = stripe.webhooks.constructEvent(body, signature, webhookSecret);
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : "Unknown error";
|
||||
console.error(`Webhook signature verification failed: ${message}`);
|
||||
return NextResponse.json({ error: message }, { status: 400 });
|
||||
}
|
||||
|
||||
try {
|
||||
switch (event.type) {
|
||||
case "checkout.session.completed": {
|
||||
const session = event.data.object as Stripe.Checkout.Session;
|
||||
console.log("Checkout completed:", {
|
||||
sessionId: session.id,
|
||||
customerEmail: session.customer_email,
|
||||
plan: session.metadata?.plan,
|
||||
subscriptionId: session.subscription,
|
||||
});
|
||||
|
||||
// TODO: Generate and deliver license key to customer
|
||||
// This is where you'd:
|
||||
// 1. Generate a DC-XXXXX-XXXXX-XXXXX-XXXXX-XXXXX license code
|
||||
// 2. Store it in your database
|
||||
// 3. Email it to the customer
|
||||
// 4. Associate it with the Stripe subscription ID
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "customer.subscription.updated": {
|
||||
const subscription = event.data.object as Stripe.Subscription;
|
||||
console.log("Subscription updated:", {
|
||||
subscriptionId: subscription.id,
|
||||
status: subscription.status,
|
||||
});
|
||||
|
||||
// TODO: Update license expiration based on subscription status
|
||||
break;
|
||||
}
|
||||
|
||||
case "customer.subscription.deleted": {
|
||||
const subscription = event.data.object as Stripe.Subscription;
|
||||
console.log("Subscription cancelled:", {
|
||||
subscriptionId: subscription.id,
|
||||
status: subscription.status,
|
||||
});
|
||||
|
||||
// TODO: Deactivate/expire the license key
|
||||
// The DashCaddy instance will gracefully downgrade to free tier
|
||||
break;
|
||||
}
|
||||
|
||||
case "invoice.payment_failed": {
|
||||
const invoice = event.data.object as Stripe.Invoice;
|
||||
console.log("Payment failed:", {
|
||||
invoiceId: invoice.id,
|
||||
customerEmail: invoice.customer_email,
|
||||
});
|
||||
|
||||
// TODO: Notify customer about failed payment
|
||||
// Consider a grace period before deactivating license
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
console.log(`Unhandled event type: ${event.type}`);
|
||||
}
|
||||
|
||||
return NextResponse.json({ received: true });
|
||||
} catch (error) {
|
||||
console.error("Webhook handler error:", error);
|
||||
return NextResponse.json(
|
||||
{ error: "Webhook handler failed" },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
export async function POST(request: NextRequest) {
|
||||
return NextResponse.json({ error: 'disabled' }, { status: 503 });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user