Skip to content

Reference

Events

Subscribe to the realtime events of your Thinger.io account over a WebSocket, with the catalog of events, their filters and the permissions each one needs.

Reference11 min read

Thinger.io emits an event whenever something happens in your account: a device connects, a record reaches a Data Bucket, an alarm fires. Open a WebSocket to receive the events you subscribe to as they happen, to keep a dashboard, an app or an integration current without polling.

Connect ​

Open a WebSocket to the events endpoint of your account:

text
wss://YOUR_SERVER/v2/users/YOUR_USER/events?authorization=YOUR_TOKEN

YOUR_SERVER is iot.thinger.io on the free Cloud account, or your own domain on a private instance. Here YOUR_TOKEN is an access token of your account, or the session token of the console. The REST reference lists the endpoint as GET /v2/users/{user}/events.

Query parameterRequiredContent
authorizationYes, unless the token travels in an Authorization: Bearer header or an authorization cookieThe token. Browsers cannot set headers on a WebSocket, so they pass it here.
projectNoA project ID. The connection works inside that project: for project members, and for access tokens bound to projects, which must use it.

The server refuses the connection with 401 when the token is not valid or has expired, and with 403 when the token cannot subscribe to events of that account or project.

One connection carries any number of subscriptions. You send JSON messages to subscribe and unsubscribe; the server answers each one, and then sends the matching events.

Subscribe ​

Send a register message with the event name and its filters:

json
{
  "action": "register",
  "event": "device_state_change",
  "filters": { "device": "YOUR_DEVICE" }
}
FieldContent
actionregister.
eventAn event name from the catalog.
filtersFields of the event and the values to match, for example { "device": "YOUR_DEVICE", "state": "connected" }. Always send it; use {} to receive every event of that name. See Filters.
paramsOptional. { "interval": <milliseconds> } limits how often stream data events (such as device_resource_stream with signal data) reach this subscription.
updateOptional. true replaces the filters and params of an existing subscription with the same filters on this connection, instead of adding another one.

The server answers with success and the message it received in request. registered maps the event name to the ID of the new subscription:

json
{
  "success": true,
  "request": {
    "action": "register",
    "event": "device_state_change",
    "filters": { "device": "YOUR_DEVICE" }
  },
  "registered": { "device_state_change": 3 }
}

Unsubscribe ​

Send unregister with the event name. With filters, only the subscriptions with those same filters are removed; without them, every subscription of this connection to that event:

json
{
  "action": "unregister",
  "event": "device_state_change",
  "filters": { "device": "YOUR_DEVICE" }
}
json
{
  "success": true,
  "request": { "action": "unregister", "event": "device_state_change", "filters": { "device": "YOUR_DEVICE" } },
  "unregistered": { "device_state_change": 3 }
}

To remove every subscription of the connection, send clear. The answer lists what was removed, also under unregistered:

json
{ "action": "clear" }
json
{
  "success": true,
  "request": { "action": "clear" },
  "unregistered": { "device_state_change": [3], "bucket_write": [4] }
}

Errors ​

A refused message gets success: false and a message:

json
{
  "success": false,
  "request": { "action": "register", "event": "bucket_write", "filters": { "bucket": "climate" } },
  "message": "action not allowed"
}
messageCause
invalid JSON inputThe message is not valid JSON (request is null).
required a JSON objectThe message is JSON, but not an object.
invalid actionaction is not register, unregister or clear.
invalid event nameevent is missing or empty.
requested event name cannot be mapped to permissionsThe token or project member subscribes to an event that is not in the permissions table, including unknown event names.
not enabled, no actions allowed, action not allowedThe token or project member lacks the permission the event needs.
subscriptions over a project require a '…' filterInside a project, the event needs a device, bucket or rule filter.
the '…' filter must be a resource identifier, or several separated by '|'Inside a project, the filter is not a plain resource ID.
… '…' does not belong to the projectInside a project, the device, bucket or rule of the filter is not in the project, or not in the member's groups.

When the account owner subscribes to an event name that does not exist, the answer is success: false with registered: null and no message.

Event messages ​

Each event arrives as one JSON message: the fields of the event, plus event, ts (milliseconds since the epoch) and user. For example, a device_state_change:

json
{
  "device": "YOUR_DEVICE",
  "state": "connected",
  "event": "device_state_change",
  "ts": 1760700000000,
  "user": "YOUR_USER"
}

