Skip to main content

Message Formats

Overview​

Know the shape of every JSON object that passes through a V2 integration, so your system and your data converter agree on each field. This article describes the uplink objects, the downlink objects and the V1 differences. It applies to the V2 types HTTP_V2, MQTT_V2 and MQTT_BROKER.

To choose an integration type, see Integrations Overview.

How it works​

Where each object appears​

A V2 integration converts between the raw bytes of a LoRaWAN® device and JSON, with a Custom v2 data converter:

DirectionObjectWho creates itWho reads it
UplinkDecoder inputKONA CoreYour decodeUplink function
UplinkDecoder outputYour decodeUplink functionKONA Core, which delivers the result to your system
DownlinkDownlink messageYour systemKONA Core
DownlinkEncoder inputKONA Core, from the downlink messageYour encodeDownlink function
DownlinkEncoder outputYour encodeDownlink functionKONA Core, which puts the bytes in the device's downlink queue

The structures below come from the default code of a new Custom v2 converter, and from the KONA Core REST API. The example values are fake.

KONA Core calls decodeUplink(input) for each uplink that passes the integration's filters. The default decoder describes input like this:

// input object structure:
// - bytes - int[]
// - fPort - int
// - recvTime - Date (needs type check)
// - tektelicMetadata - Object
FieldTypeWhat it holds
bytesArray of integersThe decrypted payload of the uplink, one integer per byte.
fPortIntegerThe port of the uplink (FPort).
recvTimeDateThe time KONA Core received the uplink. Check its type with instanceof Date before you use it.
tektelicMetadataObjectDevice, application, frame and radio metadata. The fields are listed in the message your system receives.

Example, for an uplink of 3 bytes on port 10:

{
"bytes": [1, 103, 0],
"fPort": 10,
"recvTime": "2026-01-01T00:00:00.000Z",
"tektelicMetadata": {}
}

confirm how recvTime is shown when the input is serialized as JSON; inside the decoder it's a Date object.

The decoder returns an object with four fields. This is the return statement of the default decoder:

// output object structure:
// - data - Object
// - errors - string[]
// - warnings - string[]
// - tektelicMetadata - Object
return {
"data": {},
"errors": [],
"warnings": [],
"tektelicMetadata": input.tektelicMetadata
};
FieldTypeWhat it holds
dataObjectThe decoded values, in a structure you choose.
errorsArray of stringsErrors your decoder found, for example an unknown message type. Empty when decoding succeeded.
warningsArray of stringsProblems that didn't stop decoding, for example a value out of range.
tektelicMetadataObjectThe metadata from the input. The default decoder passes it through unchanged. We recommend keeping it, so your system receives the metadata with the data.

Example output, for a decoder that reads a temperature:

{
"data": {
"temperature": 10.3
},
"errors": [],
"warnings": [],
"tektelicMetadata": {}
}

Return an object with these four fields. confirm whether KONA Core checks the code when you save a converter, and which message it shows for invalid code. If the decoder throws an exception, KONA Core raises the event INTEGRATION_UL_DECODING_FAILURE. confirm whether KONA Core raises INTEGRATION_UL_DECODING_FAILURE when errors isn't empty, and whether it still delivers the message.

The integration delivers the decoded uplink to your system:

  • HTTP_V2: as an HTTP request to the Application address (IP or name without http or https prefix), Port and Base path of the integration.
  • MQTT_V2: published to the Push Topic on your broker.
  • MQTT_BROKER: published to the Uplink Topic (subscribe) on the KONA Core broker. The topic contains the DevEUI of the device.

The body is a JSON object with the device, the LoRaWAN frame and the radio data of the uplink. The field names below come from a failed HTTP_V2 delivery that KONA Core recorded in an INTEGRATION_DISCONNECTED alarm.

