Parsing nested event objects in GC webhook payloads for Node.js Lambda

How do you actually parse the nested event object in a Genesys Cloud webhook when it hits a Node.js Lambda handler? We’re getting a 200 back but JSON.parse fails. Payload shifts between routing.queue.memberAdded and routing.queue.memberRemoved events anyway. The Lambda drops it into deadletter since the shape doesn’t match our initial schema.

{"event": {"type": "routing.queue.memberAdded", "data": {"memberId": "xyz"}}}

The JSON.parse failure happens because Lambda often receives the body as a string that’s already been processed or truncated, or the event type mismatch causes your schema validator to reject the payload before parsing completes. You’re treating all routing events as having the same shape, but memberAdded and memberRemoved carry different nested structures. The payload isn’t shifting randomly; it’s just different.

Don’t rely on a single static schema. Check the event.type first, then route to the correct parser. Here’s a minimal handler that handles both without crashing:

exports.handler = async (event) => {
 try {
 const body = typeof event.body === 'string' ? JSON.parse(event.body) : event.body;
 const eventType = body.event?.type;

 if (eventType === 'routing.queue.memberAdded') {
 // Handle added logic
 console.log('Added:', body.event.data.memberId);
 } else if (eventType === 'routing.queue.memberRemoved') {
 // Handle removed logic
 console.log('Removed:', body.event.data.memberId);
 } else {
 console.warn('Unknown event type:', eventType);
 }

 return { statusCode: 200, body: 'OK' };
 } catch (error) {
 console.error('Parse failed:', error.message);
 return { statusCode: 500, body: 'Error' };
 }
};

Make sure your Lambda role has lambda:InvokeFunction permissions if you’re chaining this. The deadletter queue is filling up because you’re returning 200 even when the internal logic fails. Catch the error, log it, and return 200 to stop GC from retrying. If you need to process these in bulk, look at the v2/analytics/conversations/details/query endpoint instead of webhooks. It’s faster and gives you a consistent schema.