Skip to content

MQTT Data Streaming

Subscribe to real-time device data over MQTT. This is the recommended way for external systems to receive device uplinks as they happen.

Overview

N-Hub exposes an MQTT bridge that streams device data to authenticated clients. Two authentication methods are supported:

  • X.509 client certificates (recommended) — strongest security, no credential rotation needed until expiry
  • Username/password — simpler setup, uses the API key's username and token as credentials

Both methods require TLS and scope data access to the API key's enterprise.

graph LR
    A[Your System] <-->|MQTT over TLS| B[MQTT Bridge] <-->|Internal| C[Device Uplinks]

Quick Start (Certificate Auth)

1. Create an API Key

Create a service account (API key) in the N-Hub portal under Settings > API Keys, or via the API:

curl -X POST -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"username": "svc-mqtt-prod", "is_service_account": true}' \
  https://api.dev-au-03.nnnco.io/api/v4/manage/users/

Note the id (UUID) — this is your api_key_id.

2. Generate an MQTT Certificate

curl -X POST -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Production MQTT Client",
    "api_key_id": "<api-key-uuid>",
    "validity_hours": 8760
  }' \
  https://api.dev-au-03.nnnco.io/api/v4/manage/mqtt-certificates/

The response contains three PEM fields — save all three immediately:

{
  "id": "...",
  "name": "Production MQTT Client",
  "certificate_pem": "-----BEGIN CERTIFICATE-----\n...",
  "private_key_pem": "<PEM-encoded EC private key>",
  "ca_certificate_pem": "-----BEGIN CERTIFICATE-----\n...",
  "fingerprint": "a1b2c3d4...",
  "expires_at": "2027-03-17T00:00:00Z"
}

Save each PEM to a file:

# Save the three PEM files (the private key is only returned once)
echo "<certificate_pem>" > client.crt
echo "<private_key_pem>" > client.key
echo "<ca_certificate_pem>" > ca.crt
chmod 600 client.key

3. Connect with MQTT

mosquitto (CLI)

mosquitto_sub \
  --cafile ca.crt \
  --cert client.crt \
  --key client.key \
  -h mqtt.dev-au-03.nnnco.io -p 8883 \
  -t "v4/groups/<enterprise_code>.master/+/uplinks" \
  -v

Python (paho-mqtt)

import ssl
import paho.mqtt.client as mqtt

def on_connect(client, userdata, flags, rc, properties=None):
    print(f"Connected (rc={rc})")
    client.subscribe("v4/groups/<enterprise_code>.master/+/uplinks")

def on_message(client, userdata, msg):
    print(f"{msg.topic}: {msg.payload.decode()}")

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
client.tls_set(
    ca_certs="ca.crt",
    certfile="client.crt",
    keyfile="client.key",
    tls_version=ssl.PROTOCOL_TLS_CLIENT,
)
client.on_connect = on_connect
client.on_message = on_message

client.connect("mqtt.dev-au-03.nnnco.io", 8883)
client.loop_forever()

Node.js (mqtt.js)

const mqtt = require('mqtt');
const fs = require('fs');

const client = mqtt.connect('mqtts://mqtt.dev-au-03.nnnco.io:8883', {
  ca: fs.readFileSync('ca.crt'),
  cert: fs.readFileSync('client.crt'),
  key: fs.readFileSync('client.key'),
});

client.on('connect', () => {
  console.log('Connected');
  client.subscribe('v4/groups/<enterprise_code>.master/+/uplinks');
});

client.on('message', (topic, message) => {
  console.log(`${topic}: ${message.toString()}`);
});

Replace <enterprise_code> with your enterprise path (e.g., nnn.acme). Your administrator can provide this value.

Quick Start (Username/Password Auth)

Username/password authentication is a simpler alternative that doesn't require certificate management. Use the API key's username and token as MQTT credentials.

1. Create an API Key

Create a service account in the portal under Manage > API Keys. Note the username (e.g., api-sp-global-04f62b) and the API token shown once at creation.

2. Connect with MQTT

mosquitto (CLI)

mosquitto_sub \
  -h mqtt.dev-au-03.nnnco.io -p 8883 \
  -u "api-sp-global-04f62b" \
  -P "YOUR_API_TOKEN" \
  --cafile ca.crt \
  -t "v4/groups/<enterprise_code>.master/+/uplinks" \
  -v

CA certificate still required