FieldTypeWhat it holds
deviceEuiStringThe DevEUI of the device, 16 hexadecimal digits.
devAddrStringThe DevAddr of the device, 8 hexadecimal digits.
deviceNameStringThe name of the device in KONA Core.
deviceClassStringThe device class, for example A.
deviceModelId, deviceModelNameStringThe ID and the name of the device model.
applicationId, applicationNameStringThe ID and the name of the device's application.
fPortIntegerThe port of the uplink.
fCntUpIntegerThe uplink frame counter.
fCntDownIntegerThe downlink frame counter.
confirmedBooleantrue when the uplink is a confirmed message.
adrBitBooleanThe ADR bit of the uplink: true when the device asks for ADR.
ackBitBooleanThe ACK bit of the uplink: true when the device acknowledges a confirmed downlink.
recvTimeIntegerThe reception time in GPS seconds, counted from 1980-01-06. This differs from the decoder input's JavaScript Date.
rfRegionStringThe frequency plan of the receiving gateway with the strongest signal, for example EU868.
uLFreqIntegerThe uplink frequency. the recorded KONA Core message uses an integer consistent with Hz, while the legacy field description says MHz.
dataRateIntegerThe data rate index of the uplink.
gatewayCountIntegerThe number of gateways that received the uplink.
marginIntegerThe radio margin reported in DevStatusAns, in dB. It describes the device's reception of the status request, not gateway RSSI.
batteryIntegerThe raw battery value from DevStatusAns; see Device status values.
devStatusTimeMillisIntegerThe time of the last DevStatusAns, in Unix milliseconds.
gatewayRxInfoArray of objectsOne entry per gateway that received the uplink. See the next table.

Device status values​

LoRaWAN defines the raw DevStatusAns battery value as follows: 0 means external power, 1–254 is the battery range, and 255 means unavailable. It isn't a percentage. The radio margin is a signed SNR value from -32 to 31 dB.

These definitions describe the protocol values. A value of 0 alone doesn't prove that KONA Core has received a status response. Check the status timestamp too.

For the protocol definitions, see section 5.5 of the LoRaWAN L2 specification.

Gateway reception values​

Each entry in gatewayRxInfo:

FieldTypeWhat it holds
gwEuiStringThe GW-ID of the gateway, 16 hexadecimal digits.
gatewayNameStringThe name of the gateway in KONA Core.
rssiIntegerThe RSSI of the uplink at this gateway, in dBm.
snrNumberThe SNR of the uplink at this gateway, in dB.
channel, antennaIdIntegerThe channel and the antenna that received the uplink.
codeRateStringThe LoRa coding rate, for example 4/5.
crcStatusIntegerThe CRC check result. confirm the values of crcStatus.
dataRateObjectmodulation (for example LORA), spreadFactor and bandwidth (in kHz).
lat, lon, altNumber or nullThe location of the gateway, when known.
gwTimeUtcMillis, gwTimeGpsMillisInteger or nullThe time the gateway received the uplink, in UTC and GPS time, when the gateway reports it.
rsigArray or nullOptional per-antenna reception information: antenna, channel, snr and rssi.

Example, with fake values, for an uplink received by one gateway:

{
"deviceEui": "0011223344556677",
"devAddr": "01ABCDEF",
"deviceName": "Example sensor",
"deviceClass": "A",
"deviceModelId": "00000000-0000-0000-0000-000000000001",
"deviceModelName": "Example model",
"applicationId": "00000000-0000-0000-0000-000000000002",
"applicationName": "Example application",
"fPort": 10,
"fCntUp": 42,
"fCntDown": 3,
"confirmed": false,
"adrBit": true,
"ackBit": false,
"recvTime": 1451260818,
"rfRegion": "EU868",
"uLFreq": 868100000,
"dataRate": 5,
"gatewayCount": 1,
"margin": 0,
"battery": 0,
"devStatusTimeMillis": 0,
"gatewayRxInfo": [
{
"gwEui": "AABBCCDDEEFF0011",
"gatewayName": "Example gateway",
"antennaId": 0,
"channel": 4,
"rssi": -80,
"snr": 9.5,
"codeRate": "4/5",
"crcStatus": 1,
"dataRate": {
"modulation": "LORA",
"spreadFactor": 7,
"bandwidth": 125
},
"lat": null,
"lon": null,
"alt": null,
"gwTimeUtcMillis": null,
"gwTimeGpsMillis": null,
"rsig": null
}
]
}

KONA Core merges output.data and output.tektelicMetadata into the delivered JSON object. If both contain the same key, the value from data takes precedence. The errors and warnings arrays aren't included in that body.

confirm the HTTP method and content type of the HTTP_V2 request, and that MQTT_V2 and MQTT_BROKER publish the same body.

