export const runtime = "nodejs"; import { NextRequest, NextResponse } from "next/server"; import { verifyWebhookSignature } from "@/lib/paypal"; import { markPaymentPaid } from "@/lib/summit-requests"; export async function POST(req: NextRequest): Promise { // Read raw body as text for signature verification const rawBody = await req.text(); // Parse the body as JSON const event = JSON.parse(rawBody); // Read required PayPal signature headers const transmissionId = req.headers.get("paypal-transmission-id"); const transmissionTime = req.headers.get("paypal-transmission-time"); const certUrl = req.headers.get("paypal-cert-url"); const authAlgo = req.headers.get("paypal-auth-algo"); const transmissionSig = req.headers.get("paypal-transmission-sig"); // Return 401 if any required header is missing if (!transmissionId || !transmissionTime || !certUrl || !authAlgo || !transmissionSig) { return NextResponse.json( { error: "Missing PayPal signature headers." }, { status: 401 } ); } // Verify webhook signature const isValid = await verifyWebhookSignature({ authAlgo, certUrl, transmissionId, transmissionSig, transmissionTime, webhookId: process.env.PAYPAL_WEBHOOK_ID ?? "", webhookEvent: event, }); if (!isValid) { return NextResponse.json( { error: "Invalid webhook signature." }, { status: 401 } ); } console.log( "[webhook] Received event:", event.event_type, "resource_id:", event.resource?.id, "transmission_id:", transmissionId ); try { if (event.event_type === "PAYMENT.CAPTURE.COMPLETED") { const orderId = event.resource?.supplementary_data?.related_ids?.order_id ?? event.resource?.id; const result = await markPaymentPaid(orderId, event.resource.id); console.log( "[webhook] markPaymentPaid result for orderId:", orderId, "captureId:", event.resource.id, result ); return NextResponse.json({ received: true }, { status: 200 }); } // All other event types — acknowledge and ignore console.log("[webhook] Ignoring unhandled event type:", event.event_type); return NextResponse.json({ received: true }, { status: 200 }); } catch (err) { console.error("[webhook] Internal error processing event:", event.event_type, err); // Return 500 so PayPal retries the webhook return NextResponse.json( { error: "Internal server error." }, { status: 500 } ); } }