Lifecycle events (device_create, bucket_update…) carry the document of the resource; _delete events carry its ID. Events of the Server administrator scope do not carry user.

Filters ​

Filter values are regular expressions that must match the whole value of the field: "device": "sensor_.*" matches every device whose ID starts with sensor_. An event without the filtered field does not match. When the field is a list, the event matches if any element does.

Escape the regular expression characters \ ^ $ . | ? * + ( ) [ ] { } of a literal ID: a filter "device": "sensor.1" also matches sensor_1. Inside a project, filters take only plain resource IDs, or several joined with | ("device": "sensor_1|sensor_2").

Permissions ​

What a connection can subscribe to depends on its token:

ConnectionCan subscribe to
The account owner, with the console session tokenEvery event of the Account scope. Events of the Server administrator scope need a server administrator.
An access tokenOnly the events below, with the permission each one needs.
A project member, or an access token with projectOnly the events below, with the member's permissions (and the token's, for a member's token), and the filter they require inside the project.
EventPermissionFilter required inside a project
bucket_writeBucket:ReadBucket on the bucket of the bucket filter, or Device:ReadDeviceBucket on the device of the device filterdevice or bucket
device_property_updateDevice:ReadDeviceProperty on the device of the device filterdevice
device_state_changeDevice:ReadDeviceConfig on the device of the device filterdevice
alarm_instance_activate, alarm_instance_normalize, alarm_instance_create, alarm_instance_update, alarm_instance_deleteAlarm:ListAlarmInstances on all alarms (*)None: the events are limited to the project
alarm_rule_executeAlarm:ListAlarmRules on all alarm rules (*)rule

A permission on one resource needs the matching filter: bucket_write with Bucket:ReadBucket on the bucket climate works with "filters": { "bucket": "climate" }, not with {}. Access tokens and their permissions are managed in Access Tokens.

Catalog ​

The public catalog GET /v1/server/events returns the name, filter fields and scope of every event the server can send. It needs no token and is not a stream: read it to discover the events and their filter values.

This is the catalog of Thinger.io 7.4. It lists 123 events: 24 activity events and the lifecycle events of 33 resource types.

Scope says who receives the event: Account events belong to the account that subscribes; Server administrator events are about the whole server and need a server administrator.

Activity events ​

Values lists the values a filter field takes. Each one is described in Activity events in detail.

EventFires whenFiltersValuesScope
alarm_instance_activateAn alarm instance becomes active.instanceAccount
alarm_instance_normalizeThe condition of an active alarm instance returns to normal.instanceAccount
alarm_rule_executeAn alarm rule is evaluated.ruleAccount
bucket_export_completedAn export of a Data Bucket finishes and its file is ready.bucket, fileAccount
bucket_export_failedAn export of a Data Bucket fails.bucket, fileAccount
bucket_export_startedAn export of a Data Bucket starts.bucket, fileAccount
bucket_writeA record is written to a Data Bucket.bucketAccount
claim_completedA device is claimed.claimAccount
device_authentication_failedA device tries to connect with wrong credentials.deviceAccount
device_callback_callAn HTTP device sends data to its callback.device, productAccount
device_geofence_eventA device enters or leaves a geofence, or stays inside or outside it.device, geofence, geofence_event, productgeofence_event: onEnter, onExit, whileInside, whileOutsideAccount
device_location_updateThe location of a device changes.device, productAccount
device_resource_request_failedA call to a device resource fails.device, product, resourceAccount
device_resource_streamA stream of a device resource starts, stops, sends data or fails.device, product, resource, signalsignal: start, stop, data, errorAccount
device_state_changeA device connects, disconnects, resumes, wakes up or goes to sleep.device, product, statestate: connected, disconnected, resumed, awake, asleepAccount
device_stats_dataThe connection statistics of a connected device change (traffic, connection time).device, productAccount
device_topic_publishAn MQTT device publishes to a topic.device, product, topicAccount
device_topic_subscribeAn MQTT device subscribes to a topic.device, product, topicAccount
device_topic_unsubscribeAn MQTT device unsubscribes from a topic.device, product, topicAccount
endpoint_callAn endpoint is called.endpoint, typetype: email, http_request, virtualAccount
endpoint_call_responseAn endpoint call finishes, successfully or not.endpoint, type, status, status_codetype: email, http_request, virtual
status: success, failure
Account
plugin_actionA plugin is started, stopped, upgraded or changes its state.plugin, actionaction: start, restart, pause, unpause, stop, kill, create, upgrade, remove, public, privateAccount
product_script_logA script of a product writes to its log.productAccount
product_streamData is sent to a stream of a product.product, streamAccount

