Parsing nested `metrics` in Genesys Cloud analytics aggregate webhook events

Setting up a consumer for the v2.analytics.conversation.aggregate event type in our Kotlin backend. The goal is to extract specific duration metrics like talk and hold from the payload. The structure is deeper than I expected, and the Kotlin data class mapping is failing silently on the nested objects.

The webhook payload looks like this:

{
 "event": {
 "id": "abc-123",
 "type": "v2.analytics.conversation.aggregate",
 "data": {
 "conversationId": "conv-987",
 "metrics": {
 "call": {
 "talk": {
 "sum": 120.5,
 "count": 1
 },
 "hold": {
 "sum": 10.0,
 "count": 1
 }
 }
 }
 }
 }
}

I’m trying to map this to a sealed class hierarchy because the metrics object varies by media type (call, chat, email). Here’s the relevant Kotlin code:

data class AnalyticsEvent(
 val event: EventPayload
)

data class EventPayload(
 val data: AnalyticsData
)

data class AnalyticsData(
 val conversationId: String,
 val metrics: MediaMetrics
)

sealed class MediaMetrics {
 data class CallMetrics(
 val call: CallDetails
 ) : MediaMetrics()
 
 data class ChatMetrics(
 val chat: ChatDetails
 ) : MediaMetrics()
}

data class CallDetails(
 val talk: MetricValue,
 val hold: MetricValue
)

data class MetricValue(
 val sum: Double,
 val count: Int
)

Using Jackson with @JsonTypeInfo and @JsonSubTypes on MediaMetrics doesn’t seem to work because there isn’t a type discriminator field in the JSON. The metrics object just contains keys like call or chat directly. Jackson throws a MismatchedInputException saying it cannot deserialize MediaMetrics out of START_OBJECT token.

I’ve tried using a custom JsonDeserializer but handling the dynamic keys feels messy. Is there a cleaner way to parse this nested structure in Kotlin without writing a massive when block for every possible media type? Or is the standard approach just to use a generic Map<String, Any> for the metrics and cast manually?