Genesys Cloud webhook payload validation failing in Node.js Lambda

Why is this setting causing my Lambda to reject valid Genesys Cloud events? I am building an ETL pipeline to capture real-time conversation analytics via webhooks. The Lambda function uses Node.js 18. It receives POST requests from the GC webhook endpoint. I validate the X-Genesyscloud-Signature header. The signature matches. The body parses correctly. Yet the handler returns a 400 Bad Request. The error log shows Invalid event structure. I expect the payload to contain a data array. It does. I check the eventType. It is conversation:updated. This should be valid. The documentation is vague about nested field requirements. I have tried stripping non-essential fields. I have tried passing the raw body. Nothing works. The ETL pipeline stalls. Data goes to dead-letter queue. I need to know the exact JSON schema expected by the consumer. Is there a hidden validation step? Please provide a minimal working example. My code snippet is below. It fails on the second request consistently. I am in Asia/Seoul time. I need a fix before morning shift. Why does this happen?

Why does this setting cause my Lambda to reject valid Genesys Cloud events?

The issue is likely how you are parsing the request body before validation. In Node.js 18 API Gateway proxy integrations, the payload is often a stringified JSON object wrapped in another layer, or the body field is null if content-type is missing. Ensure you are using JSON.parse correctly on the raw body.

const crypto = require('crypto');

exports.handler = async (event) => {
 // 1. Parse body safely
 let body;
 try {
 body = JSON.parse(event.body);
 } catch (e) {
 return { statusCode: 400, body: 'Invalid JSON' };
 }

 // 2. Validate structure
 if (!body.events || !Array.isArray(body.events)) {
 return { statusCode: 400, body: 'Missing events array' };
 }

 // 3. Verify signature
 const signature = event.headers['X-Genesyscloud-Signature'];
 const expected = crypto.createHmac('sha256', process.env.GC_SECRET)
 .update(event.body)
 .digest('hex');

 if (signature !== expected) {
 return { statusCode: 401, body: 'Invalid signature' };
 }

 return { statusCode: 200, body: 'OK' };
};

Check if event.body is undefined. GC webhooks sometimes send raw JSON without wrapping in API Gateway format if using custom domains.