> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vyntaintegrate.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Connect Sensors and Devices

> Push temperature, pressure, vibration, runtime and error-code readings from your own devices into asset health — endpoint, payload and copy-paste recipes.

By the end of this guide a device you own — a microcontroller, a gateway, or a webhook from a platform you already run — will be posting readings onto a Vynta asset, and those readings will be counting towards its health score.

<Note>
  **Who this is for.** Admins and managers: the key is issued under **Settings → Sensors & Predictions**. Anyone who writes firmware or automations can do the posting — there is nothing to install on the device side beyond an HTTP POST.
</Note>

## What You Need

<Steps>
  <Step title="Get an ingest key">
    Issue it in **Settings → Sensors & Predictions**. It is shown once, so copy it when it appears.
  </Step>

  <Step title="Get an asset ID">
    Use the copy button beside each asset on the same settings page.
  </Step>

  <Step title="Have something that can POST JSON over HTTPS">
    That is the whole requirement.
  </Step>
</Steps>

## The Endpoint

```bash theme={null}
POST https://vyntaintegrate.com/api/public/sensors/readings
content-type: application/json
x-sensor-key: YOUR_KEY
```

The body is a batch of readings:

```json theme={null}
{
  "readings": [
    {
      "equipment_id": "ASSET_UUID",
      "metric": "temperature_c",
      "value": 41.2,
      "unit": "°C",
      "recorded_at": "2026-09-21T06:15:00Z"
    }
  ]
}
```

* **equipment\_id** — the asset's ID. Only assets in your own business are accepted.
* **metric** — one of `temperature_c`, `pressure_kpa`, `vibration_mm_s`, `runtime_hours`, `error_codes`.
* **value** — the number. **unit** is optional, 20 characters max.
* **recorded\_at** — any ISO 8601 spelling. Omit it and the server stamps the arrival time; send a time without a zone and it is read as UTC.
* Up to **200 readings** per request — batch a queue rather than posting once per sample.

## Send Your First Reading

<Steps>
  <Step title="Open Settings → Sensors & Predictions">
    The **Connect a device** section shows the endpoint and a complete `curl` example.
  </Step>

  <Step title="Issue a key">
    The `curl` example fills in with your key the moment it is issued.
  </Step>

  <Step title="Run it">
    Swap `ASSET_UUID` for a copied asset ID and run the command, or paste the key into **Send a test reading** and press the button.
  </Step>

  <Step title="Confirm">
    The key row shows **Last used** the moment the endpoint accepts a batch.
  </Step>
</Steps>

## Recipes

<Tabs>
  <Tab title="ESP32 / Arduino">
    ```cpp theme={null}
    #include <HTTPClient.h>

    void pushTemperature(float celsius) {
      HTTPClient http;
      http.begin("https://vyntaintegrate.com/api/public/sensors/readings");
      http.addHeader("content-type", "application/json");
      http.addHeader("x-sensor-key", "YOUR_KEY");
      String body = "{\"readings\":[{\"equipment_id\":\"ASSET_UUID\","
                    "\"metric\":\"temperature_c\",\"value\":" + String(celsius) + "}]}";
      http.POST(body);
      http.end();
    }
    ```
  </Tab>

  <Tab title="Raspberry Pi (Python)">
    ```python theme={null}
    import requests

    requests.post(
        "https://vyntaintegrate.com/api/public/sensors/readings",
        headers={"x-sensor-key": "YOUR_KEY"},
        json={"readings": [{
            "equipment_id": "ASSET_UUID",
            "metric": "temperature_c",
            "value": 41.2,
        }]},
        timeout=10,
    )
    ```
  </Tab>

  <Tab title="Home Assistant">
    Add a `rest_command` and call it from an automation:

    ```yaml theme={null}
    rest_command:
      vynta_sensor_reading:
        url: "https://vyntaintegrate.com/api/public/sensors/readings"
        method: POST
        content_type: "application/json"
        headers:
          x-sensor-key: "YOUR_KEY"
        payload: '{"readings":[{"equipment_id":"ASSET_UUID","metric":"temperature_c","value":{{ states("sensor.plant_room_temperature") }}}]}'
    ```
  </Tab>

  <Tab title="Node-RED">
    Point an **HTTP request** node at the endpoint: method POST, the `x-sensor-key` header in its Headers tab, and `msg.payload` shaped as `{"readings":[…]}` — a Function node before it maps whatever your sensor nodes emit onto `equipment_id`, `metric` and `value`.
  </Tab>

  <Tab title="Make, Zapier or any webhook platform">
    Use the HTTP / Webhooks module: POST, JSON body, add the `x-sensor-key` header, and map your fields onto the payload. The key is header-only by design, so pick a module that supports custom headers.
  </Tab>
</Tabs>

## How Readings Are Used

Readings above their threshold count as fault signals in [asset health scoring](/guides/asset-tracking). Thresholds and per-metric switches live on the same settings page:

* A metric switched off still records readings but never affects a score.
* Switching an asset off stops its feed entirely without deleting history.
* The sample the test button posts is runtime hours, which has no default threshold — connecting can never alarm on its own.

## Common Problems

<AccordionGroup>
  <Accordion title="401 Unauthorized">
    The key is wrong or revoked. Keys are stored hashed — a revoked key cannot be restored; issue a new one and update the device.
  </Accordion>

  <Accordion title="404 No matching equipment">
    The asset ID does not belong to your business, or sensors are switched off for that asset.
  </Accordion>

  <Accordion title="400 invalid_payload">
    The reply lists the index and field that failed — usually a typo in `metric` or a malformed timestamp.
  </Accordion>

  <Accordion title="Readings arrive but the score does not move">
    They are below threshold, or the metric is switched off — both are by design.
  </Accordion>

  <Accordion title="The device cannot reach the endpoint">
    It is plain HTTPS POST — no VPN, no mTLS. Test the same URL from a laptop with the curl example first.
  </Accordion>
</AccordionGroup>
