Skip to content

Devices

HTTP

Send data to Thinger.io from any device, script or cloud service with HTTP requests, store and process it with a product, and answer with configuration data.

Guide11 min read

This guide connects anything that can send an HTTP request, such as a device without a Thinger.io library, a script or another cloud, as an HTTP device of a product. The product decides what each request does: the Data Buckets and properties that store it, the script that transforms it and what the response carries back. You create the product and the device, and send data with curl.

An HTTP device sends data when it wants; the platform cannot call it. If the device can keep a connection open, use the device libraries or MQTT to send it commands at any time.

HTTP devicesDevice without a libraryScript or curlAnother cloudSigfox, LoRaWAN serversProducthttp_sensorAPI resource dataRequest: Device Stream readingsPayload Processing: parseReadingResponse: Device Property downlinkHandle Device Connectivity: onProduct ScriptJavaScript functions, such as parseReadingAuto Provisioncreates the device on its first requestData Bucketone record per requestProperty last_readingthe last reading of the deviceProperty downlinkof the device or the productPOST …/resources/databody and token200 with the value ofthe downlink propertyThe platform never calls an HTTP device: the device receives data only in the response to its own request.
What happens with each request to an HTTP device of a product

HTTP devices used to be configured one by one with their Callback settings. The callback still works, but it is deprecated: see HTTP callback (deprecated).

Before you start ​

  • A Thinger.io account. Your server is YOUR_SERVER: iot.thinger.io on the free Cloud account, or your own domain on a private instance.
  • curl, or any HTTP client.

