VietBilling
All guides
VietBilling Engineering Guides

Safe SePay IPN webhooks: authentication, idempotency, and void

Authenticate X-Secret-Key, verify ORDER_PAID status, prevent duplicate transactions with idempotent keys, and handle TRANSACTION_VOID edge cases safely.

VietBilling EngineeringVerified 2026-09-079 min read

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":

  1. Invoice matching (order_invoice_number): Match the reference against your pending Checkout ID.
  2. Currency and amount exactness: Verify that order_currency === "VND" and that order_amount exactly 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:

The TRANSACTION_VOID policy

During banking reconciliation or reversed transactions, SePay may send voided or anomalous statuses. VietBilling enforces an explicit policy:

Related content