How SePay IPN Webhooks work
SePay delivers transaction notifications to your server using HTTP POST Instant Payment Notifications (IPN). To protect SaaS revenue and prevent duplicate access grants, your webhook handler must strictly verify authentication, enforce idempotency, and validate payment integrity.
Authenticating with Header X-Secret-Key
Every inbound SePay IPN request includes the merchant secret in the X-Secret-Key header. Compare this incoming token using constant-time string comparison to prevent timing side-channel attacks:
function verifySePayAuth(headerKey: string | undefined, expectedKey: string): boolean {
if (!headerKey || typeof headerKey !== "string") return false;
return crypto.timingSafeEqual(
Buffer.from(headerKey),
Buffer.from(expectedKey)
);
}
Verifying ORDER_PAID status and amount matching
Only activate customer access when order_status === "ORDER_PAID":
- Invoice matching (order_invoice_number): Match the reference against your pending
CheckoutID. - Currency and amount exactness: Verify that
order_currency === "VND"and thatorder_amountexactly equals the checkout total. Never accept partial amounts or mismatches.
Idempotency and webhook replay protection
Webhooks are subject to automatic network retries and transient timeouts. Without idempotent handling, duplicate deliveries will grant duplicate benefits or advance billing cycles multiple times:
- Store unique transaction identifiers: Record each unique
transaction.idandorder_idin your database within a transaction. - When an identical transaction key is replayed, acknowledge with HTTP
200 OKimmediately without repeating state mutations or side effects.
The TRANSACTION_VOID policy
During banking reconciliation or reversed transactions, SePay may send voided or anomalous statuses. VietBilling enforces an explicit policy:
- Record audit logs and increment alert counters upon encountering
TRANSACTION_VOID. - Never immediately wipe customer entitlements without human verification. Instead, flag the payment for manual reconciliation to protect active customers from false-positive banking drops.