Docs

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.

TopicYouCarries
events/<type>subscribethe account's events, one per message
<path>/eventssubscribethe stream of any server-sent events route, path without /v1/
rpc/<service>/<Method>publish, with a response topica call to that method, as you
reply/<client id>/…subscribethe 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 QoS 1.
  • 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 codeWhen
0x87 Not authorizedthe 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 invalida subscription outside the topics above
0x90 Topic Name invalida publish outside rpc/, or a response topic outside yours
0x93 Receive Maximum exceededmore than 16 QoS 1 messages in flight
0x95 Packet too largea packet over 256 KiB
0x97 Quota exceededthe 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 timeDISCONNECT after 24 hours; connect again
0x9A Retain not supporteda retained publish
0x9B QoS not supportedQoS 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));