> ## 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.

# Canary Read

> Client-mode REST API connectors for the Canary Historian: browse nodes and tags, read last values, raw history and aggregates, poll live data, annotations and events through the Views Read API, and write MQTT values into Canary through the Store and Forward Write API session (getSessionToken, storeData, keepAlive)

Technical Preview

## Overview

Client-mode REST API connectors for the Canary Historian: browse nodes and tags, read last values, raw history and aggregates, poll live data, annotations and events through the Views Read API, and write MQTT values into Canary through the Store and Forward Write API session (getSessionToken, storeData, keepAlive).

This is one of the templates in the Canary Historian REST API app (`canary-historian`). Deploy it alongside the other connectors of that app when they depend on each other (for example a token connector plus an API connector).

> [!NOTE]
>
> Not yet verified against the live vendor API: Canary Historian is self-hosted (Windows services); there is no public Canary API instance (the Axiom sandbox on canarylabs.com is a gated UI demo, no Views/SaF endpoint) and no Canary URL or API token on the factory box (no CANARY\_ variables in env). Connectors checked statically against a curated OpenAPI built 1:1 from Canary's official Read API 26.5 / Write API 26.4 docs plus the official v25 Postman collections (296/296), every event rendered against a local mock Views + SaF (22/22, write->read-back flow 4/4, 4/4 controls: expired session BadSessionToken, wrong apiToken Errors, missing historians Errors, stale liveDataToken BadLiveDataToken), Canary docs hosts reachable with all 22 methods listed (4/4). This does not clear the gate. Needs: a Canary 24+ system reachable from the test box (Views web API https :55236 and, for writes, SaF web API https :55293; its certificate trusted or CANARY\_INSECURE=1), an API token from Identity > Security > API Tokens linked to a Canary user with read permission on the view and write permission on a test DataSet (CANARY\_API\_TOKEN), the historian name (CANARY\_HISTORIAN, default localhost) and a throwaway DataSet name (CANARY\_TEST\_DATASET, default CorefluxSmoke). Gate: CANARY\_READ\_URL=https\://\<host>:55236 CANARY\_WRITE\_URL=https\://\<host>:55293 CANARY\_API\_TOKEN=\<token> CANARY\_ALLOW\_WRITE=1 python3 smoke\_canary.py -> BrowseNodes/BrowseTags/GetTagData (last + raw)/GetAggregates statusCode Good, bad token not Good, GetVersion Good, GetSessionToken returns sessionToken, StoreData/KeepAlive/RevokeSessionToken Good, value 42.0 read back with GetTagData; then a broker MQTT round-trip (publish historian/canary-write/tag-data/store and historian/canary/tag-data/get, read /response).

## Auth

* **token**: Identity API token as apiToken inside the JSON body (payload field body); sessionToken / liveDataToken / userToken for session, live data and Windows-account calls
* **windows**: Read API GetUserToken over https with username/password of a Windows account mapped to a Canary user -> userToken (5 min idle expiry). Not available on the v24+ Write API.
* **secret**: \["CANARY\_API\_TOKEN"]
* **unauthenticated**: \["GetVersion"]
* **note**: No Authorization header is sent; the Read API would also accept 'Authorization: Bearer \<apiToken>' but the Write API documents only the body field, so both connectors use the body for consistency. Canary services typically use a self-signed certificate; the broker host must trust it.

## Template parameters

