Subscribe to real-time data
Subscribes the connection to device data. Once the connection is subscribed, the server sends a realtime_data message for every uplink it receives, confirmed or unconfirmed. Data arrives from the devices of the application you are connected to and of applications that granted it access.
While the application has no subscribed connections, the server accumulates its data in a queue and sends it after subscription. So after reconnecting you also receive the uplinks that came while the client was disconnected.
With the "downlink_status": true flag the server also sends downlink_status messages that report the status of sent downlink frames.
Request and response: consume_req → consume_resp, then realtime_data messages.
Access: a token of any access level. The token access level does not affect the data stream.
- The
downlink_statusflag is not in the v0.17 description. consume_respcontains theoperation_idfrom the request.- The content of
realtime_datahas changed. New fields:battery_level,margin,join_request_time, and insidedata—packet_loss_rate,tagsand the JS codec result (execResult,execError). The server does not send thestatus,data.idanddata.gateway_availablefields from the v0.17 example.data.timecomes in ISO 8601 without a time zone, not as2018-02-17 13:06:22+0000.
Request
Fields not marked as required may be omitted.
| Field | Type | Description |
|---|---|---|
cmd | string | consume_req |
operation_id | string | Any string; the server returns it in the response to match the request and the response |
downlink_status | bool | true — also send downlink_status messages. Default false |
{
"cmd": "consume_req",
"operation_id": "sub1",
"downlink_status": true
}
Response
| Field | Type | Description |
|---|---|---|
cmd | string | consume_resp |
operation_id | string | Value from the request |
status | uint8 | 1 — the connection is subscribed, 2 — error |
consumer_count | uint16 | How many connections of the application are subscribed, including this one. On error 1 — how many are subscribed now; absent on errors 2 and 3 |
error_code, error_text | uint8, string | Only on error, see below |
{
"cmd": "consume_resp",
"operation_id": "sub1",
"status": 1,
"consumer_count": 1
}
Errors
error_code | error_text | What happened |
|---|---|---|
| 1 | Consumer limit reached | The application already has the maximum number of subscribed connections. Find the extra ones with connections_list and close or unsubscribe them |
| 2 | Already consumed | This connection is already subscribed: by an earlier consume_req or automatically on connect |
| 3 | Disabled application | The application has no non-revoked token left — for example, the tokens were revoked after connecting |
The realtime_data message
| Field | Type | Description |
|---|---|---|
cmd | string | realtime_data |
devEui | string | Device DevEUI |
devAddr | string | Device DevAddr |
data | object | The frame and reception parameters, see below |
battery_level | float | Battery level from the device's last answer to the status request (DevStatusAns): 0 — external power, 255 — the device cannot measure the level, otherwise — percent, from 0.4 to 100. null until the server receives such an answer |
margin | int8 | SNR margin from the same answer, dB, from −32 to 31. null until the server receives the answer |
join_request_time | string | Time of the device's last Join Request by the gateway clock, UTC, ISO 8601. null if the server has not seen the device join, e.g. for an ABP device |
data fields:
| Field | Type | Description |
|---|---|---|
fcnt | uint32 | Uplink frame counter |
fport | int16 | Application port. 0 — data holds MAC commands; −1 — the frame has no port and no data |
data | string | Payload in hex, already decrypted |
mtype | uint8 | Frame type: 2 — Unconfirmed Data Up, 4 — Confirmed Data Up |
adr | bool | The device has ADR enabled (the ADR bit in the frame header) |
ack | bool | The device requested an ADR acknowledgement (the ADRACKReq bit). This is not a downlink acknowledgement |
fopts | string | MAC commands from the FOpts field in hex; an empty string if there are none |
datr | uint8 | Data rate number (DR) in the device frequency plan |
freq | float | Reception frequency, MHz |
rssi | int16 | RSSI, dBm |
lsnr | float | SNR, dB |
size | uint16 | Size of the whole received LoRaWAN frame (PHYPayload), bytes |
time | string | Reception time by the gateway clock, UTC, ISO 8601 without a time zone, e.g. 2026-10-08T09:47:18.528002 |
gatewayId | string | EUI of the gateway through which the server received the frame, 16 hex characters |
packet_loss_rate | float | Frame loss calculated from gaps in the fcnt counter over the last 20 uplinks, % |
tags | object | Application and device tags; if keys match, the device tag takes precedence. An empty object if there are no tags |
execResult | object | Only if the application has a JS codec configured. The decodeUplink result: data — the decoded data, errors and warnings — codec messages. null if the codec failed |
execError | string | Only with a JS codec: the codec error text, or null if there is no error |
{
"cmd": "realtime_data",
"devEui": "6F1E570FFE14DBFC",
"devAddr": "78130AE1",
"data": {
"datr": 5,
"rssi": -97,
"lsnr": 8.5,
"data": "0A1B2C3D4E5F6071",
"freq": 868.9,
"time": "2026-10-08T09:47:18.528002",
"ack": false,
"size": 21,
"gatewayId": "0000B827EBFD64DE",
"adr": true,
"fcnt": 1542,
"mtype": 2,
"fopts": "",
"fport": 2,
"packet_loss_rate": 0,
"execResult": {
"errors": [],
"warnings": [],
"data": {
"temperature": 21.5
}
},
"execError": null,
"tags": {
"building": "A"
}
},
"battery_level": 100.0,
"margin": 9,
"join_request_time": "2026-10-01T06:12:40.114233Z"
}
Good to know
- One queue per application. If several connections of one application are subscribed, each
realtime_datamessage reaches only one of them: the server hands messages to the connections in turn. For one client to receive all data, keep one subscribed connection per application. - Data accumulates while nobody is subscribed. The server keeps uplinks that arrive without subscribers and sends them after subscription — the accumulated ones first, then new ones. By default the queue is deleted together with its data if nobody subscribes to it for 14 days.
- A message may be lost on a disconnect. The server considers a message delivered as soon as it has sent it to the connection. If the connection drops at that moment, the message is not returned to the queue. Fetch missed data with
get_data_req. - The subscription lives as long as the connection is open. Subscribe again after reconnecting.
- Automatic subscription. If automatic subscription is enabled in the application settings, the server subscribes the connection itself right after
connectedand sendsconsume_respwithoutoperation_id. In that case the server responds toconsume_reqwith error 2. Automatic subscription does not enabledownlink_status: to receive statuses, unsubscribe withunconsume_reqand subscribe again with"downlink_status": true. - The
downlink_statusflag is applied only when the subscription is made. If the connection is already subscribed without it, unsubscribe first withunconsume_req.
See also
unconsume_req— unsubscribe from data.- Sending data to a device —
downlink_statusmessages and replying to a device after its uplink. get_data_req— device data for a period, if messages were missed.