@SerialName: snake_case β†’ camelCase

Two naming worlds collide

The backend is Python, and Python names things in snake_case: photo_url, price_per_30min_cents. Kotlin names things in camelCase: photoUrl, pricePer30MinCents. Neither side should bend β€” each should look idiomatic in its own language.

But by default, kotlinx.serialization matches property names to JSON keys character for character. So val photoUrl: String? goes looking for a JSON key literally called photoUrl β€” which isn't there. Because it's nullable, decoding doesn't even fail: photoUrl just comes back null, silently, and every walker photo in the app is blank. val pricePer30MinCents: Int is worse-but-honest: it's not nullable and has no default, so decoding throws.

The fix: @SerialName

You annotate the property itself β€” no separate enum needed, unlike Swift's CodingKeys. @SerialName("photo_url") val photoUrl: String? = null tells the plugin: read the JSON key photo_url, store it in the Kotlin property photoUrl. Properties whose name already matches the JSON key (id, name, rating) need no annotation at all.