Now, Matrix allows arbitrary transports to actually put that over the wire - but mandates only the most comically simple (and inefficient) as a mandatory baseline. This is a plain HTTP PUT request of the above data encoded as JSON and a few URI parts. The reason for this is that HTTP is insanely ubiquitous and well understood; any random device or language these days can trivially send and receive messages.
However, there is nothing stopping you from using a more efficient transport for the data between your client and your server - we've been experimenting with everything from boring old JSON over WebSockets to COAP or MQTT and even capnproto. We haven't specced any of these yet, but we'll probably add them as optional profiles to the spec in future. Meanwhile plain old REST actually works pretty well in practice :)
The fun stuff in Matrix is all about the eventually consistent decentralised conversation history between servers rather than obsessing about the most efficient way to shove some key value pairs between a client and a server.