Next.js에서 Stripe와 Paystack 웹훅을 처리하는 방법 (App Router 방식)
Source: Dev.to
웹훅 서명 검증이 자주 실패하는 이유
개발자들이 SaaS 결제에서 가장 많이 겪는 문제는 웹훅 서명 검증입니다.
모든 설정을 마치고 테스트 결제가 성공해도 서버가 400 Bad Request 혹은 Signature Verification Failed 오류를 반환합니다.
Next .js App Router에서는 요청 본문이 어떻게 파싱되는지가 문제의 원인인 경우가 많습니다. Stripe와 Paystack은 서명을 검증하기 위해 원시 요청 본문이 필요하지만, Next .js는 종종 원시 페이로드에 접근하기 전에 JSON으로 파싱해 버립니다.
Stripe와 Paystack 웹훅을 처리하기 위한 골든 패턴 (2026)
app/api/webhooks/route.ts 파일을 생성합니다. App Router에서는 req.text()를 사용해 원시 본문을 얻고 자동 파싱을 방지할 수 있습니다.
import { NextResponse } from "next/server";
import crypto from "crypto";
export async function POST(req: Request) {
// 1️⃣ Get the raw body as text
const body = await req.text();
// 2️⃣ Grab the signature from headers
const signature =
req.headers.get("x-paystack-signature") ||
req.headers.get("stripe-signature");
if (!signature) {
return NextResponse.json(
{ error: "No signature" },
{ status: 400 }
);
}
// 3️⃣ Verify the signature (example for Paystack)
const hash = crypto
.createHmac("sha512", process.env.PAYSTACK_SECRET_KEY!)
.update(body)
.digest("hex");
if (hash !== signature) {
return NextResponse.json(
{ error: "Invalid signature" },
{ status: 401 }
);
}
// 4️⃣ Parse the body and handle the event
const event = JSON.parse(body);
if (event.event === "charge.success") {
// Handle successful payment in your database
console.log(
"Payment successful for:",
event.data.customer.email
);
}
return NextResponse.json(
{ received: true },
{ status: 200 }
);
}
미들웨어 고려 사항
전역 미들웨어로 라우트를 보호하고 있다면 웹훅 경로를 제외해야 합니다. 그렇지 않으면 결제 제공자가 로그인 페이지로 리다이렉트되어 API에 도달하지 못할 수 있습니다.
웹훅이 실패하면 어떻게 되나요?
웹훅 검증이 실패하면 사용자는 “Pro” 접근 권한을 받지 못하게 되고, 이로 인해 이탈률이 증가합니다. 올바른 처리는 사이드 프로젝트와 실제 비즈니스 사이의 차이를 만들죠.
추가 읽을거리
- 전체 구현 (Stripe, Paystack 및 데이터베이스 로직 포함): How to add Stripe or Paystack payments to your SaaS
- SassyPack 개요 (창업자를 위한 “Day 1” 기술적 골칫거리 해결): SassyPack
Happy coding!