Transports
MQTT
MQTT 5 over a secure WebSocket, for events, every stream as a topic, and any call by publishing to it.
Rolling out
MQTT is rolling out from 2026-10-02. The changelog says when it reaches every account.
Shape
wss://api.inorbit.hr/v1/mqtt speaks MQTT 5.0
over a WebSocket with the subprotocol mqtt. It takes the same token as the
WebSocket: on the upgrade request as
Authorization: Bearer, and an upgrade without a valid one is refused before MQTT
starts. What you may call is what the WebSocket lets you call; MQTT changes how you
call, never what you may call.
A token or key limited to scopes connects like a full one, and
each subscription and call is checked against its scopes: a topic is yours when the
operation behind it names one of your scopes. With events:read you may subscribe to
events/… and call rpc/events/ListEventTypes; any other topic is refused with 0x87
Not authorized in the SUBACK or PUBACK. A full API token may use every topic.
Messages are JSON, the same objects REST answers and server-sent events carry.
| Topic | You | Carries |
|---|---|---|
events/<type> | subscribe | the account's events, one per message |
<path>/events | subscribe | the stream of any server-sent events route, path without /v1/ |
rpc/<service>/<Method> | publish, with a response topic | a call to that method, as you |
reply/<client id>/… | subscribe | the answers to your calls |
Events
events/token.revoked receives that one type; the type is a single topic level, so
events/+ or events/# receives every type the token may see. The event is the thin
shape on Webhooks: ids, never content.
Streams
Every route that answers with server-sent events is a topic
too: its path without the leading /v1/. What GET /v1/<resource>/events streams
arrives on <resource>/events, one message per event.
A failure arrives as one message holding the error envelope, and the stream is over.
Calls
Publishing to rpc/<service>/<Method> calls iohr.<service>.v1.<Service>/<Method>, the
method behind an operation in the Reference; rpc/accounts/GetMe
is GET /v1/accounts/me. The payload is the whole request message as JSON, {} for an
empty one. Two MQTT 5 properties are required:
- Response Topic: where the answer goes. It must be under
reply/<your client id>/. - Correlation Data: any bytes of yours; the answer carries them back, so you can match it to the call.
The answer, or the error envelope {"code","error","details"} when the call fails, is
published to your response topic. Subscribe to reply/<your client id>/# before you
call. The methods you may call are the ones REST lets your token call.
Rules
- QoS 0 and 1. QoS 2 is refused with a reason code; CONNACK announces
Maximum QoS1. - A clean session every time: nothing is stored after you disconnect, and messages sent while you were away are not kept. For delivery while you are offline, use a webhook.
- No retained messages and no wills.
- The server announces its limits in CONNACK and refuses beyond them with a reason
code, never by dropping silently: packets up to 256 KiB, 16 QoS 1 messages in flight
(
Receive Maximum), 32 subscriptions per connection, keep-alive up to 300 seconds. - Set your own client id, or send none and use the one CONNACK assigns. Your reply topics are under it.
| Reason code | When |
|---|---|
0x87 Not authorized | the token's scopes do not admit that topic or method, or the stream is not yours (an events subscription by a token with no account); as DISCONNECT, the key or token behind the connection was revoked |
0x8F Topic Filter invalid | a subscription outside the topics above |
0x90 Topic Name invalid | a publish outside rpc/, or a response topic outside yours |
0x93 Receive Maximum exceeded | more than 16 QoS 1 messages in flight |
0x95 Packet too large | a packet over 256 KiB |
0x97 Quota exceeded | the 33rd subscription; in CONNACK, a key, token or account already holding its most open streams (32 per key, 128 per account, event streams and sockets included) |
0xA0 Maximum connect time | DISCONNECT after 24 hours; connect again |
0x9A Retain not supported | a retained publish |
0x9B QoS not supported | QoS 2 |
Examples
Both subscribe to every event, call GetMe and print what arrives. The token comes from
Authentication.
// npm install mqtt
import mqtt from "mqtt";
const clientId = `inorbit-${crypto.randomUUID()}`;
const client = mqtt.connect("wss://api.inorbit.hr/v1/mqtt", {
protocolVersion: 5,
clientId,
clean: true,
keepalive: 60,
wsOptions: { headers: { Authorization: `Bearer ${process.env.INORBIT_TOKEN}` } },
});
client.on("connect", async () => {
await client.subscribeAsync(["events/#", `reply/${clientId}/#`], { qos: 1 });
client.publish("rpc/accounts/GetMe", "{}", {
qos: 1,
properties: { responseTopic: `reply/${clientId}/me`, correlationData: Buffer.from("1") },
});
});
client.on("message", (topic, payload, packet) => {
const id = packet.properties?.correlationData?.toString();
console.log(topic, id ?? "", JSON.parse(payload.toString()));
});
client.on("error", (err) => console.error(err.message));