| Placeholder | Type | Description | Required |
| - | - | - | - |
| `RouteName` | string | Name of the Canary Read connector | no |
| `BaseUrl` | string | Canary Read base URL without trailing slash (e.g. https\://YOUR\_CANARY\_HOST:55236) | yes |

`BASE_ADDRESS` default: `https://YOUR_CANARY_HOST:55236`.

## Events

| Event | Method | Endpoint | Request topic | Response topic | Payload fields |
| - | - | - | - | - | - |
| `GetUserToken` | POST | `/api/v2/getUserToken` | `historian/canary/user-token/create` | `historian/canary/user-token/create/response` | `body` |
| `RevokeUserToken` | POST | `/api/v2/revokeUserToken` | `historian/canary/user-token/delete` | `historian/canary/user-token/delete/response` | `body` |
| `BrowseNodes` | POST | `/api/v2/browseNodes` | `historian/canary/node/list` | `historian/canary/node/list/response` | `body` |
| `BrowseTags` | POST | `/api/v2/browseTags` | `historian/canary/tag/list` | `historian/canary/tag/list/response` | `body` |
| `GetTagProperties` | POST | `/api/v2/getTagProperties` | `historian/canary/tag-property/get` | `historian/canary/tag-property/get/response` | `body` |
| `GetTagData` | POST | `/api/v2/getTagData` | `historian/canary/tag-data/get` | `historian/canary/tag-data/get/response` | `body` |
| `GetAggregates` | POST | `/api/v2/getAggregates` | `historian/canary/aggregate/list` | `historian/canary/aggregate/list/response` | `body` |
| `GetAnnotations` | POST | `/api/v2/getAnnotations` | `historian/canary/annotation/get` | `historian/canary/annotation/get/response` | `body` |
| `GetLiveDataToken` | POST | `/api/v2/getLiveDataToken` | `historian/canary/live-token/create` | `historian/canary/live-token/create/response` | `body` |
| `GetLiveData` | POST | `/api/v2/getLiveData` | `historian/canary/live-data/get` | `historian/canary/live-data/get/response` | `body` |
| `RevokeLiveDataToken` | POST | `/api/v2/revokeLiveDataToken` | `historian/canary/live-token/delete` | `historian/canary/live-token/delete/response` | `body` |
| `GetEvents` | POST | `/api/v2/getEvents` | `historian/canary/event/list` | `historian/canary/event/list/response` | `body` |

## Deploy

Get the template card (JSON with `template` and `metadata`) from the broker, then deploy the connector:

```bash theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
mosquitto_pub -t '$SYS/Coreflux/Command' -m "-routeCode CANARY_READ"
```

The deployable connector from the REST API app, with `BASE_ADDRESS` already filled in:

```lot theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
DEFINE ROUTE CanaryRead WITH TYPE REST_API
    ADD REST_API_CONFIG
        WITH BASE_ADDRESS "https://YOUR_CANARY_HOST:55236"
        WITH ENABLE_CLIENT "true"
        WITH USE_SSL "true"
        WITH REQUEST_TIMEOUT '30'
        WITH DEFAULT_CONTENT_TYPE "application/json"
    ADD EVENT GetUserToken
        WITH SOURCE_TOPIC "historian/canary/user-token/create"
        WITH DESTINATION_TOPIC "historian/canary/user-token/create/response"
        WITH METHOD "POST"
        WITH ENDPOINT "/api/v2/getUserToken"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Content-Type" "application/json"
        WITH BODY "{value.json.body}"
    ADD EVENT RevokeUserToken
        WITH SOURCE_TOPIC "historian/canary/user-token/delete"
        WITH DESTINATION_TOPIC "historian/canary/user-token/delete/response"
        WITH METHOD "POST"
        WITH ENDPOINT "/api/v2/revokeUserToken"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Content-Type" "application/json"
        WITH BODY "{value.json.body}"
    ADD EVENT BrowseNodes
        WITH SOURCE_TOPIC "historian/canary/node/list"
        WITH DESTINATION_TOPIC "historian/canary/node/list/response"
        WITH METHOD "POST"
        WITH ENDPOINT "/api/v2/browseNodes"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Content-Type" "application/json"
        WITH BODY "{value.json.body}"
    ADD EVENT BrowseTags
        WITH SOURCE_TOPIC "historian/canary/tag/list"
        WITH DESTINATION_TOPIC "historian/canary/tag/list/response"
        WITH METHOD "POST"
        WITH ENDPOINT "/api/v2/browseTags"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Content-Type" "application/json"
        WITH BODY "{value.json.body}"
    ADD EVENT GetTagProperties
        WITH SOURCE_TOPIC "historian/canary/tag-property/get"
        WITH DESTINATION_TOPIC "historian/canary/tag-property/get/response"
        WITH METHOD "POST"
        WITH ENDPOINT "/api/v2/getTagProperties"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Content-Type" "application/json"
        WITH BODY "{value.json.body}"
    ADD EVENT GetTagData
        WITH SOURCE_TOPIC "historian/canary/tag-data/get"
        WITH DESTINATION_TOPIC "historian/canary/tag-data/get/response"
        WITH METHOD "POST"
        WITH ENDPOINT "/api/v2/getTagData"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Content-Type" "application/json"
        WITH BODY "{value.json.body}"
    ADD EVENT GetAggregates
        WITH SOURCE_TOPIC "historian/canary/aggregate/list"
        WITH DESTINATION_TOPIC "historian/canary/aggregate/list/response"
        WITH METHOD "POST"
        WITH ENDPOINT "/api/v2/getAggregates"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Content-Type" "application/json"
        WITH BODY "{value.json.body}"
    ADD EVENT GetAnnotations
        WITH SOURCE_TOPIC "historian/canary/annotation/get"
        WITH DESTINATION_TOPIC "historian/canary/annotation/get/response"
        WITH METHOD "POST"
        WITH ENDPOINT "/api/v2/getAnnotations"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Content-Type" "application/json"
        WITH BODY "{value.json.body}"
    ADD EVENT GetLiveDataToken
        WITH SOURCE_TOPIC "historian/canary/live-token/create"
        WITH DESTINATION_TOPIC "historian/canary/live-token/create/response"
        WITH METHOD "POST"
        WITH ENDPOINT "/api/v2/getLiveDataToken"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Content-Type" "application/json"
        WITH BODY "{value.json.body}"
    ADD EVENT GetLiveData
        WITH SOURCE_TOPIC "historian/canary/live-data/get"
        WITH DESTINATION_TOPIC "historian/canary/live-data/get/response"
        WITH METHOD "POST"
        WITH ENDPOINT "/api/v2/getLiveData"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Content-Type" "application/json"
        WITH BODY "{value.json.body}"
    ADD EVENT RevokeLiveDataToken
        WITH SOURCE_TOPIC "historian/canary/live-token/delete"
        WITH DESTINATION_TOPIC "historian/canary/live-token/delete/response"
        WITH METHOD "POST"
        WITH ENDPOINT "/api/v2/revokeLiveDataToken"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Content-Type" "application/json"
        WITH BODY "{value.json.body}"
    ADD EVENT GetEvents
        WITH SOURCE_TOPIC "historian/canary/event/list"
        WITH DESTINATION_TOPIC "historian/canary/event/list/response"
        WITH METHOD "POST"
        WITH ENDPOINT "/api/v2/getEvents"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Content-Type" "application/json"
        WITH BODY "{value.json.body}"
```

Deploy it with `-addRoute` (do not include `ADD METADATA`).

## Usage example

Call `GetUserToken` by publishing a JSON payload to its request topic, and read the reply on the response topic:

```bash theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
mosquitto_sub -t 'historian/canary/user-token/create/response' &
mosquitto_pub -t 'historian/canary/user-token/create' -m '{"body": {}}'
```

## Related

* [REST API Connectors](/latest/lot-language/routes/rest-api-routes)
* [REST API Apps catalog](/latest/lot-language/routes/rest-api-apps)


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