Lifecycle events ​

Each resource type emits <type>_create, <type>_update and <type>_delete when a resource of that type is created, changed or deleted. Their filters are the IDs of the resource.

Resource typeEventsFiltersScope
alarm_instancealarm_instance_create, alarm_instance_update, alarm_instance_deleteinstanceAccount
alarm_rulealarm_rule_create, alarm_rule_update, alarm_rule_deleteruleAccount
brandbrand_create, brand_update, brand_deletebrandServer administrator
bucketbucket_create, bucket_update, bucket_deletebucketAccount
claimclaim_create, claim_update, claim_deleteclaimAccount
dashboarddashboard_create, dashboard_update, dashboard_deletedashboardAccount
devicedevice_create, device_update, device_deletedeviceAccount
device_bucketdevice_bucket_create, device_bucket_update, device_bucket_deletedevice, bucketAccount
device_propertydevice_property_create, device_property_update, device_property_deletedevice, propertyAccount
domaindomain_create, domain_update, domain_deletedomainServer administrator
endpointendpoint_create, endpoint_update, endpoint_deleteendpointAccount
groupgroup_create, group_update, group_deletegroupAccount
group_propertygroup_property_create, group_property_update, group_property_deletegroup, propertyAccount
hosthost_create, host_update, host_deletehostServer administrator
identity_provideridentity_provider_create, identity_provider_update, identity_provider_deleteidentity_providerServer administrator
oauth_clientoauth_client_create, oauth_client_update, oauth_client_deleteoauth_clientServer administrator
plugin_propertyplugin_property_create, plugin_property_update, plugin_property_deleteplugin, propertyAccount
productproduct_create, product_update, product_deleteproductAccount
product_propertyproduct_property_create, product_property_update, product_property_deleteproduct, propertyAccount
projectproject_create, project_update, project_deleteprojectAccount
project_memberproject_member_create, project_member_update, project_member_deleteproject, memberAccount
project_propertyproject_property_create, project_property_update, project_property_deleteproject, propertyAccount
project_roleproject_role_create, project_role_update, project_role_deleteproject, roleAccount
propertyproperty_create, property_update, property_deletepropertyAccount
proxyproxy_create, proxy_update, proxy_deleteproxyServer administrator
rolerole_create, role_update, role_deleteroleAccount
storagestorage_create, storage_update, storage_deletestorageAccount
syncsync_create, sync_update, sync_deletesyncAccount
sync_locksync_lock_create, sync_lock_update, sync_lock_deletesync, lockAccount
tokentoken_create, token_update, token_deletetokenAccount
typetype_create, type_update, type_deletetypeAccount
type_propertytype_property_create, type_property_update, type_property_deletetype, propertyAccount
useruser_create, user_update, user_deleteuserServer administrator

Activity events in detail ​

alarm_instance_activate ​

An alarm instance becomes active.

Filters: instance.

alarm_instance_normalize ​

The condition of an active alarm instance returns to normal.

Filters: instance.

alarm_rule_execute ​

An alarm rule is evaluated.

Filters: rule.

bucket_export_completed ​

An export of a Data Bucket finishes and its file is ready.

Filters: bucket, file.

bucket_export_failed ​

An export of a Data Bucket fails.

Filters: bucket, file.

bucket_export_started ​

An export of a Data Bucket starts.

Filters: bucket, file.

bucket_write ​

A record is written to a Data Bucket.

Filters: bucket.

claim_completed ​

A device is claimed.

Filters: claim.

device_authentication_failed ​

A device tries to connect with wrong credentials.

Filters: device.

device_callback_call ​

An HTTP device sends data to its callback.

Filters: device, product.

device_geofence_event ​

A device enters or leaves a geofence, or stays inside or outside it.

Filters: device, geofence, geofence_event, product.

Values of geofence_event: onEnter, onExit, whileInside, whileOutside.

device_location_update ​

The location of a device changes.

Filters: device, product.

device_resource_request_failed ​

A call to a device resource fails.

Filters: device, product, resource.

device_resource_stream ​

A stream of a device resource starts, stops, sends data or fails.

Filters: device, product, resource, signal.

Values of signal: start, stop, data, error.

device_state_change ​

A device connects, disconnects, resumes, wakes up or goes to sleep.

