You can use something like this : 
decodeMsg jsValue =
D.field "id" D.string
|> D.andThen decodePayload
decodePayload id=
case id of
"IntPayload" ->
... the entire msg to be decoded here, and id is already deoded and available...
"StringPayload" ->
D.field "payload" (D.map ItHasStringPayload D.string)
_ ->
D.fail <| "Event with unknown id: " ++ id
Edit: I guess for your usecase:
decodeMsg jsValue =
D.field "id" D.int
|> D.andThen (\idAsInt ->
... your decoder... (id is available as Int here)
)
But I would not have any logic in my decoders,
I would have just decoded it as is and then check if the Id match in my update function.