Steps ​

  1. Create the product

    The product http_sensor turns each request into data with these entries of its profile:

    EntryWhat it does
    API resource dataThe resource the device posts to. Its request sends the body to the device stream readings, and its response returns the downlink property of the device. Handle Device Connectivity shows the device as connected while it sends requests.
    Data Bucket http_sensor_readingsStores every reading of the readings stream, tagged with the device ID.
    Property last_readingKeeps the last reading of each device.
    Auto Provision rule sensorsCreates the device on its first request when its ID matches ^sensor_[0-9]+$. Optional.

    The product property downlink gives every device the same default answer, {"interval": 60}.

    Console

    Go to Products, click Add Product, set the Product ID to http_sensor and a Product Name, and click Add Product. On the Profile tab of the product, click Add in each card:

    1. API Resources: set the Resource Identifier to data. On Request, choose Device Stream, set the Resource Name to readings and the Payload to Source Payload. On Response, choose Device Property, the property downlink and Source Payload. On Settings, keep Handle Device Connectivity on and click Save.
    2. Buckets: set the Bucket Identifier to http_sensor_readings. On Bucket Source, choose Device Stream, the Resource Name readings and Source Payload, and click Save.
    3. Properties: set the Property Identifier to last_reading. On Property Source, choose Device Stream, the Resource Name readings and Source Payload, and click Save.
    4. Auto Provision: set the Provision Identifier to sensors and the Device Pattern to ^sensor_[0-9]+$, and click Save.

    Then open the Properties tab of the product and add the property downlink with the value {"interval": 60}.

    Profile tab of the http_sensor product with the last_reading property and the http_sensor_readings bucket fed by the readings stream, the data API resource that sends to readings and answers with the downlink property, and the sensors Auto Provision rule with the pattern ^sensor_[0-9]+$
    Profile of the http_sensor product

    API

    Save the product with its profile in http_sensor.json:

    http_sensor.json
    json
    {
      "product": "http_sensor",
      "name": "HTTP sensor",
      "enabled": true,
      "profile": {
        "api": {
          "data": {
            "enabled": true,
            "handle_connectivity": true,
            "request": { "data": { "target": "resource_stream", "resource_stream": "readings", "payload_type": "source_payload" } },
            "response": { "data": { "source": "property", "property": "downlink", "payload_type": "source_payload" } }
          }
        },
        "buckets": {
          "http_sensor_readings": {
            "enabled": true,
            "data": { "source": "resource_stream", "resource_stream": "readings", "payload_type": "source_payload" }
          }
        },
        "properties": {
          "last_reading": {
            "enabled": true,
            "data": { "source": "resource_stream", "resource_stream": "readings", "payload_type": "source_payload" }
          }
        },
        "autoprovisions": {
          "sensors": { "enabled": true, "config": { "mode": "pattern", "pattern": "^sensor_[0-9]+$" } }
        }
      }
    }

    Create the product, then the product property:

    POST/v1/users/{user}/productsAPI reference
    bash
    curl -X POST "https://YOUR_SERVER/v1/users/YOUR_USER/products" \
      -H "Authorization: Bearer YOUR_TOKEN" \
      -H "Content-Type: application/json" \
      -d @http_sensor.json
    POST/v1/users/{user}/products/{product}/propertiesAPI reference
    bash
    curl -X POST "https://YOUR_SERVER/v1/users/YOUR_USER/products/http_sensor/properties" \
      -H "Authorization: Bearer YOUR_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"property": "downlink", "value": {"interval": 60}}'

    YOUR_TOKEN is an access token of your account that can create products.

    CLI

    Save the product document of the API tab as http_sensor.json, and create the product and its property:

    bash
    thinger product create http_sensor --from http_sensor.json
    thinger product property-set http_sensor downlink '{"interval": 60}'

    AI

    Ask your AI agent

    Create a product called http_sensor for HTTP devices. Add an API resource called data that sends what it receives to the device stream readings and answers with the downlink property of the device, with device connectivity handled. Store the readings stream in a bucket called http_sensor_readings and in a property called last_reading. Add an Auto Provision rule called sensors for the device pattern ^sensor_[0-9]+$, and a product property downlink with the value {"interval": 60}.

    The agent uses thinger_resource_create with the product type and the profile entry types. See MCP tools.

    Give the stream its own name, different from the API resource, as readings here. A stream with the name of an API resource that has a response also receives that response, and an empty reading, each time the device connects.

  2. Create the HTTP device

    Skip this step to let the Auto Provision rule create the device on its first request, with an ID such as sensor_001.

    Console

    Go to Devices and click Add Device. Choose HTTP Device (Sigfox, Lora, cURL) as Device Type, set the Device Id to YOUR_DEVICE, choose the product http_sensor under Advanced Options and click Add Device. HTTP devices have no device credentials: requests are authorized with a token.

    API

    POST/v1/users/{user}/devicesAPI reference
    bash
    curl -X POST "https://YOUR_SERVER/v1/users/YOUR_USER/devices" \
      -H "Authorization: Bearer YOUR_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"device": "YOUR_DEVICE", "type": "HTTP", "product": "http_sensor"}'

    CLI

    bash
    thinger device create YOUR_DEVICE -t HTTP -p http_sensor

    AI

    Ask your AI agent

    Create an HTTP device called YOUR_DEVICE in the product http_sensor.

  3. Create a token for the device

    The device needs a token that can call its data resource. Use a device token limited to that resource, so the token cannot do anything else:

    Console

    Open the device, go to Tokens and click Add. Set the Token Name, choose Limit the resource access for this token, type the resource data and save it. Copy the Device Token.

    API

    POST/v1/users/{user}/devices/{device}/tokensAPI reference
    bash
    curl -X POST "https://YOUR_SERVER/v1/users/YOUR_USER/devices/YOUR_DEVICE/tokens" \
      -H "Authorization: Bearer YOUR_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"token_name": "HTTP sensor", "token_resources": ["data"]}'

    The response holds the token value.

    AI

    Ask your AI agent

    Create a device token for YOUR_DEVICE that can only call its data resource, and show me the token.

    A device that Auto Provision creates does not exist before its first request, so it cannot have a device token yet. Give those devices an access token with the AccessDeviceResources action on the Device type, for any device (*).

  4. Send data

    Post the reading to the data resource of the device. YOUR_TOKEN is the token from the previous step.

    POST/v3/users/{user}/devices/{device}/resources/{resource}API reference
    bash
    curl -X POST "https://YOUR_SERVER/v3/users/YOUR_USER/devices/YOUR_DEVICE/resources/data" \
      -H "Authorization: Bearer YOUR_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"temperature": 21.5, "humidity": 48}'

    If the client cannot set headers, pass the token in the URL instead: ?authorization=YOUR_TOKEN.

Result ​

The request returns 200 with the downlink property:

json
{"interval": 60}

The device shows as connected in Devices until its Disconnect Timeout passes without requests (10 minutes by default, in the device Settings). The reading is in the Data Bucket http_sensor_readings, tagged with the device, which the Buckets tab of the device shows, and in the last_reading property:

