Sign in
Docs
0%

Transports

WebSocket

One socket that carries any call by name, several at once, with the same JSON as REST.

Shape

wss://api.inorbit.hr/v1/ws is one connection for every route in the reference, addressed by the RPC's full name instead of a path. Frames are JSON text, one object each. The token goes on the upgrade request as Authorization: Bearer.

From the client:

FrameMeaning
{"type":"call","id":"1","method":"iohr.<service>.v1.<Service>/<Method>","body":{…}}start a call; body may be omitted for an empty request
{"type":"cancel","id":"1"}stop a call in flight

To the client:

FrameMeaning
{"type":"data","id":"1","body":{…}}one answer; a unary call sends exactly one, a stream sends many
{"type":"end","id":"1"}the call is over and the id is free again
{"type":"error","id":"1","code":…,"error":…,"details":[…]}the call failed; the error envelope with the id it belongs to
{"type":"error","code":…,"error":…,"details":[…]}the frame itself was refused; no call is named and the socket stays open
{"type":"call","id":"1","method":"iohr.accounts.v1.AccountsService/GetMe"}
{"type":"data","id":"1","body":{"…":"…"}}
{"type":"end","id":"1"}

The method name is the operation's x-iohr-rpc in the OpenAPI document: EventsService.StreamEvents in the reference is iohr.events.v1.EventsService/StreamEvents on the socket. The whole request message is the frame's body; path and query rules belong to REST and do not apply here.

The frames are published as a JSON Schema at https://api.inorbit.hr/frames.json, no token needed, with the limits below in x-iohr-limits. The SDKs are built against it.

Scopes

A token or key limited to scopes opens the socket like a full one, and each call is checked against its scopes the way REST checks each request: a method is yours when its operation in the reference names one of your scopes. With events:read you may call EventsService/ListEventTypes and EventsService/StreamEvents and nothing else. Any other call ends with {"type":"error","id":…,"code":"forbidden",…} and the socket stays open. A full API token may call every method.

Rules

  • id is yours, unique among the calls you have in flight, free again after end or error. Every call ends with exactly one of the two, cancellation included.
  • Calls are independent: a unary call answers while streams stay open. A refusal never closes the socket.
  • At most 64 calls in flight per connection; the 65th is rate_limited until one ends.
  • A frame from the client is at most 256 KiB.
  • A client that reads slowly stalls only its own calls; frames wait in one bounded queue per connection.
  • The server sends a WebSocket ping every 15 seconds; your WebSocket library answers it. A socket with no call in flight and no frame from you for 5 minutes is closed with code 1000, reason idle.
  • The socket counts as one of your open streams: a key, API token or person holds at most 32 (event streams, sockets and MQTT connections together), an account 128. Past that the upgrade is refused with 429 rate_limited.

How a socket ends

The token is checked once, at the upgrade, and the socket is not cut when that token expires. The server ends it in two cases, each with one error frame that names no call, then the close:

Frame codeWhyWhat to do
unauthenticatedthe key or API token behind the socket was revokedstop; a new key is a new decision
unavailablethe socket reached its longest life, 24 hoursreconnect and send again the calls that had not ended

After any close, a client reconnects with a fresh token and issues again only the calls that had not ended and are safe to repeat (reads and streams).