When the application has Send app payload encrypted selected, the payload stays encrypted with the AppSKey. confirm what a V2 decoder receives in bytes when Send app payload encrypted is selected.

To send a downlink through a V2 integration, your system sends a downlink message. For HTTP_V2, it's a request to the integration's HTTP URL path on KONA Core: POST /api/v2/integration/http/<routing key>. The routing key in the path is specific to the integration. Treat the path like a credential. The request body:

FieldTypeWhat it holds
deviceEuiStringThe DevEUI of the device that gets the downlink.
dataObjectYour data, in a structure you choose. KONA Core passes it to the encoder.
confirmedBooleantrue for a confirmed downlink, false for an unconfirmed one.
msgIdStringYour identifier for the downlink, shown in the device's Downlink queue. confirm whether msgId is required.

Example:

{
"deviceEui": "0011223344556677",
"data": {
"reportingIntervalMinutes": 15
},
"confirmed": true,
"msgId": "example-0001"
}

The REST API describes the request in Process downlink v2.

For MQTT_V2 and MQTT_BROKER, publish the same V2 envelope: deviceEui, confirmed, msgId and data. KONA Core passes the data object to encodeDownlink(input) as input.data.

KONA Core calls encodeDownlink(input) with the data from the downlink message. The default encoder:

// input object structure:
// - data - Object (customer-defined)


// output object structure:
// - fPort - int
// - bytes - int[]
// - errors - string[]
// - warnings - string[]
return {
"fPort": 0,
"bytes": [],
"errors": [],
"warnings": []
};
ObjectFieldTypeWhat it holds
InputdataObjectThe data of the downlink message, as your system sent it.
OutputfPortIntegerThe port to send the downlink on.
OutputbytesArray of integersThe payload, one integer per byte.
OutputerrorsArray of stringsErrors your encoder found. Empty when encoding succeeded.
OutputwarningsArray of stringsProblems that didn't stop encoding.

Example, for the downlink message above:

{
"fPort": 100,
"bytes": [16, 0, 15],
"errors": [],
"warnings": []
}

If the encoder fails, KONA Core raises INTEGRATION_DL_ENCODING_FAILURE. An invalid downlink raises INVALID_DL_PAYLOAD. When encoding succeeds, KONA Core puts the port and bytes in the device's queue. For the queue, the receive windows and the confirmation, see Uplink & Downlink Data Flow.

Other messages​

confirm whether a V2 integration delivers messages other than uplinks to your system, for example events, join notifications or downlink acknowledgments, and their JSON format. No allowed source shows one.

KONA Core records events for integrations, such as INTEGRATION_DISCONNECTED, DECODER_BANNED and INTEGRATION_FIRST_UL. You see them in KONA Core, and alarm rules can send notifications for them. See Events & Alarms.

V1 differences​

The legacy types HTTP and MQTT use V1 converters, with other function signatures and other objects:

V1V2
DecoderDecoder(bytes, port): returns any objectdecodeUplink(input): returns data, errors, warnings, tektelicMetadata
EncoderEncoder(data): returns port and bytesencodeDownlink(input): returns fPort, bytes, errors, warnings
HTTP downlink path/api/v1/integration/http/<routing key>/api/v2/integration/http/<routing key>
Downlink dataHTTP: a JSON-encoded string. MQTT: an object. Its structure must match the V1 encoder.An object that your encoder turns into bytes
Device field in the downlinkHTTP: devEUI. MQTT: device.deviceEui

The default V1 encoder reads the Base64 payload from data.params.data and the port from data.params.port after the wrapper is parsed.

For HTTP V1, encode the converter input as a JSON string in data:

{
"devEUI": "0011223344556677",
"confirmed": false,
"msgId": "example-0001",
"data": "{\"params\":{\"data\":\"AQID\",\"port\":10}}"
}

For MQTT V1, publish an object:

{
"device": "0011223344556677",
"data": {"params": {"data": "AQID", "port": 10}}
}

V1 uplinks also differ by transport: HTTP carries payloadMetaData and a converter-defined payload. MQTT uses the device EUI as a key, with an array of timestamped ts and values objects.

For the V1 formats, see HTTP V1 Integration and MQTT V1 Integration. To move to V2, see Migrate from V1 to V2.