Skip to content

Cookie preferences

We use cookies for our own analytics, to see how our campaigns perform and, if you allow it, to load content from other services such as the Google site search. We never sell your data. Necessary cookies keep the site working and cannot be switched off. See our Cookie Policy for details and our Privacy Policy for how we handle personal data.

Security, load balancing and remembering your cookie choice.

Show us which pages people read, how they find the site and where they get stuck, so we can improve it (Google Analytics, Microsoft Clarity).

Show us which of our ad campaigns bring visitors to the site and remember the campaign or partner link you arrived from (Google Ads, LinkedIn, Meta, partner program). We do not use these cookies to build advertising profiles.

Load the site search from Google when you use it. Google sets its own cookies and shows ads in the search results.

© 2026 The ThingsBoard Authors
22.6k Try for free

ThingsBoard Cloud

Choose your data region

Your data stays in the region you choose, for residency and compliance. No credit card required.

Rather run it yourself? Install on your own servers

Particle Integration

Particle Integration receives events from Particle Device Cloud through a webhook. An uplink data converter transforms each event into device data, including telemetry and attributes. For downlink, ThingsBoard calls a cloud function on the device through the Particle Cloud API.

Use Particle Integration when:

  • Your devices run Particle Device OS and publish events with Particle.publish().
  • You need to call device functions (Particle.function()) from ThingsBoard, for example from a dashboard control.
  1. Publish an event. The device firmware calls Particle.publish().
  2. Forward the event. A Particle webhook that matches the event name sends it as an HTTP POST to the integration endpoint. The body holds the event name, data, publish time, and Device ID (coreid).
  3. Decode the payload. The uplink converter maps coreid to the device name and the event data to telemetry and attributes. If Allow create devices or assets is on, ThingsBoard creates the device on its first event.
  4. Call a device function (optional). The Rule Engine passes an RPC request to the integration. The downlink converter encodes it, and ThingsBoard calls POST https://api.particle.io/v1/devices/{deviceId}/{function}, which runs the matching Particle.function() on the device.
  • Access to ThingsBoard Cloud with integrations enabled for your tenant. The ThingsBoard endpoint must be reachable from the internet, because Particle Device Cloud calls it.
  • Permission to create integrations and data converters, and to edit rule chains for downlink.
  • A Particle Console account with at least one device that connects to Particle Device Cloud.
  • For downlink: the Particle CLI to create an access token.

Register the device and flash firmware that publishes a ThingsBoard event.

For a single development device, use Particle Device Setup. For a product fleet, use your existing provisioning and claiming process.

  1. Power the device and complete network setup. Wi-Fi devices can use setup.particle.io.
  2. Register or claim the device in your sandbox or product.
  3. Open Particle Console ⇾ Devices and check that the device is listed and online.
  4. Copy the Device ID. Webhooks send it as coreid, and this guide uses it as the ThingsBoard device name.

This guide publishes the event tb/telemetry. Webhooks match event names by prefix, so a webhook for tb/ also receives later events such as tb/status or tb/location.

Event names may contain letters, numbers, underscores, dashes, and slashes. Names that start with particle or spark are reserved.

The firmware below publishes example values every 30 seconds. Replace them with real sensor data.

#include "Particle.h"
SYSTEM_THREAD(ENABLED);
unsigned long lastPublishMs = 0;
const std::chrono::milliseconds publishPeriod = 30s;
void setup() {
}
void loop() {
if (Particle.connected() &&
millis() - lastPublishMs >= publishPeriod.count()) {
lastPublishMs = millis();
// Replace these values with data from your sensors/application.
Variant data;
data.set("deviceType", Variant("Particle device"));
data.set("temperature", Variant(23.5));
data.set("humidity", Variant(60));
data.set("battery", Variant(87));
Particle.publish("tb/telemetry", data);
}
}

Device OS 6.2 and later sends Variant data as CBOR, which is smaller over the air. Particle Device Cloud converts it back to JSON before it calls the webhook.

The webhook sends ThingsBoard a body like this. The event data arrives as a JSON string in data:

{
"event": "tb/telemetry",
"data": "{\"deviceType\":\"Particle device\",\"temperature\":23.5,\"humidity\":60,\"battery\":87}",
"coreid": "3c003c000f51373331333230",
"published_at": "2026-08-10T12:04:33.940Z"
}

Create the uplink converter and the integration, then point a Particle webhook at the integration endpoint.

