Skip to main content
All webhook payloads sent by Pagsmile are signed using HMAC-SHA256. Validating the request signature ensures data authenticity, integrity, and protection against unauthorized requests.
Security Requirement: Always verify the signature against the exact raw HTTP request body before parsing the JSON body. Your API Secret is used locally to compute the signature and is never transmitted in the request.

Required Request Headers

Every incoming webhook request includes six headers essential for authenticity verification:
HeaderDescription
Content-TypeExact request content-type string used during signature generation.
X-Client-IDAPI Key identifying the signing credential.
X-TimestampRequest execution time in Unix milliseconds.
X-Nonce32-character lowercase hexadecimal random string.
X-Content-HashLowercase SHA-256 hex digest computed over the raw payload body.
X-SignatureLowercase HMAC-SHA256 hex signature to compare against.
📌 Note: X-Signature is not included in canonical headers; it is the target value used for final verification.

Signature Construction (StringToSign)

To calculate the expected signature, construct the StringToSign string by concatenating the seven components below with a single line feed (\n). Do not append a trailing line feed at the end. Plaintext

Canonicalization Rules

  1. HTTP Method: Convert to uppercase string (e.g., POST).
  2. Canonical Path:
    • Include path only (exclude scheme, host, query, and fragment).
    • Normalize empty paths to /.
    • Preserve trailing slashes.
    • Best Practice: Use a simple ASCII path (e.g., /webhooks/pagsmile) to prevent escaping mismatches across event families.
  3. Canonical Query: Lexically sort query parameters by name, format as name=value (using + for spaces), and join with &. If no query exists, use an empty line.
  4. Canonical Headers: Formatted in lexical order for exact header names: content-type, x-client-id, x-content-hash, x-nonce, x-timestamp. Trim whitespace and format as lowercase-name:trimmed-value.
  5. Content Hash: SHA-256 computed over exact raw network bytes. Do not parse and re-serialize JSON before hashing.

Verification Pipeline (10-Step Execution Flow)

Follow this strict step-by-step pipeline inside your application middleware: Image
🛡️ Timing-Attack Protection: Always compare your calculated signature with X-Signature using a constant-time comparison function (e.g., crypto.timingSafeEqual in Node.js or hmac.equal in Python) to prevent side-channel timing attacks.