import { type NextRequest, NextResponse } from "next/server" import createMollieClient from "@mollie/api-client" import { updatePaymentStatus } from "@/lib/google-sheets" import { sendPaymentConfirmation } from "@/lib/email" import { addToListmonk } from "@/lib/listmonk" // Lazy initialization let mollieClient: ReturnType | null = null function getMollie() { if (!mollieClient) { mollieClient = createMollieClient({ apiKey: process.env.MOLLIE_API_KEY! }) } return mollieClient } export async function POST(request: NextRequest) { try { // Mollie sends payment ID in the body as form data const formData = await request.formData() const paymentId = formData.get("id") as string if (!paymentId) { console.error("[Webhook] No payment ID received") return NextResponse.json({ error: "Missing payment ID" }, { status: 400 }) } // Fetch the full payment from Mollie API (this is how you verify — no signature needed) const payment = await getMollie().payments.get(paymentId) const metadata = (payment.metadata || {}) as Record console.log(`[Webhook] Payment ${paymentId} status: ${payment.status}`) if (payment.status === "paid") { const customerEmail = payment.billingAddress?.email || "" const amountPaid = `€${payment.amount.value}` // Update Google Sheet const updated = await updatePaymentStatus({ name: metadata.name || "", email: customerEmail, paymentSessionId: paymentId, paymentStatus: "Paid", paymentMethod: payment.method || "unknown", amountPaid, paymentDate: new Date().toISOString(), }) if (updated) { console.log(`[Webhook] Google Sheet updated for ${metadata.name}`) } else { console.error(`[Webhook] Failed to update Google Sheet for ${metadata.name}`) } // Send confirmation email if (customerEmail) { await sendPaymentConfirmation({ name: metadata.name || "", email: customerEmail, amountPaid, paymentMethod: payment.method || "card", contributions: metadata.contributions || "", dietary: metadata.dietary || "", }) // Add to Listmonk newsletter addToListmonk({ email: customerEmail, name: metadata.name || "", attribs: { contact: metadata.contact, contributions: metadata.contributions, expectations: metadata.expectations, }, }).catch((err) => console.error("[Webhook] Listmonk sync failed:", err)) } } else if (payment.status === "failed" || payment.status === "canceled" || payment.status === "expired") { console.log(`[Webhook] Payment ${payment.status}: ${paymentId}`) if (metadata.name) { await updatePaymentStatus({ name: metadata.name, paymentSessionId: paymentId, paymentStatus: "Failed", paymentDate: new Date().toISOString(), }) } } // Mollie expects 200 OK return NextResponse.json({ received: true }) } catch (err) { console.error("[Webhook] Error:", err) return NextResponse.json({ error: "Webhook error" }, { status: 500 }) } }