Edge clients
Devices or small services need a broker-mediated path.
Use MQTT when a broker is a better fit than a direct WSS or HTTPS connection.
MQTT is still a secure public protocol. Clients connect to the broker with TLS, authenticate with per-client credentials, and publish only to the topics allowed for that client.
Edge clients
Devices or small services need a broker-mediated path.
Network boundaries
The client can reach a broker more reliably than a direct hub route.
Fan-in traffic
Many clients need isolated topic access through one public broker endpoint.
Not the default
Use WSS first unless MQTT solves a real deployment problem.
mqtts://.topic_prefix the identity returns.When MQTT is enabled, the client identity carries an mqtt block:
{ "mqtt": { "endpoint": "mqtts://mqtt.thalovant.com:8883", "username": "client-access-key", "password": "client-broker-password", "topic_prefix": "<namespace>/<hub-id>/<client-id>", "tls": true }}| Field | Meaning |
|---|---|
endpoint |
Broker URL. Public clients should use mqtts://. |
username |
Broker username for this client. It is the client access key. |
password |
Broker password for this client. |
topic_prefix |
Full topic base for this client. Append a channel suffix instead of hardcoding a path. |
tls |
Whether the client should connect over TLS. |
The identity’s topic_prefix is the full base for every topic this client uses. It looks like <namespace>/<hub-id>/<client-id>, where <client-id> is the client access key. Treat it as opaque: read topic_prefix from the identity and append the channel suffix instead of assembling the path yourself.
| Channel | Topic | Purpose |
|---|---|---|
| Inbound | <topic_prefix>/in |
The client publishes requests here. |
| Outbound | <topic_prefix>/out |
The client subscribes here for replies. |
| Status | <topic_prefix>/status |
Retained presence and status for this client. |
A client’s MQTT credentials come from its identity. To read them for a custom client:
mqtts://mqtt.thalovant.com:8883), username (the access key), broker password, and topic prefix. Keep the complete identity as well: its hub password is required for Noise authentication. You can also download _identity.json.If two-step sign-in blocks the panel, set it up first on Profile and Security.
You can connect any MQTT client to the broker with the credentials above, without Thalovant Voice or a managed runtime. Reaching the broker is the easy part.
The <topic_prefix>/in and <topic_prefix>/out topics carry the HiveMind admission and handshake envelopes, followed by raw binary Noise ciphertext. Subscribe to the outbound topic before sending the admission HELLO. Application ciphertext is not base64 or JSON wrapped; keep every chunk of one logical message in order and never retain handshake or application frames. The v3 Noise handshake authenticates the hub and derives session keys from the identity’s hub password. The retired crypto_key field is not required.
A custom client must complete broker admission and the Noise handshake before sending application requests. Use the MQTT transport in a compatible Python, Node.js, Go, or Rust SDK, or drive the protocol with the embedded C library and your own transport. A broker connection alone does not establish an authenticated hub session.
Preserve client static keys and verified server pins across reconnects. After broker loss, complete a fresh Noise handshake before sending again. Use different identities for simultaneously connected client processes.
from thalovant import ThalovantClient, ThalovantControlPlane
api = ThalovantControlPlane()
result = api.create_client_identity( "hub-id", name="python-mqtt-client", preferred_protocols=("mqtt", "wss"),)
identity = result.identityif identity.mqtt is None: raise RuntimeError("MQTT is not available for this identity.")
with ThalovantClient(identity, protocol="mqtt") as client: print(client.ask("Reply over MQTT.").text)import { ThalovantClient, ThalovantControlPlane } from "@thalovant/sdk";
const api = new ThalovantControlPlane();
const result = await api.createClientIdentity("hub-id", { name: "node-mqtt-client", preferredProtocols: ["mqtt", "wss"],});
if (!result.identity.mqtt) { throw new Error("MQTT is not available for this identity.");}
const client = new ThalovantClient(result.identity, { protocol: "mqtt" });try { const reply = await client.ask("Reply over MQTT."); console.log(reply.text);} finally { await client.close();}result, err := control.CreateClientIdentityForHubID(ctx, "hub-id", thalovant.BootstrapIdentityOptions{ Name: "go-mqtt-client", PreferredProtocols: []thalovant.HubProtocol{ thalovant.ProtocolMQTT, thalovant.ProtocolWSS, },})if err != nil { log.Fatal(err)}if result.Identity.MQTT == nil { log.Fatal("MQTT is not available for this identity.")}
client, err := thalovant.NewClientWithOptions(result.Identity, thalovant.ClientOptions{ Protocol: thalovant.ProtocolMQTT,})if err != nil { log.Fatal(err)}defer client.Close(ctx)let result = control .create_client_identity_for_hub_id( "hub-id", BootstrapIdentityOptions { name: "rust-mqtt-client".into(), preferred_protocols: vec![HubProtocol::Mqtt, HubProtocol::Wss], ..Default::default() }, ) .await?;
if result.identity.mqtt.is_none() { panic!("MQTT is not available for this identity.");}
let client = Client::with_protocol(result.identity.clone(), HubProtocol::Mqtt)?;| Symptom | Check |
|---|---|
| The SDK says MQTT is unsupported | Use Python, server-side Node.js, Go, or Rust. Kotlin, Swift, .NET, and the Node browser build do not own an MQTT transport. Also confirm the hub and identity enable MQTT. |
The identity has no mqtt block |
Enable MQTT on the hub, then open Connection details or download a fresh identity to pick up broker credentials. |
| Broker auth fails | Confirm the username is the access key and the client uses the latest broker password. Rotate the identity if needed. |
| TLS fails | Use the mqtts:// endpoint and confirm the broker certificate is valid. |
| A publish succeeds but nothing replies | Confirm the outbound subscription and Noise handshake completed, then send raw ciphertext frames. Broker acknowledgement alone does not confirm hub authentication or an application reply. |
| A reconnect fails authentication | Preserve the original client key and server pins, check the hub password, and complete a new handshake before sending. |
| Messages are ignored | Publish to <topic_prefix>/in and subscribe to <topic_prefix>/out. Do not invent topic paths. |
Last reviewed: September 9, 2026. Review this page when MQTT admission, Noise negotiation, TLS requirements, supported SDKs, or topic bindings change.