Webhooks
Xác thực và xử lý subscription webhook an toàn, idempotent.
Xác thực trước khi parse business event
Đọc raw request body, xác thực chữ ký bằng webhook secret, rồi mới parse JSON. Nếu framework đã biến đổi body, chữ ký có thể không còn khớp.
export async function POST(request: Request) {
const rawBody = await request.text()
const signature = request.headers.get("x-vietbilling-signature")
verifyVietBillingSignature(rawBody, signature, process.env.VIETBILLING_WEBHOOK_SECRET!)
const event = JSON.parse(rawBody)
if (await wasProcessed(event.id)) return new Response("ok")
await processBillingEvent(event)
await markProcessed(event.id)
return new Response("ok")
}
Tên header và thuật toán ký phải lấy từ cấu hình webhook hiện tại của Organization; không tự suy đoán chúng từ ví dụ minh họa.
Xử lý idempotent
Đặt unique constraint trên event id. Event có thể đến lại hoặc khác thứ tự. Xử lý các event Checkout, Order, Payment, Subscription và BenefitGrant theo cách idempotent, đối chiếu timestamp và resource id trước khi cập nhật.
Retry
Trả 2xx sau khi event đã được lưu bền vững. Trả lỗi tạm thời nếu hệ thống chưa thể xử lý để VietBilling retry; đẩy công việc nặng sang queue.