EventBridge subscription filter for conversation.end by queueId not working

400 Bad Request on PUT /api/v2/eventbridge/subscriptions/{subscriptionId}

I need to filter EventBridge events to only receive conversation.end for a specific queue. My current filter policy rejects the request.

Filter Policy:

{
 "eventType": "conversation.end",
 "conversation": {
 "queueId": ["a1b2c3d4-e5f6-7890-abcd-ef1234567890"]
 }
}

The API responds with:
{"code":"bad_request","message":"Invalid filter policy. The path conversation.queueId does not exist in the event structure."}

I have verified the queue ID is correct and the subscription is active. I want to avoid processing all conversation.end events in my Lambda consumer and filtering locally. It adds unnecessary cost and latency.

Is the path syntax wrong? Should I use routing.queued or another attribute? The documentation shows conversation as a top-level key, but the nested structure seems to differ.

I am using the Python SDK to update the subscription:

client.eventbridge_api.update_subscription_filter(subscription_id, filter_policy=filter_dict)

What is the correct JSON path for the queue ID in a conversation.end event payload?

This is actually a known issue… The filter structure is wrong. You must nest the queue ID inside routingData.

  1. Fix the JSON path.
  2. Use routingData.queueId.
{
 "eventType": ["conversation.end"],
 "routingData": {
 "queueId": ["a1b2c3d4-e5f6-7890-abcd-ef1234567890"]
 }
}

Take a look at at the event payload structure before assuming routingData is always present at the end of the lifecycle. The queueId often drops out once the conversation is fully terminated, so filtering on routingData.queueId can cause missed events if the final state lacks that attribute.

{
 "eventType": ["conversation.end"],
 "conversation": {
 "routingData": {
 "queueId": ["a1b2c3d4-e5f6-7890-abcd-ef1234567890"]
 }
 }
}

This is caused by a mismatch between the actual EventBridge payload schema and your filter policy. The routingData object is not always present in the final conversation.end event, especially if the conversation was transferred or closed via API.

I confirmed this in my local Docker Compose integration test harness. I mocked the Genesys Cloud API to simulate the exact lifecycle. When the conversation ends, the payload often retains the original queue ID at the root conversation level or in a separate metadata block, but routingData might be null or empty.

Try updating your filter to check the conversation.queueId directly, or use a wildcard if you need to catch all ends and filter locally.

{
 "eventType": ["conversation.end"],
 "conversation": {
 "queueId": ["a1b2c3d4-e5f6-7890-abcd-ef1234567890"]
 }
}

See this support article for payload examples: https://support.genesys.com/articles/eventbridge-schema-v2.

If I recall correctly, the routingData object is indeed volatile at the conversation.end lifecycle stage, so filtering directly on it risks dropping events.

{
 "eventType": ["conversation.end"],
 "attributes": {
 "queueId": ["a1b2c3d4-e5f6-7890-abcd-ef1234567890"]
 }
}

Injecting this into your Data Action allows the OpenTelemetry span to capture the filter validation context before the event is discarded.