Hey everyone,
I’m trying to set up a simple Node.js Lambda function to process Genesys Cloud interaction webhooks. The goal is to grab the interaction ID and push it to our WFM tracking sheet. It’s not working as expected.
Here’s the setup:
- Runtime: Node.js 18.x
- Trigger: API Gateway (POST method, binary media types disabled)
- Payload source: Genesys Cloud /api/v2/interactions/events/webhooks
The Lambda receives the event, but event.body comes in as a stringified JSON, not an object. When I try to access event.body.interactionId, it returns undefined. I’ve checked the Genesys Cloud webhook logs and the payload looks correct on the Genesys side.
Here’s my code snippet:
exports.handler = async (event) => {
console.log('Received event:', JSON.stringify(event, null, 2));
let body;
try {
body = JSON.parse(event.body);
} catch (e) {
return {
statusCode: 500,
body: 'Failed to parse body'
};
}
const interactionId = body.interactionId;
console.log('Interaction ID:', interactionId);
// ... rest of the logic
};
The logs show the parsed body correctly, but interactionId is still undefined. I’ve tried accessing body.data.interactionId too, no luck. Am I missing a header or a specific parsing step for these webhooks?
Also, I noticed the timestamp in the payload is in ISO 8601 format. Is there a standard way to convert this to CST for our reports without using a library?
Sounds like you’re hitting the classic AWS API Gateway binary vs text mismatch. Genesys Cloud sends JSON, but if your gateway is configured to treat application/json as binary (or if you left binary media types enabled globally), Lambda receives a base64-encoded string instead of a parsed JSON object. That’s why event.body is garbage to JSON.parse.
Check your API Gateway settings. If Binary Media Types includes */* or application/json, you need to decode it manually in the Lambda handler. Here’s how to handle that edge case:
exports.handler = async (event) => {
let body;
// Check if the body is a base64-encoded string (common when binary is enabled)
if (event.isBase64Encoded) {
body = JSON.parse(Buffer.from(event.body, 'base64').toString());
} else {
// Standard text parsing
body = typeof event.body === 'string' ? JSON.parse(event.body) : event.body;
}
// Now you can safely access the interaction ID
const interactionId = body.id;
console.log("Received Interaction ID:", interactionId);
return {
statusCode: 200,
body: JSON.stringify({ success: true })
};
};
Also worth checking the retry policy on the webhook endpoint itself. If your Lambda takes longer than 30 seconds to respond, Genesys marks it as failed and starts retrying with exponential backoff. You’ll end up processing the same interaction multiple times. Make sure you’re returning a 200 or 202 quickly, and handle idempotency on your WFM side using that interaction ID.