TLS is always required. Use the platform's CA certificate (ca.crt) for server verification. You can obtain it by creating an MQTT certificate (the ca_certificate_pem field in the response), or from your administrator.

Python (paho-mqtt)

import ssl
import paho.mqtt.client as mqtt

def on_connect(client, userdata, flags, rc, properties=None):
    print(f"Connected (rc={rc})")
    client.subscribe("v4/groups/<enterprise_code>.master/+/uplinks")

def on_message(client, userdata, msg):
    print(f"{msg.topic}: {msg.payload.decode()}")

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
client.tls_set(
    ca_certs="ca.crt",
    tls_version=ssl.PROTOCOL_TLS_CLIENT,
)
client.username_pw_set("api-sp-global-04f62b", "YOUR_API_TOKEN")
client.on_connect = on_connect
client.on_message = on_message

client.connect("mqtt.dev-au-03.nnnco.io", 8883)
client.loop_forever()

Node.js (mqtt.js)

const mqtt = require('mqtt');
const fs = require('fs');

const client = mqtt.connect('mqtts://mqtt.dev-au-03.nnnco.io:8883', {
  ca: fs.readFileSync('ca.crt'),
  username: 'api-sp-global-04f62b',
  password: 'YOUR_API_TOKEN',
});

client.on('connect', () => {
  console.log('Connected');
  client.subscribe('v4/groups/<enterprise_code>.master/+/uplinks');
});

client.on('message', (topic, message) => {
  console.log(`${topic}: ${message.toString()}`);
});

Replace <enterprise_code> with your enterprise path (e.g., nnn.acme). Your administrator can provide this value.

Topics

MQTT topics follow the pattern:

v4/groups/{enterprise_code}.master/{device_id}/{message_type}
Topic Pattern Description
v4/groups/{enterprise}.master/+/uplinks All uplinks for your enterprise
v4/groups/{enterprise}.master/{device_id}/uplinks Uplinks from a specific device
v4/groups/{enterprise}.master/+/downlinks All downlink confirmations
v4/groups/{enterprise}.master/+/joins All join events
v4/groups/{enterprise}.master/# All message types for your enterprise

Wildcards: - # — matches all remaining levels (e.g., all devices and message types) - + — matches a single level (e.g., any device ID)

Message Format

Each MQTT message contains a JSON payload:

{
  "device_id": "ABC123",
  "timestamp_ms": 1710300000000,
  "source": "dl-mqtt",
  "message_type": "uplink",
  "device_type": "nsen-v2",
  "readings": [
    {"channel_id": "temperature", "value": 22.5, "unit": "\u00b0C"},
    {"channel_id": "humidity", "value": 65, "unit": "%"}
  ],
  "network_metadata": {
    "rssi": -95,
    "snr": 7.5,
    "gateway_id": "GW001"
  },
  "location": {"latitude": -33.8688, "longitude": 151.2093},
  "raw_payload": "0x1A2B3C..."
}

Certificate Management

List Certificates

curl -H "Authorization: Bearer <token>" \
  https://api.dev-au-03.nnnco.io/api/v4/manage/mqtt-certificates/

Revoke a Certificate

curl -X POST -H "Authorization: Bearer <token>" \
  https://api.dev-au-03.nnnco.io/api/v4/manage/mqtt-certificates/<cert-id>/revoke/

Revoked certificates are immediately rejected on the next connection attempt.

Certificate Limits

  • 10 active certificates per API key
  • Default validity: 1 year (8,760 hours)
  • Maximum validity: 10 years (87,600 hours)
  • The private key is returned once at creation — it is never stored on the server

Connection Details

Setting Value
Host mqtt.dev-au-03.nnnco.io
Port 8883 (TLS required)
Protocol MQTT v3.1.1 or v5
Auth X.509 client certificate or username/password
QoS 0 or 1 supported
Keep Alive 60 seconds recommended

Troubleshooting

Issue Solution
SSL: CERTIFICATE_VERIFY_FAILED Ensure you're using the ca_certificate_pem from the create response, not a system CA
Connection refused Verify the cert hasn't expired: openssl x509 -in client.crt -noout -dates
Not authorized (cert auth) Check that the API key is active and belongs to your enterprise
Not authorized (username/password) Verify the API token is correct — it is only shown once at API key creation
No messages received Verify topic matches your enterprise code — check with your admin
certificate revoked Generate a new certificate — the old one was revoked