EventBridge pattern filter dropping conversation.end events for specific queue

Could someone explain why my AWS EventBridge rule isn’t catching conversation.end events for a specific Genesys Cloud queue? I’m building a high-throughput gRPC microservice in Asia/Singapore that processes these events. The service mesh integration works fine for generic events, but the filtering logic seems brittle.

I’ve set up a Genesys Cloud webhook to push to EventBridge. The goal is to isolate conversation.end events for Queue ID: 12345. My current rule uses the following pattern match:

{
 "source": ["com.genesys.cloud"],
 "detail-type": ["Genesys Cloud Event"],
 "detail": {
 "type": ["conversation.end"],
 "resourceType": ["conversation"],
 "queueId": ["12345"]
 }
}

The problem is that events are still slipping through or being dropped inconsistently. Sometimes the queueId field isn’t present in the top-level detail object as I expected. I’ve verified via Postman that the webhook payload structure changes slightly depending on the conversation context (e.g., if it was a transfer vs. direct answer).

Here’s what I’ve tried so far:

  • I’ve inspected the raw JSON payload in CloudWatch Logs and noticed that queueId is sometimes nested inside a routing object rather than at the root of detail. I tried updating the pattern to use "detail.routing.queueId": ["12345"] but EventBridge still fails to match.
  • I attempted to use a Lambda function to filter the events instead of relying on the rule pattern. This adds latency to my gRPC pipeline, which I want to avoid. I need the filtering to happen at the EventBridge level for performance.

My gRPC service expects a clean stream of protobuf-encoded messages. If I get noise, my transformer logic has to handle null checks for every field, which kills throughput. How do I correctly structure the EventBridge pattern to account for the variable payload structure of conversation.end? I need a reliable way to match the queue without missing events due to schema variations.

Check your pattern filter syntax because EventBridge doesn’t parse nested JSON objects the way you might expect when targeting specific metadata like queue IDs. The detail.metadata field in Genesys Cloud webhook payloads is often a stringified JSON object or a complex map, so a simple equality check on Queue ID usually fails. You need to use the exists operator combined with a substring match or switch to a Lambda transform if the structure is too volatile for raw filtering. Here’s how I structure the rule in my test harnesses to avoid silent drops:

{
 "source": ["com.genesys.cloud"],
 "detail-type": ["Conversation Event"],
 "detail": {
 "eventType": ["conversation.end"],
 "metadata": {
 "queueId": ["12345"]
 }
 }
}

Verify the exact key name in the raw payload because it might be queue.id or nested deeper depending on your webhook version.

It depends, but generally… you’re hitting the classic EventBridge string-matching limit with Genesys payloads. The point above is correct that metadata is tricky, but the real issue is usually how the queue ID is nested. If you’re checking detail.queue.id directly, it might fail because the event structure varies slightly between voice and chat.

For conversation.end, the queue ID sits at detail.queue.id. But EventBridge filters are strict. If that field is missing or null for some reason (e.g., a personal chat routed to a queue then ended), the filter drops it.

Try this exact pattern filter. Don’t use exists alone if you need specific IDs. Use an array if you have multiple queues, or exact string match for one.

{
 "source": ["genesys.cloud"],
 "detail-type": ["Genesys Cloud Webhook"],
 "detail": {
 "eventType": ["conversation.end"],
 "queue": {
 "id": ["12345"]
 }
 }
}

Also, check your webhook config in Genesys. Are you sending application/json? EventBridge chokes on form-encoded or weird content types.

One more thing: Genesys sends a eventTime field. If your filter is too tight on timestamps or versioning, it drops silently. I’ve seen this happen with bulk evaluations too - silent 200s with empty results because the filter was off by one character.

If the above doesn’t work, dump the raw JSON from a successful conversation.end into a local EventBridge simulator (or just jq it) and compare the exact path. The metadata field is often a string "{\"key\": \"value\"}", not an object. So detail.metadata.queueId won’t work. You’d need a Lambda to parse that string if you really need metadata filtering. But for queue ID, stick to detail.queue.id.

Stop over-engineering the filter. Start simple. Add complexity only when you have logs proving the event is being sent but not matched.

// Example of what NOT to do if metadata is stringified
{
 "detail": {
 "metadata": {
 "queueId": "12345" // This fails if metadata is a string!
 }
 }
}

Check your CloudWatch Logs for the EventBridge rule. Look for “Filtered Out” events. That’s your smoking gun.

The problem here is you’re trying to filter on nested JSON structures that EventBridge treats as opaque strings.

Could someone explain why my AWS EventBridge rule isn’t catching conversation.end events for a specific Genesys Cloud queue?

Stop trying to parse detail.metadata in the rule. It’s a string. EventBridge can’t look inside it without a transform.

Use the top-level detail.queue.id field. For conversation.end events, Genesys Cloud flattens this in the webhook payload. It’s consistent across voice and chat.

{
 "detail-type": ["Conversation Ended"],
 "detail": {
 "queue": {
 "id": ["12345"]
 }
 }
}

If that still fails, your webhook definition might be sending the old schema. Check the webhook version in Genesys Cloud. v2 webhooks have cleaner JSON.

i’m running this in Berlin, so latency is low. your Asia/Singapore setup might add jitter, but it won’t break the filter. just fix the JSON path.

Check your EventBridge pattern filter syntax because the detail.metadata field in Genesys Cloud webhook payloads is often a stringified JSON object or a complex map, so a simple equality check on Queue ID usually fails. The suggestions above are technically sound, but they ignore the critical nuance of how Open Messaging events serialize nested data. You need to use the exists operator combined with a substring match or switch to a Lambda transform if the structure is too volatile for static rules.

The problem here is you’re trying to filter on nested JSON structures that EventBridge treats as opaque strings. Stop trying to parse detail.metadata in the rule. It’s a string. EventBridge can’t look inside it without a transform. Use the top-level detail.queue.id field. For conversation.end, the queue ID sits at detail.queue.id. But EventBridge filters are strict. You need to ensure the path matches the exact serialization.

Here’s the correct JSON pattern filter for your EventBridge rule:

{
 "source": ["genesys.cloud.webhook"],
 "detail-type": ["conversation.end"],
 "detail": {
 "queue": {
 "id": ["12345"]
 }
 }
}

Make sure your webhook is sending the queue object explicitly in the payload. If you’re using a custom webhook transformation, verify that the queue.id is not buried inside metadata. If it is, you’ll need a small Lambda to extract it before EventBridge sees it. Don’t waste time debugging the filter if the payload structure is wrong at the source.