Skip to content
Stand with Ukraine flag

Python REST Client

The ThingsBoard Python REST Client wraps the REST API and is auto-generated from the OpenAPI spec — every REST endpoint has a typed method. Edition-specific packages ensure type-safe access to the right endpoints for your tenant.

Install the edition-specific package:

Terminal window
pip install tb-paas-client==4.3.1.2

Snippets below import models from tb_paas_client.models and exceptions from tb_paas_client.exceptions. Each snippet is self-contained — open it inside a with ThingsboardClient(...) as client: block, replace placeholders like YOUR_API_KEY_VALUE and YOUR_DEVICE_ID with real values, and run it. The client is synchronous and not thread-safe — create one instance per worker.

End-to-end: authenticate with an API key, create a device, push a telemetry value, then clean up.

import json
from tb_paas_client import ThingsboardClient
from tb_paas_client.models import Device
with ThingsboardClient("https://thingsboard.cloud", api_key="YOUR_API_KEY_VALUE") as client:
saved = client.save_device(Device(name="Quickstart Device", type="default"))
device_id = str(saved.id.id)
client.save_entity_telemetry(
entity_type="DEVICE",
entity_id=device_id,
scope="ANY",
body=json.dumps({"temperature": 22.4}),
)
print(f"Pushed telemetry to {saved.name}")
client.delete_device(device_id=device_id)

ThingsboardClient authenticates eagerly on construction. The client is a context manager — using it inside with releases the underlying connection pool on exit. JWT tokens refresh automatically; the client re-logs in transparently if the refresh token expires.

from tb_paas_client import ThingsboardClient
with ThingsboardClient("https://thingsboard.cloud", api_key="YOUR_API_KEY_VALUE") as client:
print(f"Logged in as {client.get_user().email}")
from tb_paas_client import ThingsboardClient
with ThingsboardClient(
"https://thingsboard.cloud",
username="tenant@thingsboard.org",
password="tenant",
) as client:
print(f"Logged in as {client.get_user().email}")

The client retries 429 Too Many Requests responses with exponential backoff by default. Tune via constructor keyword arguments (defaults shown below), or pass retry_on_rate_limit=False to disable:

from tb_paas_client import ThingsboardClient
client = ThingsboardClient(
"https://thingsboard.cloud",
api_key="YOUR_API_KEY_VALUE",
max_retries=3, # default 3
initial_retry_delay_ms=1_000, # default 1 s
max_retry_delay_ms=30_000, # default 30 s
)

Every entity type — devices, assets, dashboards, customers, alarms — follows the same method-naming pattern: save_<entity>, get_<entity>_by_id, get_<entity>_info_by_id, delete_<entity>. Required fields differ per type; see the REST API reference for each model. The walkthrough below uses devices. To update an existing entity, mutate the model and call save_<entity> again.

from tb_paas_client import ThingsboardClient
from tb_paas_client.models import Device
with ThingsboardClient("https://thingsboard.cloud", api_key="YOUR_API_KEY_VALUE") as client:
new_device = Device(name="Test Device", type="default")
saved = client.save_device(new_device)
device_id = str(saved.id.id) # saved.id is EntityId wrapper, .id is the UUID
fetched = client.get_device_by_id(device_id=device_id)
print("Fetched:", fetched.name)
client.delete_device(device_id=device_id)

Both save_entity_telemetry(entity_type, entity_id, scope, body) and save_entity_attributes_v2(entity_type, entity_id, scope, body) take a JSON string as body.

import json
from tb_paas_client import ThingsboardClient
with ThingsboardClient("https://thingsboard.cloud", api_key="YOUR_API_KEY_VALUE") as client:
device_id = "YOUR_DEVICE_ID"
client.save_entity_telemetry(
entity_type="DEVICE",
entity_id=device_id,
scope="ANY", # required by URL path; server-ignored for telemetry
body=json.dumps({"temperature": 26.5, "humidity": 87}),
)

This example uses an asset with a deviceCount attribute; the same calls work for any entity type — substitute "DEVICE" / device_id for a device.

