Skip to main content

Sending data to a device

A downlink is data from the server to a device: a command, a new setting, or a reply to a request. Sending is asynchronous: the server queues the frame, immediately responds with a dataId identifier, and transmits the frame when the device has a receive window open. The server then sends separate messages to report what happens to the frame.

When a device can receive a frame​

ClassWhen it receivesWhen the frame goes out
AOnly in two short windows (RX1, RX2) right after its own uplinkAfter the device's next uplink — minutes or hours later
CThe receiver is always onRight after queuing
B—The server does not support class B yet

For more about classes, see Device classes. The class of a particular device is returned by dev_lw_class_req.

Command order​

  1. Subscribe to data and frame statuses: consume_req with "downlink_status": true. The flag is applied only when the subscription is made: if the connection is already subscribed without it, unsubscribe first with unconsume_req.
  2. Check that the data fits: max_dl_data_req.
  3. Queue the frame: downlink_data_req. Keep the dataId from the response: it identifies the frame when you check its status.
  4. Wait for a downlink_status message with a final status. If no message arrives, request the status with downlink_ack_req.
  5. If the frames have not left yet and are no longer needed, withdraw all scheduled frames of the device: cancel_downlink_req with devEui and "allScheduled": true. A single frame cannot be withdrawn by the dataId from step 3.

A class A device — the frame waits in the queue until the next uplink:

A class C device — the server transmits the frame right away, without waiting for an uplink:

A frame for a class C device goes through the gateway that received the device's last uplink best. Until the device has sent at least one uplink after joining the network, the server does not know which gateway to use, and the frame stays in the queue.

Frame status​

The frame status is visible in three places:

  • in the downlink_status message the server sends on its own if the subscription was made with "downlink_status": true;
  • in the downlink_ack_req response — on request;
  • in the get_downlink_data_req history — for a period.
CodeNameMeaningFinal
0ScheduledThe frame is in the queue, waiting for a receive windowno
4Realtime ScheduledA realTime frame is waiting for the nearest windowno
1SentThe frame has been handed to a gateway; the server is waiting for the transmission acknowledgementno
14DC LimitThe gateway airtime budget is exhausted; the frame stays in the queue and goes out laterno
3DeliveredThe gateway radiated the frame. This is an acknowledgement from the gateway, not from the deviceyes
2LateThe gateway rejected the frame: too late for the receive windowyes
9Too EarlyThe gateway rejected the frame: too early to transmityes
10CollisionThe gateway rejected the frame: another transmission is already scheduled for that timeyes
11TX Freq RejectedThe gateway does not support the transmission frequencyyes
12TX Power RejectedThe gateway does not support the transmit poweryes
13GPS UnlockedWithout GPS sync the gateway cannot transmit at the scheduled timeyes
7TX_ACK TimeoutThe gateway did not acknowledge the transmission within 10 secondsyes
5Realtime LateA realTime frame did not make it into a window within 2 seconds and was droppedyes
8ExpiredThe ttl ran out (1 hour by default) — the frame was droppedyes
6CanceledThe frame was withdrawn with cancel_downlink_req or downlink_purge_reqyes

The server sends it on every status change except queuing (0 and 4) and withdrawal (6).

  • Statuses go to the application that owns the device — for frames sent by any means, not only through the WebSocket API.
  • There is one status queue per application. If several connections of one application are subscribed, each message reaches only one of them — the same as realtime_data messages.
  • The server keeps undelivered messages for 5 minutes. If the connection was down for longer, request the status with downlink_ack_req.
  • In the current server version the status subscription is not removed on unsubscribing or closing the connection, so after a reconnect some downlink_status messages may not arrive. Check the final status of important frames with downlink_ack_req.
FieldTypeDescription
cmdstringdownlink_status
devEui, devAddrstringThe device
dataIduint32Frame identifier from downlink_data_resp
downlink_statusuint8Status code, see the table above
downlink_status_textstringStatus name
downlink_status_timestringWhen the status was set, UTC, ISO 8601
emit_tsstringWhen the server sent the message, UTC, ISO 8601. Helps to order messages that arrived out of order
{
"cmd": "downlink_status",
"devEui": "6F1E570FFE14DBFC",
"devAddr": "78130AE1",
"dataId": 3046127811,
"downlink_status": 3,
"downlink_status_text": "Delivered",
"downlink_status_time": "2026-10-08T09:47:21.402113+00:00",
"emit_ts": "2026-10-08T09:47:21.415870+00:00"
}

If a frame was not delivered​

StatusWhat to do
8 ExpiredThe device did not report while the frame was waiting. Increase ttl to the device's uplink interval, with a margin
5 Realtime LateNo receive window opened within 2 seconds. Do not set realTime for deferred sending
2 Late, 9 Too Early, 10 CollisionThe gateway could not transmit at the scheduled time. Send the frame again
11 TX Freq RejectedThe transmission frequency does not suit the gateway. Remove freq from the request or check the device frequency plan
12 TX Power RejectedThe transmit power does not suit the gateway. Check the device frequency plan and the gateway settings
13 GPS UnlockedCheck the GPS antenna and the gateway synchronization
7 TX_ACK TimeoutCheck the gateway connection to the server
14 DC LimitNothing to do: the frame stays in the queue and goes out later

The device does not acknowledge reception: the server sends frames as Unconfirmed Data Down. The only way to make sure the device executed a command is its reply in an uplink.

Commands of the group​

CommandPurpose
dev_lw_class_reqGet the device class — it determines when the frame goes out
max_dl_data_reqGet the number of bytes that fit into a frame
downlink_data_reqQueue a frame
downlink_ack_reqGet the frame status on request
cancel_downlink_reqWithdraw the scheduled frames of a device that have not left yet
downlink_purge_reqClear the device queue: cancel frames with status 0 (high access level token)