Click Select existing and choose the previously created uplink converter from the dropdown, then click Next.
+
Downlink data converter:
-
Click Skip — the downlink converter is only required for RPC and can be added later.
+
Click Skip — a downlink converter is only needed when ThingsBoard must send data back to the device (e.g., RPC commands or shared attribute updates). It can be configured later.
Connection:
Copy the HTTP endpoint URL — you will use it to send uplink messages.
-
In Advanced settings enable Replace response status from 'No-Content' to 'OK'.
+
In Advanced settings, enable Replace response status from "No-Content" to "OK" if your device or client requires a 200 OK response — by default the integration returns 204 No Content.
@@ -194,13 +222,13 @@ For request body `{"deviceName":"Thermometer A","deviceType":"thermostat","model
-#### Connection settings
+### Connection Settings
Base URL
@@ -223,7 +251,7 @@ When enabled, ThingsBoard validates each incoming request against a list of requ
| Field | Description |
|-------|-------------|
| **Header** | Name of the required HTTP header (e.g. `Authorization`, `X-API-Key`) |
-| **Secret** | Required value for that header (e.g. `Bearer my-token`) |
+| **Value** | Required value for that header (e.g. `Bearer my-token`) |
Multiple header filters can be added. All configured headers must be present in every request.
@@ -241,7 +269,7 @@ When enabled, ThingsBoard generates an **Integration key** and **Integration sec
Optional key–value pairs attached to the integration. These values are injected into every message processed by the integration and are accessible in converter scripts as `integrationMetadata`.
-## Send an uplink message
+## Send Test Uplink
Send a test message by running the command below, replacing `$YOUR_HTTP_ENDPOINT_URL` with the HTTP endpoint URL copied during setup.
@@ -259,11 +287,10 @@ Go to **Entities ⇾ Devices** — device *Thermometer A* is provisioned aut
{ src: '/src/assets/images/user-guide/integrations/http/http-integration-go-to-devices-1.png', alt: 'Entities → Devices (1): Thermometer A auto-created by the integration (2); Latest telemetry tab (3) shows temperature = 33', caption: 'Go to Entities → Devices (1) — Thermometer A is auto-created on the first uplink (2). Open Latest telemetry (3) to confirm temperature = 33' },
]} />
-
+## Validation and Debugging
-Go to **Integrations center ⇾ Integrations**, click **HTTP integration**, and open the **Events** tab. You should see one event with status "OK":
+Go to **Integrations center ⇾ Integrations**, click **HTTP integration**, and open the **Events** tab.
+You should see one event with status **OK**:
-Use Dashboards to visualize the received data. ThingsBoard provides **Solution Templates** with pre-built dashboards for common use cases.
+Use Dashboards to visualize the received data. ThingsBoard provides **Solution Templates** with pre-built dashboards for common use cases.
+
+## Secure HTTP Integration with Header Filters
-## Restrict access with a header filter
+A header filter protects the integration endpoint by requiring every incoming HTTP request to include one or more specific headers with exact values. Requests missing a required header or sending the wrong value are rejected with `401 Unauthorized` before reaching the converter.
-Require a specific HTTP header on every incoming request — requests without it are rejected.
+Use this to prevent unauthorized systems from pushing arbitrary data to your ThingsBoard endpoint.
-1. Open the HTTP integration, click **Toggle edit mode** (pencil icon, top right).
-2. Enable the **Enable security (Headers filter)** toggle, enter a header name (e.g. `test-header`) and value (e.g. `secret`), click **Add**, then click **Apply changes**.
+1. Open the HTTP integration and click **Toggle edit mode** (pencil icon, top right).
+2. Enable **Enable security (Headers filter)**.
+3. Click **Add** and enter the **Header** name and its expected **Value**, then click **Add**.
+4. Repeat to add more headers if needed — all configured headers must be present in every request.
+5. Click **Apply changes**.
-Once configured, add the required header to every uplink request with `-H "$HEADER:$VALUE"`.
+**Header filter fields:**
-Run the command below, replacing `$YOUR_HTTP_ENDPOINT_URL`, `$HEADER`, and `$VALUE` with your values:
+| Field | Description |
+|-------|-------------|
+| **Header** | HTTP header name ThingsBoard checks on each incoming request |
+| **Value** | Exact value required in that header |
+
+**Example: Authorization header**
+
+A common pattern is to protect the endpoint with a bearer token. Set **Header** to `Authorization` and **Value** to `Bearer my-secret-token`, then include the header in every uplink request. Replace `$YOUR_HTTP_ENDPOINT_URL` with the HTTP endpoint URL copied during setup:
```bash
-curl -v -X POST -d '{"deviceName":"Thermometer A","deviceType":"thermostat","temperature":33,"model":"N001"}' $YOUR_HTTP_ENDPOINT_URL -H "Content-Type:application/json" -H "$HEADER:$VALUE"
+curl -v -X POST \
+ -d '{"deviceName":"Thermometer A","deviceType":"thermostat","temperature":33,"model":"N001"}' \
+ $YOUR_HTTP_ENDPOINT_URL \
+ -H "Content-Type: application/json" \
+ -H "Authorization: Bearer my-secret-token"
```
-## Configure downlink
-
-The downlink converter (encoder) transforms a Rule Engine message into the HTTP response body returned to the device. For the full encoder function reference, see Downlink data converter.
+Any request without the correct `Authorization` header is rejected.
-HTTP downlinks are not pushed — they are delivered as the response body to the device's **next uplink request**. When a downlink is queued, the integration returns `200 OK` with the encoded payload instead of `204 No Content`.
+## Configure Downlink
-The encoder function receives `msg`, `metadata`, and `msgType`, and must return an object with:
-- `contentType` — `JSON`, `TEXT`, or `BINARY` (`BINARY` expects a Base64-encoded string)
-- `data` — the response body string
-- `metadata` — optional key-value pairs
+HTTP downlinks are not pushed to the device — they are delivered as the response body to the device's **next uplink request**. When a downlink is queued, the integration returns `200 OK` with the encoded payload instead of `204 No Content`.
-
+The downlink converter transforms a Rule Engine message into the HTTP response body. For the full encoder function reference, see Downlink data converter.
-### Add a downlink converter
+### Add Downlink Converter
- 1. Go to **Integrations center ⇾ Integrations** and open the HTTP Integration.
+ 1. Go to **Integrations center ⇾ Integrations** and open the HTTP integration.
2. Click **Toggle edit mode**.
3. In the **Downlink data converter** field, click **Create new**.
- 4. In the **Add data converter** dialog, enter a name, and write or paste the encoder script.
+ 4. Enter a name and paste the encoder script below, then click **Add**.
-
-
-```js maxLines=15 collapsible
-/** Encoder **/
-
-var result = {
- contentType: "JSON", // JSON, TEXT, or BINARY (base64)
- data: JSON.stringify(msg), // encode the full message as the response body
- metadata: {}
-};
-
-return result;
-```
-
-
-```js maxLines=15 collapsible
+```js
/** Encoder **/
var result = {
@@ -360,11 +381,11 @@ var result = {
return result;
```
-
-
- 5. Click **Add**, then click **Apply changes**.
+
+
Click Apply changes.
+
-### Configure the Root Rule Chain
+### Configure Root Rule Chain
@@ -386,7 +407,7 @@ import ConfigureDownlinkRuleChain from '@includes/docs/user-guide/integrations/_
{ src: '/src/assets/images/user-guide/integrations/http/http-integration-configure-rule-chain-3.png', alt: 'Rule chain with integration downlink node connected to Attributes Updated output', caption: 'Connect the node to the Attributes Updated / Post attributes output and click Apply changes' },
]} />
-### Test the downlink
+### Test Downlink
When a shared attribute is created or updated, the Rule Engine routes the event to the integration, which queues the encoded payload as the response to the device's next uplink.
@@ -408,7 +429,7 @@ Send the uplink message again. ThingsBoard returns the downlink payload in the H
{ src: '/src/assets/images/user-guide/integrations/http/http-send-downlink-message-3.png', alt: 'Terminal — HTTP/2 200 response with {"powerState":"on"} body', caption: 'Response body contains the downlink payload: {"powerState":"on"}' },
]} />
-The sent and received data can be viewed in the downlink converter's **Events** tab — the **In** block shows the input data, the **Out** block shows the encoded message sent to the device, and **Metadata** shows the request headers:
+To inspect the exchange, open the downlink converter's **Events** tab — **In** shows the Rule Engine message, **Out** shows the encoded response, **Metadata** shows the request headers.
-## See also
+## Troubleshooting
+
+**No telemetry or device after sending a request**
+
+Open the converter's **Events** tab: go to **Integrations center → Data converters**, click your converter, and open **Events**. If **Out** is empty or shows an error, the script failed. Check the **In** column first to confirm the payload you expected was received.
+
+**Common issues:**
+
+| Symptom | Likely cause | Fix |
+|---------|-------------|-----|
+| Telemetry missing in ThingsBoard | Wrong field path in the script | Check **Out** in converter events; verify `data.yourField` matches the actual JSON key |
+| Device not created, `deviceName` is null | Field doesn't exist or has a different name | Add a fallback: `var deviceName = data.id \|\| 'Unknown';` |
+| Script error in converter events | Accessing a field on a `null` parent | Add a null-check: `data.sensor ? data.sensor.temp : null` |
+| Device not auto-created despite correct converter output | **Allow create devices or assets** is disabled | Enable it in the integration settings |
+| Unexpected key names in ThingsBoard | Output key name differs from expected | Field names in `attributes`/`telemetry` blocks become the ThingsBoard keys exactly as written |
+
+**Converter not triggered at all**
+
+- Check the integration **Events** tab — `ERROR` status means the request was rejected (e.g., failed header filter, malformed body).
+- No events at all: verify the `POST` is going to the exact endpoint URL copied from the integration **Connection** step.
+- Confirm the integration is enabled — the toggle must be on in integration settings.
+
+## See Also
- Integration overview
- Uplink data converter
diff --git a/src/content/_includes/docs/user-guide/integrations/uplink-data-converter.mdx b/src/content/_includes/docs/user-guide/integrations/uplink-data-converter.mdx
index 88de00cc4c..929276edc3 100644
--- a/src/content/_includes/docs/user-guide/integrations/uplink-data-converter.mdx
+++ b/src/content/_includes/docs/user-guide/integrations/uplink-data-converter.mdx
@@ -12,6 +12,30 @@ import TabItem from '@components/TabItem.astro';
The **Uplink data converter** is the decoding stage of every **ThingsBoard integration**, where raw payloads from an external device or network server are mapped to the ThingsBoard data model: device or asset name, profile, customer, group, telemetry values, and attributes.
+Without an uplink converter, ThingsBoard cannot understand how external HTTP payloads should be interpreted and processed internally.
+
+Example:
+
+Incoming HTTP payload:
+
+```json
+{
+ "device": "Boiler-01",
+ "temperature": 42
+}
+```
+
+Converter output:
+
+```json
+{
+ "deviceName": "Boiler-01",
+ "telemetry": {
+ "temperature": 42
+ }
+}
+```
+
ThingsBoard provides three ways to define the decoder:
- **Typed:** Configure entity type, name patterns, and field mappings in the UI — ThingsBoard pre-fills a decoder script tailored to each integration type. No scripting needed for structured JSON payloads; for binary or custom-encoded payloads, edit the pre-filled decoder to match your device's payload format.
Supported integrations: ChirpStack, Loriot, The Things Stack Community, The Things Stack Industries, ThingPark, and ThingPark Enterprise.
@@ -117,6 +141,98 @@ Keys added to the **Update only keys list** in **Advanced decoding parameters**
In a cluster deployment, keys in the Update only keys list may still be written more than once when uplink messages arrive at different executor nodes, or immediately after a converter configuration change.
+### Common Scripting Patterns
+
+The patterns below apply to any generic uplink converter, regardless of integration type.
+
+**Device name from a different field**
+
+Replace the field reference to match whatever field carries the device identifier in your payload:
+
+```js
+var deviceName = data.serial; // if your field is "serial"
+var deviceName = data.id; // if your field is "id"
+var deviceName = 'Gateway-01'; // hardcoded — all data goes to one device
+```
+
+**Hardcoded device type**
+
+If all devices share the same profile, use a string literal instead of reading it from the payload:
+
+```js
+var deviceType = 'thermostat';
+```
+
+**Rename a field**
+
+Map a source field to a different ThingsBoard key using `newName: data.originalField`:
+
+```js
+attributes: {
+ serialNumber: data.param2, // renames param2 → serialNumber
+ firmwareVersion: data.fw, // renames fw → firmwareVersion
+}
+```
+
+**Extract nested values**
+
+If your payload contains nested objects, access them with dot notation:
+
+```json
+{ "sensor": { "temperature": 22.5, "humidity": 60 } }
+```
+
+```js
+telemetry: {
+ temperature: data.sensor.temperature,
+ humidity: data.sensor.humidity
+}
+```
+
+**Separate telemetry from attributes**
+
+Put values that change over time in `telemetry`, and device metadata in `attributes`:
+
+```js
+attributes: {
+ firmware: data.fw, // rarely changes — store as attribute
+ model: data.model
+},
+telemetry: {
+ temperature: data.temp, // changes over time — store as telemetry
+ battery: data.bat,
+ rssi: data.signal
+}
+```
+
+**Normalize or transform values**
+
+Transform values inside the decoder before mapping them:
+
+```js
+telemetry: {
+ temperature: data.tempC * 9/5 + 32, // Celsius → Fahrenheit
+ batteryPercent: Math.round(data.bat * 100) // 0–1 float → 0–100 integer
+}
+```
+
+**Non-JSON payload**
+
+If the device sends plain text or CSV, decode the payload as a string and parse manually:
+
+```js
+// Example: "Sensor-01,22.5,60"
+var str = decodeToString(payload);
+var parts = str.split(',');
+var result = {
+ deviceName: parts[0],
+ telemetry: {
+ temperature: parseFloat(parts[1]),
+ humidity: parseFloat(parts[2])
+ }
+};
+```
+
## Typed Uplink Converter
Available from **ThingsBoard 4.0**. Configure the entity type, name pattern, and key mappings in the UI — ThingsBoard pre-fills a decoder script for the selected integration type. For structured JSON payloads, no script changes are needed. For binary payloads, modify the pre-filled decoder to match your device's payload format.