MachineQ Developer Documentation logo DOCS

Working with Device Data

MQcentral records every uplink in two complementary forms: decoded payloads at /v1/devices/{DevEUI}/payloads and raw log entries at /v1/logs. Use the payloads endpoint for decoded application data; use the logs endpoint for raw hex and signal metadata.

Before You Begin

You need:

Decoded Payloads: /v1/devices/{DevEUI}/payloads

Each entry in the Payloads array contains:

Payload Example
{
  "Time": "2026-04-30T14:23:11.523Z",
  "ApplicationData": {
    "temperature": 23.5,
    "humidity": 41.2
  },
  "Data": {
    "FCnt": "1247",
    "Fport": "1",
    "SpreadingFactor": "7"
  }
}
  • Time: when the uplink was received.
  • ApplicationData: the decoded payload as a structured JSON object. Only populated if a decoder type is assigned to the device.
  • Data: raw metadata key-value pairs from the network server, including frame counter and port.

Raw Logs: /v1/logs?DevEUI=...

For signal-level metadata and raw hex payloads:

Raw Log Entry Example
{
  "Timestamp": "2026-04-30T14:23:11.523Z",
  "DevEUI": "2CC407FFFE500C3F",
  "DevAddr": "01ABCDEF",
  "Fport": "1",
  "FCnt": "1247",
  "PayloadHex": "0142A30B009A",
  "PrimaryGatewayRSSI": "-87",
  "PrimaryGatewaySNR": "9.5",
  "SpreadingFactor": "7",
  "GatewayCount": "2",
  "MessageType": "4",
  "MessageTypeText": "Confirmed data up"
}

Key fields:

  • Fport: application port (1–223). Devices use ports to multiplex different message types, such as sensor data on one port and configuration responses on another.
  • FCnt: frame counter. Monotonically increasing per device. A counter reset indicates a rejoin, which can signal "device just restarted."
  • PrimaryGatewayRSSI / PrimaryGatewaySNR: Received Signal Strength Indicator (RSSI) and Signal-to-Noise Ratio (SNR) from the gateway that heard the uplink best.
  • GatewayCount: how many gateways detected this uplink. Values above 1 indicate redundant coverage.

Decoded payloads

Fetch the decoded payloads
curl -sS -H "Authorization: Bearer $MQ_TOKEN" \
  "https://api.machineq.net/v1/devices/$MQ_DEV_EUI/payloads?StartTime=2026-04-01T00:00:00Z&EndTime=2026-04-30T00:00:00Z" \
  | jq

Filter by StartTime and EndTime in RFC3339 format.

Raw logs with signal metadata

Fetch the raw logs
curl -sS -H "Authorization: Bearer $MQ_TOKEN" \
  "https://api.machineq.net/v1/logs?DevEUI=$MQ_DEV_EUI&StartTime=2026-04-01T00:00:00Z&EndTime=2026-04-30T00:00:00Z&Page=1" \
  | jq
API reference:

Use the Page parameter to paginate; each page returns up to 100 log entries. Without a page number, the API returns the 100 newest entries.

For real-time consumption, configure an output profile with a delivery target rather than polling; see Data Delivery: Output Profiles.

Payload Decoders

Devices send compact binary payloads to conserve battery and air time. MQcentral uses pre-built decoder types to translate raw hexadecimal from the device into structured ApplicationData.

List available decoder types

List the decoder types
curl -sS -H "Authorization: Bearer $MQ_TOKEN" \
  "https://api.machineq.net/v1/decodertypes" | jq

Each entry returns an Id and Name. Supported decoders include ELSYS, LPP, Milesight sensor variants, and others; call the endpoint to see the full list available for your account.

Assign a decoder to a device

Pass the decoder Id as DecoderType when provisioning or patching a device:

Assign the decoder to a device
curl -sS -X PATCH https://api.machineq.net/v1/devices/$MQ_DEV_EUI \
  -H "Authorization: Bearer $MQ_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "Name": "warehouse-temp-sensor-001",
    "DecoderType": "<decoder_id>"
  }'

Once assigned, ApplicationData populates automatically on every subsequent uplink.

Queue a downlink to a device:

Send the downlink
curl -sS -X POST https://api.machineq.net/v1/devices/$MQ_DEV_EUI/message \
  -H "Authorization: Bearer $MQ_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "DevEUI": "2CC407FFFE500C3F",
    "Payload": "01FF",
    "TargetPort": "100",
    "Confirm": true,
    "FlushQueue": false
  }'
Field Required Description
DevEUI Yes Target device EUI.
Payload Yes (if no ApplicationPayload) Hex-encoded payload string.
TargetPort Yes (with Payload) LoRaWAN port number as a string (1–223).
Confirm No If true, requests an acknowledgment frame from the device.
FlushQueue No If true, clears pending queued messages before sending this one.
ApplicationPayload Yes (if no Payload) Device-specific JSON object (alternative to Payload). Consult device documentation for the correct structure.

The downlink is sent on the next available receive window. For Class A devices that means the next uplink. For Class C devices it goes out almost immediately.

Confirm: true requests a MAC-layer acknowledgment; it confirms the network server delivered the packet, not that your application logic ran. For application-level acknowledgment, use Reliable Downlinks.

For configuration pushes or any downlink where you need to know whether the device acknowledged at the application level, the Firmware Update Over The Air (FUOTA) service provides a Reliable Downlinks API: send a downlink, expect a specific uplink response, and retry on failure until success or max_retries.

Note: The Reliable Downlinks API is hosted at https://fuota.machineq.net, a separate base URL from the v1 API used elsewhere in this guide. For the full FUOTA API reference, check out: https://docs.machineq.net/mq-fuota-api-v3.2.html.

Create the reliable downlink job
curl -sS -X POST https://fuota.machineq.net/api/v3.2/reliable_downlinks \
  -H "Authorization: Bearer $MQ_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "config-rollout-2026-04-30",
    "devices": [
      "2CC407FFFE500C3F",
      "2CC407FFFE500BDC",
      "2CC407FFFE500C02",
      "2CC407FFFE500C04",
      "2CC407FFFE500C05"
    ],
    "downlink_fport": 221,
    "downlink_hex": "0101C20200E103C8050100",
    "expected_uplink_fport": 221,
    "expected_uplink_hex": "0101C20200E103C8050100",
    "max_retries": 24,
    "retry_interval": 900
  }'
Field Required Description
name Yes Human-readable job name.
downlink_hex Yes Hex payload to send.
downlink_fport Yes FPort for the downlink (1–223).
expected_uplink_hex Yes Hex payload expected as confirmation from the device.
expected_uplink_fport Yes FPort of the expected uplink response.
devices Yes (or device_group_id) Array of DevEUI strings.
device_group_id No FUOTA device group ID (alternative to devices).
max_retries No Retry limit per device (default: 24).
retry_interval No Seconds between retries per device (default: 900).

The response returns a job_id. Poll job status with:

Fetch the reliable downlink status
curl -sS -H "Authorization: Bearer $MQ_TOKEN" \
  "https://fuota.machineq.net/api/v3.2/reliable_downlinks/<job_id>" | jq

The status response includes successful_devices, failed_devices, successful_count, failed_count, and device_count. Devices not in either list are still in progress.

  • Tune retry_interval to your device's uplink period. For Class A devices that report every 15 minutes, set retry_interval at or slightly below that interval. A shorter value queues downlinks the device can't receive yet.
  • Batch by intent, not by device. Send one job with all target devices rather than one job per device. The service is designed for fleet-scale pushes.
  • Class C devices need a longer interval, not shorter. A short retry interval on Class C floods the radio and starves uplinks on half-duplex gateways.

Handling Duplicates and Out-of-Order Delivery

LoRaWAN is at-least-once delivery. The same uplink may be delivered multiple times, most commonly when multiple gateways hear the same packet. A robust receiver must be idempotent.

The combination (DevEUI, FCnt) is unique per uplink. Use it as your idempotency key. If your downstream system has already processed a (DevEUI, FCnt) pair, drop the duplicate.

Out-of-order delivery is rarer but real. Don't assume FCnt arrives in monotonic order at your receiver; across gateways and retries, two uplinks can arrive in either order. Sort by FCnt if ordering matters to your application logic.

What's Next?