The uplink converter parses the webhook body, then parses the event data inside it. Particle Integration uses the Generic converter: you write the decoder in TBEL or JavaScript. For converter types and the full decoder reference, see Uplink data converter.

The decoder in this guide maps:

  • coreid ⇾ device name.
  • deviceType from the event data ⇾ device profile. Default: Particle.
  • published_at ⇾ telemetry timestamp.
  • Other event data fields ⇾ telemetry.
  • coreid and the integration name ⇾ attributes particleDeviceId and integrationName.
  1. Go to Integrations ⇾ Data converters and click + Add data converter ⇾ Create new converter.

  2. Converter type — keep Uplink.

  3. Integration type — select Particle.

  4. Name — enter a name, for example Particle Uplink Converter.

  5. Main decoding configuration — the editor opens with the generic decoder template, which does not read the Particle webhook format. Replace it with the decoder below. The editor opens in TBEL; use the TBEL / JS toggle to switch to JavaScript.

    /** Decoder **/
    // Particle webhook body
    var data = decodeToJson(payload);
    // Particle event data must contain valid JSON.
    var eventData = decodeToJson(data.data);
    var deviceName = data.coreid;
    var deviceType = eventData.deviceType != null ? eventData.deviceType : "Particle";
    var groupName = "Particle devices";
    var timestamp = Date.now();
    if (data.published_at != null) {
    timestamp = new Date(data.published_at).getTime();

    To adapt:

    • Other telemetry — change the fields the firmware publishes. Every field not in excludeFromTelemetryList becomes telemetry; nested objects become dot-separated keys.
    • Device type — publish deviceType from the firmware, for example Photon 2 or Tracker One, or change the Particle default.
    • Attributes — add fields such as a serial number to attributes and to excludeFromTelemetryList.
    • Plain-text event data — skip the second parse and store the value directly, for example telemetry: { rawData: data.data }.
    • Several event types — branch on data.event, for example tb/telemetry and tb/status.
  6. Click Test decoder function and check the result (see Test the Decoder).

  7. Click Add.

Decoder Inputs

Variable Type Content
payload byte array The webhook body: event, data, coreid, and published_at.
metadata {[key: string]: string} integrationName, every request header as Header:<name>, and the key–value pairs from the integration’s Metadata field.

Test the Decoder

Click Test decoder function below the editor. Set Payload content type to JSON, replace the payload with the sample webhook body from Publish Events from Firmware, and click Test. With the default Metadata (integrationName = Test PARTICLE), the Output panel shows:

{
"deviceName": "3c003c000f51373331333230",
"deviceType": "Particle device",
"groupName": "Particle devices",
"attributes": {
"integrationName": "Test PARTICLE",
"particleDeviceId": "3c003c000f51373331333230"
},
"telemetry": {
"ts": 1786363473940,
"values": {
"temperature": 23.5,
"humidity": 60,
"battery": 87
}
}
}

Check that deviceName holds the Device ID and telemetry.values holds the expected keys. If the output is empty or shows an error, fix the decoder and test again.

  1. Go to Integrations ⇾ Integrations and click + Add integration.
  2. Basic settings:
    • Integration type — select Particle.
    • Name — keep the default Particle integration or enter your own.
    • Enable integration and Allow create devices or assets — keep both on, so the device is created on its first event.
    • Click Next.
  3. Uplink data converter:
    • Click Select existing and choose Particle Uplink Converter.
    • Alternatively, click Create new to write a decoder here.
    • Click Next.
  4. Downlink data converter:
  5. Connection:
    • Copy the HTTP endpoint URL. You need it for the Particle webhook.
    • Leave the other parameters at their defaults. See Connection Settings for details.
  6. Click Add.
Parameter Description
Base URL Address of your ThingsBoard server, used to build the endpoint URL. Example: https://thingsboard.cloud.
HTTP endpoint URL Read-only. Format: {Base URL}/api/v1/integrations/particle/{integrationKey}, where integrationKey is a UUID assigned at creation. Accepts JSON bodies only.
Allow downlink Lets the integration call Particle device functions. Off by default. When on, the Token field appears. See Configure Downlink.
Token Particle access token that ThingsBoard sends as Authorization: Bearer <token> to the Particle Cloud API. Required when Allow downlink is on.
Enable security Accepts only requests that carry the configured headers. See Secure the Endpoint with Header Filters.
Execute remotely Runs the integration as a separate process outside the ThingsBoard cluster. ThingsBoard generates an Integration key and Integration secret for it. Particle needs a public endpoint, so the standard setup keeps this off. See Remote Integration.
Metadata In Advanced settings. Key–value pairs added to the metadata of every message from this integration.

The webhook forwards matching events to the integration endpoint. Event name matching is a case-sensitive prefix: tb/ matches tb/telemetry, tb/status, and any other event that starts with tb/.

  1. Open Particle Console and select the sandbox, organization, or product that contains your device.
  2. In the left sidebar, open Cloud services and click Go to Integrations.
  3. Select Custom Webhook and click Start now.
  4. On the Webhook Builder tab, set:
    • Name — for example ThingsBoard.
    • Event name — tb/.
    • URL — the HTTP endpoint URL of the integration.
    • Request type — POST.
    • Request format — JSON.
    • Keep Status enabled.
  5. Click Enable integration.

Publish an event, then confirm that ThingsBoard decoded it and created the device.

Flash the firmware from Publish Events from Firmware and wait for the device to connect. It publishes tb/telemetry every 30 seconds. The device’s Events tab in Particle Console shows each published event.

To test without a running device, open the webhook’s View integration page in Particle Console and click Test. Enter your Device ID, put a JSON object in Event data, and click Run test:

{ "deviceType": "Particle device", "temperature": 23.5, "humidity": 60, "battery": 87 }
  • Integration events — go to Integrations ⇾ Integrations, open the integration, and click the Events tab. The uplink appears with status OK.
  • Converter events — open Particle Uplink Converter in Integrations ⇾ Data converters and click the Events tab. In shows the webhook body, Out shows the decoded result, and Metadata shows the request headers and integration name.
  • Device — go to Devices & assets ⇾ Devices. The integration has created a device named after the Device ID, in the Particle devices group. Open it and check the values on the Latest telemetry tab and particleDeviceId on the Attributes tab.

Anyone who knows the endpoint URL can send data to it. A header filter rejects every request that does not carry the required headers with the exact values, and returns 403 Forbidden before the converter runs. Particle logs the rejected call as a hook-error event.

  1. In Particle Console, edit the webhook and add a custom HTTP header, for example X-API-Key with a secret value.
  2. In ThingsBoard, open the integration and click Toggle edit mode (pencil icon).
  3. Turn on Enable security.
  4. Under Headers filter, click Add and enter the same Header and Value. A request must carry every header in the list. The value match is exact and case-sensitive.
  5. Click Apply changes.

ThingsBoard sends each downlink right away as a Particle Cloud API call. Nothing is queued: if the device is offline or the call fails, ThingsBoard logs an error and drops the command.

The downlink converter turns an RPC request from the Rule Engine into a function call. For the full encoder reference, see Downlink data converter.

ThingsBoard authenticates to the Particle Cloud API with an access token. The Call a function endpoint requires the devices.function:call scope.

For production, use a Particle API user limited to that scope. For a quick test, create a user token with the Particle CLI:

  1. Install the CLI, then close and reopen the terminal:

    Terminal window
    bash <( curl -sL https://particle.io/install-cli )
  2. Log in to your Particle account:

    Terminal window
    particle login
  3. Create a token that does not expire, and copy it. The CLI shows it only once.

    Terminal window
    particle token create --never-expires

The firmware below registers the function setOutput, which turns the D7 output on or off. Replace the pin and handler with your own control logic.

#include "Particle.h"
SYSTEM_THREAD(ENABLED);
int setOutput(String command);
void setup() {
pinMode(D7, OUTPUT);
digitalWrite(D7, LOW);
Particle.function("setOutput", setOutput);
}
void loop() {
}
int setOutput(String command) {
if (command == "on") {
digitalWrite(D7, HIGH);
return 1;
}
if (command == "off") {
digitalWrite(D7, LOW);
return 0;
}
return -1;
}

The function name must match the RPC method. A cloud function takes one string argument and should return quickly: start long operations and return a status code.

Add a downlink converter to the integration and turn on Allow downlink with the access token.

  1. Open the integration in Integrations ⇾ Integrations and click Toggle edit mode (pencil icon).
  2. In the Downlink data converter field, click Create new. The Downlink converter type and Particle integration type are preselected.
  3. Enter a name, for example Particle Downlink Converter.
  4. Main encoding configuration opens with a generic encoder that does not set the Device ID. Replace it with the encoder below. The same code runs in TBEL and JavaScript.
  5. To record downlink events, click the debug icon next to the name, select All messages, and click Apply.
  6. Click Add.
  7. Enable downlink: turn on Allow downlink and paste the token from Create a Particle Access Token into Token.
  8. Click Apply changes.

Encoder used in this guide:

/** Encoder **/
// The integration calls the Particle function named by "method"
// and passes "params" as its string argument.
// msg.params is serialized JSON, for example "\"on\"": JSON.parse returns on.
var result = {
contentType: "JSON",
data: JSON.stringify({
method: msg.method,
params: JSON.parse(msg.params)
}),
metadata: {
// Particle Device ID of the target device.
// This guide uses it as the ThingsBoard device name.
deviceId: metadata.deviceName
}
};
return result;

The integration reads these fields from the encoder result:

Field Required Description
metadata.deviceId Yes Particle Device ID used in the API URL. Without it, the downlink fails with Device id not found in metadata.
method or function in data Yes Name of the cloud function to call.
params, command, or arg in data No Function argument, sent as {"arg": "<value>"}. Numbers and booleans are converted to strings. A JSON object becomes an empty argument: to send it, pass msg.params as is, without JSON.parse.

Route RPC requests to the integration. Other message types have no method field, so the converter cannot turn them into function calls.

  1. Go to Data processing ⇾ Rule chains and open the Root Rule Chain.
  2. From the Action section, drag an integration downlink node onto the canvas.
  3. Enter a Name (for example, To Particle integration), select your Particle integration, and click Add.
  4. Connect the message type switch node to the integration downlink node with the RPC Request to Device relation.
  5. Click Apply changes.

Add a dashboard switch that calls setOutput with on or off.

  1. Open a dashboard, click Edit mode, then click + Add widget.
  2. In the Control widgets bundle, select Switch Control.
  3. On the Data tab, set Target device to Device and select the Particle device.
  4. On the Appearance tab:
    • Retrieve value using method — Don’t retrieve.
    • RPC set value method — setOutput.
    • Convert value function — return value ? "on" : "off";
  5. Click Add, save the dashboard, and exit edit mode.
  6. Toggle the switch.

Each toggle produces this call:

RPC method: setOutput, params: "on"
│
▼
POST https://api.particle.io/v1/devices/{deviceId}/setOutput
Authorization: Bearer <token>
{"arg": "on"}
│
▼
Particle.function("setOutput", ...) on the device
  • Device — the D7 output (on many boards, the blue LED) turns on or off.
  • Converter events — open the downlink converter’s Events tab. In shows the RPC request, and Out shows the encoded data and metadata.deviceId.
  • Integration events — open the integration’s Events tab. A failed call appears with status ERROR and the Particle API response.
Symptom Cause Fix
Webhook does not fire The event name does not start with the webhook’s Event name. Publish tb/telemetry with a tb/ webhook. Matching is case-sensitive.
Firmware publish fails The event name starts with the reserved particle or spark. Use a custom prefix such as tb/.
Particle shows hook-error Wrong endpoint URL, unreachable ThingsBoard, or a failed header filter (403). Copy the HTTP endpoint URL again. Check that ThingsBoard is reachable over HTTPS and that the webhook sends the filtered headers.
Device named api appears The event came from the CLI or Cloud API, not from a device. Test from the device or from the webhook’s Test dialog with a Device ID.
Device not created Allow create devices or assets is off, or coreid is missing. Turn the option on. Keep the default webhook fields.
Converter error on data The event data is plain text or invalid JSON. Publish valid JSON, or map data.data directly (see To adapt).
Telemetry saved as one string The decoder stores data without parsing it. Parse data.data as JSON and flatten the fields.
Downlink 401 or 403 The token is missing, expired, revoked, or lacks devices.function:call. Create a new token and paste it into Token.
Downlink 404 The device is offline, the function is not registered, or the device name is not the Device ID. Check that the device is online, that the RPC method matches the Particle.function() name, and that metadata.deviceId holds the Device ID.
No downlink and no error Allow downlink is off, no downlink converter is assigned, or the rule chain does not route RPC requests. Check the integration settings and the RPC Request to Device relation.
Device id not found in metadata The encoder does not set metadata.deviceId. Use the encoder from this guide.
Duplicate or out-of-order telemetry Particle delivers webhooks on a best-effort basis. Order data by published_at, and deduplicate where it matters.

To read debug events, open the integration or converter, click Events, and select an event: In is the received data, Out is the converter result, and Error holds the error text.