MQTT is a supported broker transport for control devices that should keep a connection open. Firmware starts with the HTTPS API: authenticate, read the MQTT catalog, request a short-lived MQTT credential, then connect with the values returned by Realer.
OAuth token issue, catalog discovery, and MQTT credential issue are HTTPS calls. This page describes the MQTT runtime loop after the device has authenticated and received the returned CONNECT tuple.
The public broker endpoint uses MQTT over TLS: mqtts://mqtt.therealer.com:8883. Plain MQTT is not accepted for public device traffic.
Use the catalog broker_url for the broker connection. Use HTTPS only for OAuth, catalog discovery, and MQTT credential issue. The OAuth Bearer token is never the MQTT password.
This page summarizes the MQTT runtime sequence. OAuth, catalog discovery, and credential issue remain HTTPS calls; feed data, desired-state delivery, and application acknowledgements use MQTT over TLS after broker connection.
| Step | What firmware uses | Firmware purpose |
|---|---|---|
| Authenticate | OAuth device authentication | Issue or renew the Bearer access token used for HTTPS bootstrap calls. |
| Read MQTT catalog | GET /iot/v1/devices/{device_id}/mqtt |
Discover broker URL, MQTT limits, topics, scopes, and credential request data. |
| Request CONNECT tuple | POST /iot/v1/mqtt-credentials |
Receive the short-lived MQTT client ID, username, and plaintext credential returned once. |
| Publish and subscribe | Catalog feed_data_topic, feed_data_ack_topic, and desired_topic values |
Publish feed data, receive application acknowledgements, and receive command desired-state messages. |
| Handle application messages | MQTT payload reference | Use canonical JSON payloads plus acknowledgement status, retryable, and error.type for firmware behavior. |
| Handle field behavior | Field semantics | Use shared retry, ordering, desired-state correlation, expiry, and result-handling rules. |
MQTT scopes are Realer OAuth authorization values. Request them in POST /oauth/token; they are not sent inside MQTT packets.
During HTTPS bootstrap, Realer uses the Bearer token scopes and the requested MQTT credential scopes to issue a short-lived CONNECT tuple. During broker use, Realer checks the scopes stored on that MQTT credential for CONNECT, SUBSCRIBE, and PUBLISH.
| Scope | Firmware use |
|---|---|
iot:catalog:read |
Bearer token can read the MQTT catalog over HTTPS. |
iot:mqtt:connect |
MQTT credential can connect to the broker. |
iot:mqtt:ack:read |
MQTT credential can subscribe to the application acknowledgement topic. |
iot:mqtt:feed-data:write |
MQTT credential can publish sensor values and command acknowledgements to catalog feed-data topics. |
iot:mqtt:desired:read |
MQTT credential can subscribe to command desired-state topics. Omit this scope when the device has no command routes or does not handle desired-state messages. |
POST /oauth/token with grant_type=client_credentials. Request iot:catalog:read and the MQTT scopes your firmware needs.
GET /iot/v1/devices/{device_id}/mqtt with Authorization: Bearer <access_token>. This response tells the device which broker URL, client ID, topics, limits, and credential request to use.
credential_endpoint with its returned body unless your firmware intentionally requests a narrower scope set. The response returns mqtt_client_id, mqtt_username, mqtt_credential, scopes, expires_in, renew_after, and session_hard_expires_in.
broker_url with the exact client ID, username, and password returned by Realer. The OAuth Bearer token is not used as the MQTT password.
feed_data_ack_topic. Subscribe to command desired_topic values when your catalog contains command routes. Publish measurements and command acknowledgements to route feed_data_topic values.
renew_after to request the next MQTT credential, reconnect with the new tuple, and resubscribe.
The OAuth response does not include the MQTT broker host, topics, username, or password. Read the catalog after authentication.
credential_endpoint, MQTT credentials are not available for that device yet. Use the HTTPS flow only when HTTPS access is enabled for the same device; otherwise retry later and keep local safe behavior until MQTT credentials become available.
curl "https://api.therealer.com/iot/v1/devices/12345/mqtt" \
-H 'Authorization: Bearer b11db7f6c816568eb3b156df3aeaa5'
Return the MQTT broker URL, route topics, limits, credential lifecycle, and default credential request body.
The Bearer access token obtained from the OAuth token endpoint.
Type: String
Example: Bearer b11db7f6c816568eb3b156df3aeaa5
ID (id) of the authenticated control device that is reading its MQTT catalog.
Type: Integer
Example: 12345
200 OK - Abbreviated response example
Save the returned broker URL, client ID, acknowledgement topic, route topics, limits, credential lifecycle, and credential request body.
{
"code": 2000,
"mqtt": {
"broker_url": "mqtts://mqtt.therealer.com:8883",
"protocol": "mqtt-5.0",
"client_id": "cdv_aaaaaaaaaaaaaaaaaaaaaaaaaa",
"qos": 1,
"retain_policy": "disabled",
"feed_data_ack_topic": "realer/iot/v1/devices/cdv_aaaaaaaaaaaaaaaaaaaaaaaaaa/acks",
"feed_data_ack_subscribe_scope": "iot:mqtt:ack:read",
"credential_endpoint": {
"endpoint": "/iot/v1/mqtt-credentials",
"http_method": "POST",
"body": {
"device_id": 12345,
"scopes": [
"iot:mqtt:connect",
"iot:mqtt:ack:read",
"iot:mqtt:feed-data:write"
]
}
}
},
"mqtt_routes": []
}
The live catalog can include limits, credential lifecycle hints, capabilities, and diagnostic fields. Firmware should honor limits it understands and ignore unknown fields.
Use the credential request from the catalog as the default request body. The response is sent with 201 Created, Cache-Control: no-store, and Pragma: no-cache. The password is returned once, so keep it only in short-lived runtime memory.
curl "https://api.therealer.com/iot/v1/mqtt-credentials" \
-H 'Authorization: Bearer b11db7f6c816568eb3b156df3aeaa5' \
-H 'Content-Type: application/json' \
-d '{"device_id":12345,"scopes":["iot:mqtt:connect","iot:mqtt:ack:read","iot:mqtt:feed-data:write"]}'
Issue a short-lived MQTT CONNECT tuple for the authenticated control device.
The Bearer access token obtained from the OAuth token endpoint.
Type: String
Example: Bearer b11db7f6c816568eb3b156df3aeaa5
The request body media type.
Value: application/json
{
"device_id": 12345,
"scopes": [
"iot:mqtt:connect",
"iot:mqtt:ack:read",
"iot:mqtt:feed-data:write"
]
}
Schema: mqtt-credential-request.schema.json
ID of the authenticated control device that will connect to the broker.
MQTT broker scopes requested for the short-lived CONNECT tuple. If omitted, Realer uses the default MQTT credential scopes for the device and requires iot:mqtt:connect.
201 Created
Use the returned client ID, username, and plaintext credential for MQTT CONNECT. The plaintext credential is returned once.
{
"code": 2000,
"mqtt": {
"mqtt_client_id": "cdv_aaaaaaaaaaaaaaaaaaaaaaaaaa",
"mqtt_username": "realer-cdv_aaaaaaaaaaaaaaaaaaaaaaaaaa-cred-v12",
"mqtt_credential": "plaintext-returned-once",
"scopes": [
"iot:mqtt:connect",
"iot:mqtt:ack:read",
"iot:mqtt:feed-data:write"
],
"expires_in": 3600,
"renew_after": 2700,
"session_hard_expires_in": 3600
}
}
The response can include additional diagnostic fields. Firmware should use the documented fields above and ignore unknown fields.
Sensor routes and command routes use the same feed-data publish shape. Command routes add an optional desired-state subscription.
Publishing command feed data reports the physical command state observed by the device. It does not directly update the desired command value stored by Realer.
| Route type | Firmware publishes | Firmware subscribes |
|---|---|---|
sensor |
feed_data_topic with sensor value payloads |
feed_data_ack_topic |
command |
feed_data_topic with command acknowledgement payloads |
feed_data_ack_topic and desired_topic |
{
"source_type": "sensor",
"mqtt": {
"feed_data_topic": "realer/iot/v1/devices/cdv_aaaaaaaaaaaaaaaaaaaaaaaaaa/routes/rte_aaaaaaaaaaaaaaaaaaaaaaaaaa/feed-data",
"feed_data_publish_scope": "iot:mqtt:feed-data:write"
}
},
{
"source_type": "command",
"mqtt": {
"feed_data_topic": "realer/iot/v1/devices/cdv_aaaaaaaaaaaaaaaaaaaaaaaaaa/routes/rte_bbbbbbbbbbbbbbbbbbbbbbbbbb/feed-data",
"feed_data_publish_scope": "iot:mqtt:feed-data:write",
"desired_topic": "realer/iot/v1/devices/cdv_aaaaaaaaaaaaaaaaaaaaaaaaaa/routes/rte_bbbbbbbbbbbbbbbbbbbbbbbbbb/desired",
"desired_subscribe_scope": "iot:mqtt:desired:read"
}
}
Publish feed data with QoS 1 and retain disabled. MQTT PUBACK means broker acceptance only; the application result arrives later on feed_data_ack_topic. See the MQTT payload reference for canonical JSON payloads.
message_id is required for retry and idempotency.value is required.value_received_at is required.desired_id when responding to a desired-state message. Use report_status only when the outcome is not the default applied.desired_id report local physical changes, such as a switch toggled at the device. For those local reports, omit report_status; if sent, only reported is valid.message_id if the device changed while offline.version, status, retryable, message_id, and, when applicable, desired_id, the publish sequence_number, and error.accepted, replayed, conflict, rejected, or error.| Condition | Firmware handling |
|---|---|
| Broker disconnect | Reconnect with the current valid tuple. If reconnect fails or the tuple is expired, request a new CONNECT tuple over HTTPS. |
| Credential expiry | Use renew_after to renew before expiry. If renewal cannot complete, keep local safe behavior until cloud authorization is restored. |
| Publish failure | Retry the same local event with the same message_id when the MQTT client reports that the publish was not accepted by the broker. |
| Negative acknowledgement | Read acknowledgement status, retryable, and error.type. Retry only when retryable is true. |
| Desired-state rejection | Publish command feed data with the same desired_id, current physical value, and report_status set to rejected or stale. |
Command desired-state messages arrive on the route desired_topic. Each message has version, desired_id, value, valid_for_seconds, expires_at, and a server-assigned sequence_number. See the MQTT payload reference for the canonical payload shape.
valid_for_seconds is the execution window firmware should use for stale-command handling.expires_at is diagnostic server time; devices with unreliable clocks should not depend on it alone.sequence_number to ignore stale lower sequence values.desired_id.report_status set to rejected or stale.
Use renew_after to start renewal before the MQTT credential expires. V1 uses controlled reconnect: request a new CONNECT tuple, disconnect the old MQTT session, reconnect with the new tuple, and resubscribe to acknowledgement and desired-state topics.
POST /oauth/revoke on intentional shutdown, decommissioning, or credential compromise when the device can still reach HTTPS.