import json
from tb_paas_client import ThingsboardClient
with ThingsboardClient("https://thingsboard.cloud", api_key="YOUR_API_KEY_VALUE") as client:
asset_id = "YOUR_ASSET_ID"
attrs = client.get_attributes_by_scope(
entity_type="ASSET",
entity_id=asset_id,
scope="SERVER_SCOPE",
keys="deviceCount", # comma-separated; pass "k1,k2,k3" for multiple
)
current = int(attrs[0].value) if attrs else 0
updated = current + 1
client.save_entity_attributes_v2(
entity_type="ASSET",
entity_id=asset_id,
scope="SERVER_SCOPE",
body=json.dumps({"deviceCount": updated}),
)
from tb_paas_client import ThingsboardClient
with ThingsboardClient("https://thingsboard.cloud", api_key="YOUR_API_KEY_VALUE") as client:
page = 0 # pages are zero-indexed
while True:
devices = client.get_tenant_devices(page_size=100, page=page)
for device in devices.data:
print(device.name, str(device.id.id))
if not devices.has_next:
break
page += 1

For server-side filtering on attribute or telemetry values, use the Entity Data Query API. The example below counts all devices, then counts only the active ones:

from tb_paas_client import ThingsboardClient
from tb_paas_client.models import (
EntityCountQuery, EntityTypeFilter, KeyFilter, EntityKey,
BooleanFilterPredicate, FilterPredicateValueBoolean,
)
with ThingsboardClient("https://thingsboard.cloud", api_key="YOUR_API_KEY_VALUE") as client:
type_filter = EntityTypeFilter(entity_type="DEVICE")
total = client.count_entities_by_query(
EntityCountQuery(entity_filter=type_filter)
)
print("Total devices:", total)
active_filter = KeyFilter(
key=EntityKey(type="ATTRIBUTE", key="active"),
value_type="BOOLEAN",
predicate=BooleanFilterPredicate(
operation="EQUAL",
value=FilterPredicateValueBoolean(default_value=True),
),
)
active = client.count_entities_by_query(
EntityCountQuery(entity_filter=type_filter, key_filters=[active_filter])
)
print("Active devices:", active)

For a paginated list of matching entities (not just a count), build an EntityDataQuery with an EntityDataPageLink and call client.find_entity_data_by_query(query). See the tb-examples.md catalog for full examples.

Entity groups and permissions

Section titled Entity groups and permissions

Create and populate a group

Section titled Create and populate a group
from tb_paas_client import ThingsboardClient
from tb_paas_client.models import EntityGroup
with ThingsboardClient("https://thingsboard.cloud", api_key="YOUR_API_KEY_VALUE") as client:
device_group = EntityGroup(name="Acme Devices", type="DEVICE")
saved_group = client.save_entity_group(entity_group=device_group)
device_group_id = str(saved_group.id.id)
# add_entities_to_entity_group takes a list of raw UUID strings
client.add_entities_to_entity_group(
entity_group_id=device_group_id,
request_body=["YOUR_DEVICE_ID"],
)
Create a role, look up the customer's auto-generated "All" user group, then bind them via `share_entity_group_to_child_owner_user_group`:
from tb_paas_client import ThingsboardClient
from tb_paas_client.models import Role
with ThingsboardClient("https://thingsboard.cloud", api_key="YOUR_API_KEY_VALUE") as client:
customer_id = "YOUR_CUSTOMER_ID"
device_group_id = "YOUR_DEVICE_GROUP_ID"
role = Role(name="Acme Device Readers", type="GROUP")
saved_role = client.save_role(role=role)
role_id = str(saved_role.id.id)
all_users = client.get_entity_group_all_by_owner_and_type(
owner_type="CUSTOMER",
owner_id=customer_id,
group_type="USER",
)
user_group_id = str(all_users.id.id)
client.share_entity_group_to_child_owner_user_group(
entity_group_id=device_group_id,
user_group_id=user_group_id,
role_id=role_id,
)

The client raises ApiException for non-2xx responses, with HTTP-status-specific subclasses (NotFoundException for 404, UnauthorizedException for 401, etc.). e.body is the raw response body (typically JSON for 4xx, may be empty for 5xx).

  • 401 Unauthorized — JWT auth auto-refreshes tokens and re-logs in using stored credentials, so you’ll only see this if credentials become invalid.
  • 429 Too Many Requests — already retried with exponential backoff by default (see Rate-limit handling). You only observe a 429 if retries are exhausted or disabled.
  • 404 Not Found — the common case worth catching explicitly:
from tb_paas_client import ThingsboardClient
from tb_paas_client.exceptions import ApiException, NotFoundException
with ThingsboardClient("https://thingsboard.cloud", api_key="YOUR_API_KEY_VALUE") as client:
try:
device = client.get_device_by_id(device_id="nonexistent-id")
except NotFoundException:
print("Device not found")
except ApiException as e:
print(f"API error {e.status}: {e.body}")

The tb-examples.md catalog in the repository covers additional entities (assets, dashboards, customers), alarms, relations, and Entity Data Query examples with pagination and sort orders.