Resources as a live REST API
Every resource the firmware declares is called with RUN, and the platform exposes it as a REST endpoint: POST to send it a value, GET to read it. No topic conventions, no glue code on either side.
Developers · IOTMP Protocol
IOTMP has carried Thinger.io's device traffic since 2015. Telemetry, remote calls, streams, terminals and tunnels share one TLS connection, and the protocol is now an open IETF Internet-Draft that anyone can implement.
How it works
Telemetry, cloud calls, firmware and remote access usually ride separate protocols, each with its own port, credential and stack. IOTMP opens one outbound connection and tells the conversations apart with a Stream ID on every frame.
Telemetry#12
START_STREAM · STREAM_DATA
Samples at the rate the server asks for. In compact mode the keys travel once.
Remote call#13
RUN · OK
Either side calls a resource of the other and gets OK or ERROR back.
Terminal#15
STREAM_DATA both ways
A shell with a PTY, keystrokes down and output up on one stream.
Files#17
RUN · STREAM_DATA
Small files inline in the reply, large ones in chunks with flow control.
TCP tunnel#19
STREAM_DATA both ways
TCP relayed to a service on the device LAN: SSH, a PLC, a web panel.
On the wire
Terminals, file transfers and tunnels add no message type: they are built on the same RUN and STREAM_DATA primitives that carry a temperature reading.
| Code | Message | Dir | What it does |
|---|---|---|---|
| Session | |||
| 0x03 | CONNECT | Device to server | Opens the session with credentials, a token or a certificate |
| 0x04 | DISCONNECT | Either direction | Ends the session cleanly |
| 0x05 | KEEP_ALIVE | Either direction | Keeps the connection up; the only frame without a Stream ID |
| Replies | |||
| 0x01 | OK | Answer to a request | The request succeeded, with a result when there is one |
| 0x02 | ERROR | Answer to a request | The request failed; after CONNECT, the server closes |
| Calls | |||
| 0x06 | RUN | Either direction | Call a resource on the other end with a PSON payload |
| 0x07 | DESCRIBE | Either direction | Ask the other end for its API: resources, inputs, outputs, optional JSON Schema |
| Streams | |||
| 0x08 | START_STREAM | Either direction | Open a stream on a resource: telemetry, a terminal, a tunnel |
| 0x09 | STOP_STREAM | Either direction | Close it from either end |
| 0x0A | STREAM_DATA | Either direction | A sample, a chunk, a line of output, in the stream |
RUN the resource led with {"on": true}: a type, a body size and three tagged fields. 15 bytes on the wire.
2 B KEEP_ALIVE4 B OK without payload15 B this call
Compact streaming
When the server asks for compact mode, the first sample sets the keys and every sample after it carries the values alone, in the same order. Payloads travel as PSON, a binary drop-in for JSON, 40 to 75% smaller on typical IoT data.
{"temperature": 23.5, "humidity": 60, "pressure": 1013}[23.6, 61, 1013]PSON payload sizes from the compact mode example of the IOTMP draft (11.4.6) · one cell, one byte
60%
Smaller per sample
Temperature and humidity: 35 bytes per sample in normal mode, 14 in compact mode.
67%
With more keys
An eight sensor environmental station: 83 bytes per sample down to 27.
78%
Less than MQTT 3.1.1
For 100 samples of two sensors, and 67% less than MQTT v5 with topic aliases.
Figures from the draft (Tables 25 and 26). ESP32 benchmarks against MQTT, CoAP, LwM2M and HTTP are on iotmp.io.

SPECIFIED DOWN TO THE BYTE
Beyond telemetry
The Thinger.io clients build four jobs that usually need a tool of their own on the same RUN and STREAM_DATA primitives, over the connection the device already keeps open.
Every resource the firmware declares is called with RUN, and the platform exposes it as a REST endpoint: POST to send it a value, GET to read it. No topic conventions, no glue code on either side.
Firmware reaches ESP32 and the other supported boards over the connection they already keep open, in chunks with flow control, and the same connection carries a console session to the microcontroller.
A config file comes back inline in one RUN reply. Logs and large files stream in chunks with flow control and bandwidth limits, with no FTP server or second protocol on the device.
A transparent TCP relay to the device itself or to anything on its LAN: SSH, a router panel, a PLC, a database port. No port forwarding, no VPN, nothing exposed to the internet.
ThinRemote turns these channels into a managed service for Linux fleets
Security model
Every session opens the same way: the device dials out, TLS comes up, the device proves who it is, and only then can either side send.
OUTBOUND ONLY
The connection always starts on the device, never from the server. Nothing listens, nothing is forwarded: it works behind NAT and firewalls the way a browser does.
TLS 1.2+ · PORT 25206 · WSS 443
TLS 1.2 or later is required in production, 1.3 recommended: on port 25206, or over a WebSocket on 443 where only web traffic gets out. Plain TCP is for trusted networks and development.
CREDENTIALS · TOKEN · CERTIFICATE
The first frame proves who the device is: its credentials, a bearer token or a client certificate. On OK either side can send at any time; on ERROR the server closes.
No open ports. There is no inbound surface on the device to scan, harden or patch.
Behind NAT and firewalls. Factory floors, cellular links and home routers need no change at all.
One credential. One identity covers telemetry, calls, terminals, files and tunnels.
Implement it
The same sketch that puts an ESP32 online in the quick start is an IOTMP client: the frames of the trace at the top of the page are what these lines send.
#include <ThingerESP32.h>ThingerESP32 thing(USERNAME, DEVICE_ID, CREDENTIAL);CONNECTvoid setup() { pinMode(16, OUTPUT); thing.add_wifi(SSID, PASSWORD); thing["relay"] << digitalPin(16);answers RUN thing["uptime"] >> outputValue(millis());STREAM_DATA}void loop() { thing.handle();KEEP_ALIVE · reconnect}Connected · TLS · 1 connection
< 400
lines of C
A complete IOTMP and PSON client, as the draft measures it.
4
open-source clients
Arduino, Linux, ESP-IDF and Zephyr, MIT licensed on GitHub.
2015
in production
Under every Thinger.io device since, now written down as a draft.
A good fit
Not a replacement for every protocol
Thinger.io speaks both sides of that line: MQTT, HTTP, LoRaWAN and Sigfox devices land in the same console as IOTMP ones. See Device Connectivity
Next step
Read the open draft and build your own implementation, or let the open-source Thinger.io clients speak it for you on a free account.