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

# Eclipse Ditto (digital twins)

> Client-mode REST API connector for Eclipse Ditto digital twins: create, read, merge and delete things, write feature properties from MQTT telemetry, set desired properties, send live messages to devices, search and count twins with RQL, manage policies and check connection status

Technical Preview

## Overview

One client-mode connector, **EclipseDitto**, for the [Eclipse Ditto](https://eclipse.dev/ditto/) HTTP API 2. Ditto is an open-source digital twin framework: every device or asset is a **thing** with attributes (static metadata) and **features** (groups of live properties and desired properties), and access is controlled per thing by a **policy**.

Use the connector to keep a twin in step with the plant floor: merge each telemetry message from the broker into a feature, tag things with their UNS path and line, read the twin or a single property back, set a desired setpoint, send a live command through Ditto to the device, and find every twin on a line with one RQL search.

| Event | Request | Notes |
| - | - | - |
| ListThings | `GET /things?ids={ids}` | `ids` is a comma-separated list of thing ids |
| GetThing | `GET /things/{thing_id}` | Whole twin: policy id, attributes, features |
| CreateThing | `POST /things` | Ditto generates the thing id; returns `201` |
| PutThing | `PUT /things/{thing_id}` | `201` created or `204` replaced |
| PatchThing | `PATCH /things/{thing_id}` | JSON merge patch; `null` deletes a key |
| DeleteThing | `DELETE /things/{thing_id}` | Returns `204` |
| GetAttributes | `GET /things/{thing_id}/attributes` | |
| PutAttribute | `PUT /things/{thing_id}/attributes/{attribute_path}` | Body is the raw JSON value |
| ListFeatures | `GET /things/{thing_id}/features` | |
| GetFeature | `GET /things/{thing_id}/features/{feature_id}` | |
| PutFeature | `PUT /things/{thing_id}/features/{feature_id}` | Whole feature with `properties` |
| GetFeatureProperties | `GET /things/{thing_id}/features/{feature_id}/properties` | |
| PutFeatureProperties | `PUT /things/{thing_id}/features/{feature_id}/properties` | |
| PatchFeatureProperties | `PATCH /things/{thing_id}/features/{feature_id}/properties` | Merge telemetry into a feature; returns `204` |
| GetFeatureProperty | `GET /things/{thing_id}/features/{feature_id}/properties/{property_path}` | `property_path` may contain slashes |
| PutFeatureProperty | `PUT /things/{thing_id}/features/{feature_id}/properties/{property_path}` | |
| GetDesiredProperties | `GET /things/{thing_id}/features/{feature_id}/desiredProperties` | |
| PutDesiredProperty | `PUT /things/{thing_id}/features/{feature_id}/desiredProperties/{property_path}` | Desired value the device should converge to |
| SendThingMessage | `POST /things/{thing_id}/inbox/messages/{subject}?timeout={timeout}` | `timeout` `0` returns `202`; otherwise waits for the reply |
| SendFeatureMessage | `POST /things/{thing_id}/features/{feature_id}/inbox/messages/{subject}?timeout={timeout}` | Same, addressed to one feature |
| SearchThings | `GET /search/things?{query}` | Pre-encoded RQL query, e.g. `filter=...&option=size(50)` |
| CountThings | `GET /search/things/count?{query}` | Same `query`; returns a number |
| GetPolicy | `GET /policies/{policy_id}` | |
| PutPolicy | `PUT /policies/{policy_id}` | Who can read and write the thing |
| WhoAmI | `GET /whoami` | Shows the subject your credentials map to |
| ListConnections | `GET /connections` | Devops credentials |
| GetConnectionStatus | `GET /connections/{connection_id}/status` | Devops credentials |

Topics are `cloud-iot/eclipse-ditto/<object>/<verb>`; every reply goes to `<topic>/response`. Paths in the table are relative to `/api/2`.

## Authentication

Ditto is self-hosted or run by a vendor, so authentication depends on how your gateway is set up. Every event sends `Authorization: {authorization}`, so pass the whole header value:

* `"Basic <base64(user:password)>"` when Ditto sits behind nginx basic auth (the default Docker Compose stack, with user `ditto`).
* `"Bearer <JWT>"` when Ditto is configured for an OpenID Connect provider such as Keycloak or Microsoft Entra ID.

Keep it in a broker secret (suggested `DITTO_AUTHORIZATION`) and map it in with `GET SECRET`. `ListConnections` and `GetConnectionStatus` are devops endpoints and need the devops credentials instead (suggested `DITTO_DEVOPS_AUTHORIZATION`). Wrong credentials return `401`; a policy that does not grant `READ` or `WRITE` returns `403` or `404`.

## Basic Syntax

Set `BASE_ADDRESS` to your Ditto gateway or nginx front, with no trailing slash. For the local Docker Compose stack that is `http://localhost:8080`, with `USE_SSL "false"`.

```lot theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
DEFINE ROUTE EclipseDitto WITH TYPE REST_API
    ADD REST_API_CONFIG
        WITH BASE_ADDRESS "https://YOUR_DITTO_HOST"
        WITH ENABLE_CLIENT "true"
        WITH USE_SSL "true"
        WITH REQUEST_TIMEOUT '30'
        WITH DEFAULT_CONTENT_TYPE "application/json"
        # Smoke: WhoAmI and GetThing (GET), PutThing (PUT), PatchFeatureProperties (PATCH), SearchThings, DeleteThing on a throwaway thing.
    ADD EVENT ListThings
        WITH SOURCE_TOPIC "cloud-iot/eclipse-ditto/thing/list"
        WITH DESTINATION_TOPIC "cloud-iot/eclipse-ditto/thing/list/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/api/2/things?ids={value.json.ids}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
    ADD EVENT GetThing
        WITH SOURCE_TOPIC "cloud-iot/eclipse-ditto/thing/get"
        WITH DESTINATION_TOPIC "cloud-iot/eclipse-ditto/thing/get/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/api/2/things/{value.json.thing_id}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
    ADD EVENT CreateThing
        WITH SOURCE_TOPIC "cloud-iot/eclipse-ditto/thing/create"
        WITH DESTINATION_TOPIC "cloud-iot/eclipse-ditto/thing/create/response"
        WITH METHOD "POST"
        WITH ENDPOINT "/api/2/things"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Content-Type" "application/json"
            ADD "Authorization" "{value.json.authorization}"
        WITH BODY "{value.json.body}"
    ADD EVENT PutThing
        WITH SOURCE_TOPIC "cloud-iot/eclipse-ditto/thing/put"
        WITH DESTINATION_TOPIC "cloud-iot/eclipse-ditto/thing/put/response"
        WITH METHOD "PUT"
        WITH ENDPOINT "/api/2/things/{value.json.thing_id}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Content-Type" "application/json"
            ADD "Authorization" "{value.json.authorization}"
        WITH BODY "{value.json.body}"
    ADD EVENT PatchThing
        WITH SOURCE_TOPIC "cloud-iot/eclipse-ditto/thing/patch"
        WITH DESTINATION_TOPIC "cloud-iot/eclipse-ditto/thing/patch/response"
        WITH METHOD "PATCH"
        WITH ENDPOINT "/api/2/things/{value.json.thing_id}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Content-Type" "application/merge-patch+json"
            ADD "Authorization" "{value.json.authorization}"
        WITH BODY "{value.json.body}"
    ADD EVENT DeleteThing
        WITH SOURCE_TOPIC "cloud-iot/eclipse-ditto/thing/delete"
        WITH DESTINATION_TOPIC "cloud-iot/eclipse-ditto/thing/delete/response"
        WITH METHOD "DELETE"
        WITH ENDPOINT "/api/2/things/{value.json.thing_id}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
    ADD EVENT GetAttributes
        WITH SOURCE_TOPIC "cloud-iot/eclipse-ditto/attributes/get"
        WITH DESTINATION_TOPIC "cloud-iot/eclipse-ditto/attributes/get/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/api/2/things/{value.json.thing_id}/attributes"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
    ADD EVENT PutAttribute
        WITH SOURCE_TOPIC "cloud-iot/eclipse-ditto/attribute/put"
        WITH DESTINATION_TOPIC "cloud-iot/eclipse-ditto/attribute/put/response"
        WITH METHOD "PUT"
        WITH ENDPOINT "/api/2/things/{value.json.thing_id}/attributes/{value.json.attribute_path}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Content-Type" "application/json"
            ADD "Authorization" "{value.json.authorization}"
        WITH BODY "{value.json.body}"
    ADD EVENT ListFeatures
        WITH SOURCE_TOPIC "cloud-iot/eclipse-ditto/feature/list"
        WITH DESTINATION_TOPIC "cloud-iot/eclipse-ditto/feature/list/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/api/2/things/{value.json.thing_id}/features"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
    ADD EVENT GetFeature
        WITH SOURCE_TOPIC "cloud-iot/eclipse-ditto/feature/get"
        WITH DESTINATION_TOPIC "cloud-iot/eclipse-ditto/feature/get/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/api/2/things/{value.json.thing_id}/features/{value.json.feature_id}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
    ADD EVENT PutFeature
        WITH SOURCE_TOPIC "cloud-iot/eclipse-ditto/feature/put"
        WITH DESTINATION_TOPIC "cloud-iot/eclipse-ditto/feature/put/response"
        WITH METHOD "PUT"
        WITH ENDPOINT "/api/2/things/{value.json.thing_id}/features/{value.json.feature_id}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Content-Type" "application/json"
            ADD "Authorization" "{value.json.authorization}"
        WITH BODY "{value.json.body}"
    ADD EVENT GetFeatureProperties
        WITH SOURCE_TOPIC "cloud-iot/eclipse-ditto/feature-properties/get"
        WITH DESTINATION_TOPIC "cloud-iot/eclipse-ditto/feature-properties/get/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/api/2/things/{value.json.thing_id}/features/{value.json.feature_id}/properties"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
    ADD EVENT PutFeatureProperties
        WITH SOURCE_TOPIC "cloud-iot/eclipse-ditto/feature-properties/put"
        WITH DESTINATION_TOPIC "cloud-iot/eclipse-ditto/feature-properties/put/response"
        WITH METHOD "PUT"
        WITH ENDPOINT "/api/2/things/{value.json.thing_id}/features/{value.json.feature_id}/properties"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Content-Type" "application/json"
            ADD "Authorization" "{value.json.authorization}"
        WITH BODY "{value.json.body}"
    ADD EVENT PatchFeatureProperties
        WITH SOURCE_TOPIC "cloud-iot/eclipse-ditto/feature-properties/patch"
        WITH DESTINATION_TOPIC "cloud-iot/eclipse-ditto/feature-properties/patch/response"
        WITH METHOD "PATCH"
        WITH ENDPOINT "/api/2/things/{value.json.thing_id}/features/{value.json.feature_id}/properties"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Content-Type" "application/merge-patch+json"
            ADD "Authorization" "{value.json.authorization}"
        WITH BODY "{value.json.body}"
    ADD EVENT GetFeatureProperty
        WITH SOURCE_TOPIC "cloud-iot/eclipse-ditto/feature-property/get"
        WITH DESTINATION_TOPIC "cloud-iot/eclipse-ditto/feature-property/get/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/api/2/things/{value.json.thing_id}/features/{value.json.feature_id}/properties/{value.json.property_path}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
    ADD EVENT PutFeatureProperty
        WITH SOURCE_TOPIC "cloud-iot/eclipse-ditto/feature-property/put"
        WITH DESTINATION_TOPIC "cloud-iot/eclipse-ditto/feature-property/put/response"
        WITH METHOD "PUT"
        WITH ENDPOINT "/api/2/things/{value.json.thing_id}/features/{value.json.feature_id}/properties/{value.json.property_path}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Content-Type" "application/json"
            ADD "Authorization" "{value.json.authorization}"
        WITH BODY "{value.json.body}"
    ADD EVENT GetDesiredProperties
        WITH SOURCE_TOPIC "cloud-iot/eclipse-ditto/desired-properties/get"
        WITH DESTINATION_TOPIC "cloud-iot/eclipse-ditto/desired-properties/get/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/api/2/things/{value.json.thing_id}/features/{value.json.feature_id}/desiredProperties"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
    ADD EVENT PutDesiredProperty
        WITH SOURCE_TOPIC "cloud-iot/eclipse-ditto/desired-property/put"
        WITH DESTINATION_TOPIC "cloud-iot/eclipse-ditto/desired-property/put/response"
        WITH METHOD "PUT"
        WITH ENDPOINT "/api/2/things/{value.json.thing_id}/features/{value.json.feature_id}/desiredProperties/{value.json.property_path}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Content-Type" "application/json"
            ADD "Authorization" "{value.json.authorization}"
        WITH BODY "{value.json.body}"
    ADD EVENT SendThingMessage
        WITH SOURCE_TOPIC "cloud-iot/eclipse-ditto/thing-message/send"
        WITH DESTINATION_TOPIC "cloud-iot/eclipse-ditto/thing-message/send/response"
        WITH METHOD "POST"
        WITH ENDPOINT "/api/2/things/{value.json.thing_id}/inbox/messages/{value.json.subject}?timeout={value.json.timeout}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Content-Type" "application/json"
            ADD "Authorization" "{value.json.authorization}"
        WITH BODY "{value.json.body}"
    ADD EVENT SendFeatureMessage
        WITH SOURCE_TOPIC "cloud-iot/eclipse-ditto/feature-message/send"
        WITH DESTINATION_TOPIC "cloud-iot/eclipse-ditto/feature-message/send/response"
        WITH METHOD "POST"
        WITH ENDPOINT "/api/2/things/{value.json.thing_id}/features/{value.json.feature_id}/inbox/messages/{value.json.subject}?timeout={value.json.timeout}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Content-Type" "application/json"
            ADD "Authorization" "{value.json.authorization}"
        WITH BODY "{value.json.body}"
    ADD EVENT SearchThings
        WITH SOURCE_TOPIC "cloud-iot/eclipse-ditto/search/things"
        WITH DESTINATION_TOPIC "cloud-iot/eclipse-ditto/search/things/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/api/2/search/things?{value.json.query}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
    ADD EVENT CountThings
        WITH SOURCE_TOPIC "cloud-iot/eclipse-ditto/search/count"
        WITH DESTINATION_TOPIC "cloud-iot/eclipse-ditto/search/count/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/api/2/search/things/count?{value.json.query}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
    ADD EVENT GetPolicy
        WITH SOURCE_TOPIC "cloud-iot/eclipse-ditto/policy/get"
        WITH DESTINATION_TOPIC "cloud-iot/eclipse-ditto/policy/get/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/api/2/policies/{value.json.policy_id}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
    ADD EVENT PutPolicy
        WITH SOURCE_TOPIC "cloud-iot/eclipse-ditto/policy/put"
        WITH DESTINATION_TOPIC "cloud-iot/eclipse-ditto/policy/put/response"
        WITH METHOD "PUT"
        WITH ENDPOINT "/api/2/policies/{value.json.policy_id}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Content-Type" "application/json"
            ADD "Authorization" "{value.json.authorization}"
        WITH BODY "{value.json.body}"
    ADD EVENT WhoAmI
        WITH SOURCE_TOPIC "cloud-iot/eclipse-ditto/whoami/get"
        WITH DESTINATION_TOPIC "cloud-iot/eclipse-ditto/whoami/get/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/api/2/whoami"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
    ADD EVENT ListConnections
        WITH SOURCE_TOPIC "cloud-iot/eclipse-ditto/connection/list"
        WITH DESTINATION_TOPIC "cloud-iot/eclipse-ditto/connection/list/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/api/2/connections"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
    ADD EVENT GetConnectionStatus
        WITH SOURCE_TOPIC "cloud-iot/eclipse-ditto/connection/status"
        WITH DESTINATION_TOPIC "cloud-iot/eclipse-ditto/connection/status/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/api/2/connections/{value.json.connection_id}/status"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
```

## MQTT examples

Request bodies go under `body`, so control fields like `authorization`, `thing_id` and `feature_id` are not sent to Ditto. Thing ids are `<namespace>:<name>`.

**Create a twin for a press**: create its policy on `cloud-iot/eclipse-ditto/policy/put`, then publish to `cloud-iot/eclipse-ditto/thing/put`:

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
{
  "authorization": "Basic <base64 user:password>",
  "thing_id": "org.coreflux:press-07",
  "body": {
    "policyId": "org.coreflux:press-07",
    "attributes": {"site": "porto", "line": "line-1", "uns": "porto/line1/press07"},
    "features": {"telemetry": {"properties": {"temperature": 0, "pressure": 0}}}
  }
}
```

Ditto returns `201` with the new thing, or `204` when it replaced an existing one.

**Merge telemetry into the twin**: publish each reading to `cloud-iot/eclipse-ditto/feature-properties/patch`. It sends a JSON merge patch, so only the keys you send change and `null` removes a key:

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
{
  "authorization": "Basic <base64 user:password>",
  "thing_id": "org.coreflux:press-07",
  "feature_id": "telemetry",
  "body": {"temperature": 71.4, "pressure": 4.2, "state": "RUNNING"}
}
```

**Read one property back**: publish `{"authorization": "...", "thing_id": "org.coreflux:press-07", "feature_id": "telemetry", "property_path": "temperature"}` to `cloud-iot/eclipse-ditto/feature-property/get`. Nested paths use slashes, for example `"status/alarm"`.

**Set a desired setpoint**: publish to `cloud-iot/eclipse-ditto/desired-property/put` with `"property_path": "speed"` and `"body": 1500`. The body is the raw JSON value, so a string must be a JSON string such as `"body": "\"AUTO\""`.

**Send a live command to the device**: publish to `cloud-iot/eclipse-ditto/thing-message/send`:

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
{
  "authorization": "Basic <base64 user:password>",
  "thing_id": "org.coreflux:press-07",
  "subject": "set-speed",
  "timeout": "10s",
  "body": {"setpoint": 1500}
}
```

With `"timeout": "0"` Ditto accepts the message with `202` and does not wait; with a timeout it waits for the device's reply and returns `408` if no device answers in time.

**Find every twin on a line**: publish to `cloud-iot/eclipse-ditto/search/things` with a pre-encoded [RQL](https://eclipse.dev/ditto/basic-rql.html) query:

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
{
  "authorization": "Basic <base64 user:password>",
  "query": "filter=eq(attributes%2Fline%2C%22line-1%22)&option=size(50)"
}
```

`cloud-iot/eclipse-ditto/search/count` takes the same `query` and returns a number.

## Helper actions

Keep the credentials in a broker secret and mirror plant telemetry into Ditto as it arrives:

```lot theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
DEFINE ACTION DittoMirrorPressTelemetry
ON TOPIC "porto/line1/+/telemetry" DO
    SET "auth" WITH GET SECRET "DITTO_AUTHORIZATION"
    SET "machine" WITH TOPIC POSITION 3
    SET "thing" WITH "org.coreflux:" + {machine}
    SET "temperature" WITH GET JSON "temperature" IN PAYLOAD AS DOUBLE
    SET "pressure" WITH GET JSON "pressure" IN PAYLOAD AS DOUBLE
    PUBLISH TOPIC "cloud-iot/eclipse-ditto/feature-properties/patch" WITH { "authorization": {auth}, "thing_id": {thing}, "feature_id": "telemetry", "body": { "temperature": {temperature}, "pressure": {pressure} } }

DEFINE ACTION DittoCountLineTwins
ON EVERY 15 MINUTES DO
    SET "auth" WITH GET SECRET "DITTO_AUTHORIZATION"
    PUBLISH TOPIC "cloud-iot/eclipse-ditto/search/count" WITH { "authorization": {auth}, "query": "filter=eq(attributes%2Fline%2C%22line-1%22)" }
```

`DittoMirrorPressTelemetry` assumes thing ids match the machine segment of the topic, for example `org.coreflux:press07`. Restrict who can publish to `cloud-iot/eclipse-ditto/#` with a rule: its payloads carry the credentials and can change twins and send commands to devices.

## Notes

* Errors come back on the response topic: `400` for bad JSON, a bad RQL filter or an invalid id, `401` for missing or wrong credentials, `403` when the policy does not allow the change, `404` for an unknown thing, feature, property or policy (or one you cannot see), `408` when a message times out, `412` when a condition fails, and `413` when an entity is too large.
* `PatchThing` and `PatchFeatureProperties` send `application/merge-patch+json`. Every other write is a plain JSON `PUT` or `POST`.
* The `query` field on search events and `ids` on `ListThings` must be URL-encoded. `ListThings` needs at least one id; use `SearchThings` to list without ids.
* Ditto also has WebSocket, Server-Sent Events and its own MQTT and Kafka connections. For high-rate telemetry, a Ditto MQTT connection that subscribes to your Coreflux broker can be cheaper than one HTTP call per message. This template covers the HTTP API only and does not create connections.
* The public sandbox `https://ditto.eclipseprojects.io` listed in the Ditto OpenAPI spec refused every request from our test machine, so test against your own instance.

## Related

* [REST API Connectors](/latest/lot-language/routes/rest-api-routes)
* [REST API app templates](/latest/lot-language/routes/rest-api-apps/index)
* [Azure Digital Twins](/latest/lot-language/routes/rest-api-apps/azure-digital-twins)
* [Mender](/latest/lot-language/routes/rest-api-apps/mender)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.