Filters: device, product, state.

Values of state: connected, disconnected, resumed, awake, asleep.

device_stats_data ​

The connection statistics of a connected device change (traffic, connection time).

Filters: device, product.

device_topic_publish ​

An MQTT device publishes to a topic.

Filters: device, product, topic.

device_topic_subscribe ​

An MQTT device subscribes to a topic.

Filters: device, product, topic.

device_topic_unsubscribe ​

An MQTT device unsubscribes from a topic.

Filters: device, product, topic.

endpoint_call ​

An endpoint is called.

Filters: endpoint, type.

Values of type: email, http_request, virtual.

endpoint_call_response ​

An endpoint call finishes, successfully or not.

Filters: endpoint, type, status, status_code.

Values of type: email, http_request, virtual.

Values of status: success, failure.

plugin_action ​

A plugin is started, stopped, upgraded or changes its state.

Filters: plugin, action.

Values of action: start, restart, pause, unpause, stop, kill, create, upgrade, remove, public, private.

product_script_log ​

A script of a product writes to its log.

Filters: product.

product_stream ​

Data is sent to a stream of a product.

Filters: product, stream.

Reconnect ​

The server does not keep events for disconnected clients: events emitted while the socket is closed are lost, and the subscriptions end with the connection. After a reconnection, send the register messages again and read the current state (device status, last bucket records) through the REST API to fill the gap.

The server sends a WebSocket ping after 60 seconds without messages from the client and closes the connection if the client does not answer. Standard WebSocket clients answer pings on their own.

Examples ​

YOUR_USER is your username and YOUR_DEVICE the ID of one of your devices.

js
const url = 'wss://YOUR_SERVER/v2/users/YOUR_USER/events?authorization=YOUR_TOKEN';

function connect() {
  const ws = new WebSocket(url);
  ws.onopen = () => {
    ws.send(JSON.stringify({
      action: 'register',
      event: 'device_state_change',
      filters: { device: 'YOUR_DEVICE' },
    }));
  };
  ws.onmessage = (message) => {
    const data = JSON.parse(message.data);
    if ('success' in data) {
      if (!data.success) console.error('Refused:', data.message ?? data);
      return;
    }
    console.log(`${data.device} is ${data.state}`);
  };
  // Subscriptions end with the connection: connect and register again
  ws.onclose = () => setTimeout(connect, 5000);
}

connect();
bash
echo '{"action":"register","event":"device_state_change","filters":{"device":"YOUR_DEVICE"}}' \
  | websocat -n "wss://YOUR_SERVER/v2/users/YOUR_USER/events?authorization=YOUR_TOKEN"

The first message you receive is the answer with registered; connect or disconnect the device to receive the event. The command-line example uses websocat.

Device resource streams ​

A separate WebSocket streams the resources of one connected device, such as a sensor reading every few seconds:

text
wss://YOUR_SERVER/v3/users/YOUR_USER/devices/YOUR_DEVICE/resources/<resource>?authorization=YOUR_TOKEN&interval=5000

The token needs Device:AccessDeviceResources on the device. Without /<resource>, one socket streams several resources of the device, which you choose with messages.

Query parameterContent
intervalSampling interval in milliseconds, for a single resource. 0 or none: the device sends its data when it produces it.
rawPresent (no value): the socket carries only the resource data, as text or binary, without the event fields. Needs a resource in the URL.
signalsComma-separated signals to receive: start, stop, data, error. By default data,error.

Each message is a device_resource_stream event (device, resource, signal, payload, ts…), or only the payload in raw mode. On a socket for several resources, send { "resource": "<resource>", "interval": <seconds> } to start or change a stream (in these messages interval is in seconds, not milliseconds as in the URL), { "resource": "<resource>", "enabled": false } to stop it, and { "resource": "<resource>", "payload": … } to send input to it.

Problems with a message arrive as { "error": "<message>" }, for example { "error": "device is not connected" } or { "error": "cannot access this device resource with the supplied credentials" }. If the device is not connected when you open the socket, the server answers 404 with device not available, and the socket closes when the device disconnects.

Deprecated endpoints ​

EndpointUse instead
GET /v1/users/{user}/events (WebSocket)GET /v2/users/{user}/events. The v1 socket sends no answers and has no unregister or clear.
GET /v1/users/{user}/devices/{device}/stats (server-sent events with the device status)The device_state_change event on GET /v2/users/{user}/events.

See also ​