Files
ipv6-sims/app/api/payments/webhook/route.ts
T
2026-05-19 12:48:41 +07:00

86 lines
2.5 KiB
TypeScript

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<NextResponse> {
// 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 }
);
}
}