bash
thinger device property YOUR_DEVICE last_reading

To show the data of each device in a dashboard, add a product dashboard with the bucket as From Device Bucket.

Send data back to the device ​

The response of each request carries the downlink property, so the device receives its configuration every time it reports. The product property sets the value for every device; a device property with the same name overrides it for one device. Change it from the console, a dashboard or the API, and the next response carries the new value:

PUT/v3/users/{user}/devices/{device}/properties/{property}API reference
bash
curl -X PUT "https://YOUR_SERVER/v3/users/YOUR_USER/devices/YOUR_DEVICE/properties/downlink" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"value": {"interval": 120}}'

YOUR_TOKEN is an access token of your account. The API resource can answer with something else, such as the result of a product function or an endpoint call: see API resources. Without a response, the request returns 200 with an empty body.

Process the payload ​

A function of the product script can transform each request before it reaches the stream: decode a compact format, convert units, rename fields. The body does not need to be JSON: a text/plain body reaches the function as text. This function turns a reading sent as 21.5,48 into JSON:

Product Script
js
// "21.5,48" -> {"temperature": 21.5, "humidity": 48}
function parseReading(payload) {
  if (typeof payload !== 'string') return payload;
  const [temperature, humidity] = payload.split(',').map(Number);
  return { temperature, humidity };
}

Write it in the Product Script card of the product profile and click Save. Then edit the API resource data, set Payload Processing to parseReading on its Request and save it. The device can now send the short form:

bash
curl -X POST "https://YOUR_SERVER/v3/users/YOUR_USER/devices/YOUR_DEVICE/resources/data" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: text/plain" \
  -d '21.5,48'

The same setting exists on each bucket and property, to transform the data for only one of them. A function that returns nothing skips the write.

Store the location ​

A request does not move the device on maps by itself: store its position in the location property of the device, which places it on maps and checks its geofences. For readings with lat and lng fields, add this function to the script:

Product Script
js
function toLocation(payload) {
  if (payload.lat === undefined || payload.lng === undefined) return;
  return { lat: payload.lat, lon: payload.lng };
}

Then add a property location to the profile with the Device Stream readings as source, Source Payload and Payload Processing toLocation. Readings without a position leave the property as it was.

Request reference ​

PartValue
Method and URLPOST https://YOUR_SERVER/v3/users/YOUR_USER/devices/YOUR_DEVICE/resources/data, where data is an API resource of the product.
AuthorizationAuthorization: Bearer YOUR_TOKEN header, or ?authorization=YOUR_TOKEN. A device token of the device, or an access token with the AccessDeviceResources action on it.
BodyA JSON document with Content-Type: application/json, or text with Content-Type: text/plain. An array writes one Data Bucket record per element.
ts fieldOptional. A number in the body with the time of the reading in milliseconds since the Unix epoch, for data sent late: the Data Bucket stores the record with that time.
ResponseMeaning
200Accepted. The body is the response of the API resource, such as the downlink property, or empty if it has none.
400The body is not valid JSON while the content type says it is, or the device is disabled.
401No token, or the token is not valid.
403The token has no permission for this device resource.
404The device does not exist and no Auto Provision rule matches its ID, the product has no enabled API resource with that name, or the property of the response does not exist (property not found). In the last case the data is stored anyway.

For every device operation, see the REST API reference.

Troubleshooting ​

SymptomCauseFix
401 unauthorizedThe token is missing, mistyped or revoked.Copy the token again, or create a new one.
403 not authorizedThe token belongs to another device or does not reach this device resource.Use a device token of this device with the resource, or an access token with AccessDeviceResources on it.
404 with an empty bodyThe device does not exist and its ID does not match an Auto Provision rule.Create the device, or fix the Device Pattern of the rule.
404 resource not foundThe device has no product, or the product has no enabled API resource with that name.Assign the device to the product, and check the name and Enabled of the API resource.
404 property not foundThe response property does not exist for this device or its product.Add the product property downlink, or set it on the device.
400 invalid json payloadThe body is not JSON but the content type says it is.Send valid JSON, or text with Content-Type: text/plain and a function that decodes it.
The device shows as disconnected between requestsThe Disconnect Timeout is shorter than the reporting interval, or Handle Device Connectivity is off.Raise the Disconnect Timeout in the device Settings, and turn the option on in the API resource.
The Data Bucket gets empty records, or the value of the responseThe stream has the name of an API resource that has a response.Give the Device Stream of the request its own Resource Name, such as readings.

