Node.js Example

Node.js requires regex replacements to add spaces after colons and commas to match Python's formatting.

const crypto = require('crypto');

// Step 1: Extract signature from header
const receivedSignature = req.headers['ap-signature'];

// Step 2: Get webhook body
const body = req.body;

// Step 3: Build payload for signing
const payload = {
    ...body,  // All fields from webhook body
    url: 'https://your-registered-webhook-url.com'
};

// Step 4: Serialize with Python-compatible formatting
// NOTE: This regex approach has known limitations with complex nested structures.
// Test thoroughly with your specific webhook payloads.
const payloadStr = JSON.stringify(payload)
    .replace(/"((?:[^"\\]|\\.)*)"\s*:/g, '"$1": ')  // space after colons
    .replace(/,(?=\s*["{[0-9tfn])/g, ', ');          // space after commas

// Step 5: Compute expected signature
const hmac = crypto.createHmac('sha256', signingKey);
hmac.update(payloadStr);
const expectedSignature = hmac.digest('hex');

// Step 6: Validate (use constant-time comparison)
const isValid = crypto.timingSafeEqual(
    Buffer.from(receivedSignature),
    Buffer.from(expectedSignature)
);

if (isValid) {
    // Webhook is authentic - safe to process
    processWebhook(body);
} else {
    // Invalid signature - reject
    res.status(401).send('Unauthorized');
}
🚧

Node.js Limitation:

The regex replacement approach has known limitations with complex nested structures (arrays of objects, mixed-type arrays). We recommend testing your implementation against real sandbox webhooks before deploying to production.