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?