More cases in Troubleshooting.

HTTP callback (deprecated) ​

Deprecated

The HTTP callback stays available for the devices that use it, but new integrations should use a product as described above. A product covers the same needs, as Move a callback to a product shows, and adds Auto Provision, payload processing, text payloads and responses from any source.

The callback is set on each HTTP device, in its Callback tab, with or without a product. Each request to the callback URL runs the actions of the device and answers with one of its properties.

HTTP clientsDevice without a libraryScript or curlAnother cloudSigfox, LoRaWAN serversHTTP deviceCallback settingsWrite BucketCall EndpointSet Device PropertyResponse DataTimeout: disconnected without requestsData BucketEndpointDevice propertyThe Data Bucket and the endpointmust exist; the property is createdPOST …/callback/dataJSON body and token200 with the value ofthe Response Data propertyThe platform never calls an HTTP device: the device receives data only in the response to its own request.
What happens with each request to the callback of an HTTP device

Configure the callback ​

Create the HTTP device as in Steps, with or without a product. Open the device and go to Callback. In Settings, enable the actions you need:

FieldWhat it does
Write BucketStores the request body in a Data Bucket.
Call EndpointCalls an endpoint with the request body.
Set Device PropertySaves the request body in a device property, so it always holds the last value.
Response DataAnswers each request with the value of a device property.
TimeoutMinutes without requests before the device shows as disconnected.

The Data Bucket of Write Bucket and the endpoint of Call Endpoint must exist before the first request: if one is missing, the request still returns 200 but that action does nothing. Set Device Property creates the property if it does not exist.

Then enable Authorization. The console creates an access token that can only send data to this device, and shows it in Overview with the Target URL and a Curl Example.

Callback Overview tab of an HTTP device with the target URL, the authorization header and a curl example
Callback overview of an HTTP device

From the API, set the same actions with PUT /v3/users/{user}/devices/{device}/callback:

json
{
  "actions": {
    "write_bucket": "YOUR_BUCKET",
    "set_property": "telemetry",
    "send_property": "downlink"
  },
  "properties": { "timeout": 10 }
}

Send data to the callback ​

Post a JSON body to the device callback. YOUR_TOKEN is the token from Overview, or any access token with the CallDeviceCallback action on this device.

POST/v3/users/{user}/devices/{device}/callback/dataAPI reference
bash
curl -X POST "https://YOUR_SERVER/v3/users/YOUR_USER/devices/YOUR_DEVICE/callback/data" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"temperature": 21.5, "humidity": 48}'

The body is in the Data Bucket and in the telemetry property, and the response carries the Response Data property. Change that property as in Send data back to the device; read the current response without sending data with GET /v3/users/YOUR_USER/devices/YOUR_DEVICE/callback/data.

PartValue
Method and URLPOST https://YOUR_SERVER/v3/users/YOUR_USER/devices/YOUR_DEVICE/callback/data
AuthorizationAuthorization: Bearer YOUR_TOKEN header, or ?authorization=YOUR_TOKEN
BodyAny JSON document, with Content-Type: application/json
ts query parameterOptional. Time of the reading in milliseconds since the Unix epoch, for data sent late.
LocationOptional. lat and lng (or latitude and longitude) at the top level or inside location update the device location and its geofences.
ResponseMeaning
200 with a JSON bodyAccepted. The body is the Response Data property, or "" if none is set.
400The body is not valid JSON, ts is not a number, or the device is disabled.
401No token, or the token is not valid.
403The token has no permission for this device.
404There is no HTTP device with that ID (device callback not found). The callback does not create devices with Auto Provision.

Move a callback to a product ​

CallbackProduct
POST …/callback/dataPOST …/resources/<resource>, an API resource with a Device Stream request
Write BucketA product bucket with the stream as source, created on the first write
Set Device PropertyA product property with the stream as source
Call EndpointA flow with the stream as source and an Endpoint Call target
Response DataThe response of the API resource, such as Device Property
TimeoutDisconnect Timeout in the device Settings
ts query parameterA ts field in the body
lat and lng in the bodyA location property filled by a function, as in Store the location
Authorization token from OverviewA device token limited to the API resource

Next steps ​