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

# Seeq

> Client-mode REST API connector for Seeq: log in with an access key, push MQTT values into Seeq signals as samples, store alarms and events as capsules on Seeq conditions, read samples and capsules back, search items and run Seeq Formulas through the Seeq Server REST API

Technical Preview

## Overview

Seeq is an advanced analytics application for process manufacturing data. It connects to historians and other sources, and it can also **store** signals and conditions itself. The Seeq web application uses the **Seeq Server REST API** for everything, so anything you do in Workbench can be done through `https://<server>/api/`.

The **SeeqRestApi** connector covers login, server status, item search, stored signals (create, push samples, replace samples, read samples or one sample), stored conditions (create, add capsules, read capsules), Seeq Formula runs, and archiving. Typical uses: send MQTT readings that are not in any historian into a Seeq signal, store alarms or batch events from MQTT as capsules, and pull Seeq results (for example an aggregate) back onto the broker. Each event publishes the server's reply on `<topic>/response`.

| Event | Topic | Request | Notes |
| - | - | - | - |
| Login | `historian/seeq/session/create` | `POST /api/auth/login` | Access key as username + password (Seeq directory); session token comes back in the x-sq-auth response header, body = user |
| Logout | `historian/seeq/session/delete` | `DELETE /api/auth/logout` | Invalidate the session token |
| GetServerStatus | `historian/seeq/server-status/get` | `GET /api/system/server-status` | Server readiness and version (no token needed) |
| Ping | `historian/seeq/ping/get` | `GET /api/system/ping` | Authenticated readiness check; keeps the session alive |
| GetCurrentUser | `historian/seeq/user/get` | `GET /api/users/me` | User behind the token (token check) |
| SearchItems | `historian/seeq/item/search` | `GET /api/items?{query}` | Find signals / conditions / assets: filters=Name==Temperature\&types=StoredSignal\&limit=50 (URL-encoded) |
| GetItem | `historian/seeq/item/get` | `GET /api/items/{id}` | All properties of one item |
| CreateSignal | `historian/seeq/signal/create` | `POST /api/signals` | Create a signal stored in Seeq (name required; valueUnitOfMeasure, interpolationMethod, maximumInterpolation) -> id |
| GetSignal | `historian/seeq/signal/get` | `GET /api/signals/{id}` | Signal metadata |
| ArchiveSignal | `historian/seeq/signal/delete` | `DELETE /api/signals/{id}` | Archive a signal |
| AddSamples | `historian/seeq/sample/create` | `POST /api/signals/{id}/samples` | Push samples \{samples: \[\{key: ISO time, value}]} into a stored signal |
| ReplaceSamples | `historian/seeq/sample/update` | `PUT /api/signals/{id}/samples` | Replace samples in the same time range (optional interval \{start, end}) |
| GetSamples | `historian/seeq/sample/list` | `GET /api/signals/{id}/samples?start={start}&end={end}&limit={limit}` | Samples over an interval (start and end required); continuationToken for the next page |
| GetSample | `historian/seeq/sample/get` | `GET /api/signals/{id}/sample/{key}?lookup={lookup}` | One sample at or near a key; lookup AtOrBefore + now = latest value |
| CreateCondition | `historian/seeq/condition/create` | `POST /api/conditions` | Create a stored condition (name + maximumDuration, e.g. 1d) -> id |
| ArchiveCondition | `historian/seeq/condition/delete` | `DELETE /api/conditions/{id}` | Archive a condition and its capsules |
| AddCapsules | `historian/seeq/capsule/create` | `POST /api/conditions/{id}/capsules` | Store alarms / events as capsules \{capsules: \[\{start, end, properties}]} |
| GetCapsules | `historian/seeq/capsule/list` | `GET /api/conditions/{id}/capsules?start={start}&end={end}&limit={limit}` | Capsules in a time range |
| RunFormula | `historian/seeq/formula/run` | `POST /api/formulas/run` | Run a Seeq Formula \{formula, parameters: \["name=\<id>"], start, end} -> samples / capsules / scalar / table |
| RunFormulaQuery | `historian/seeq/formula-query/run` | `GET /api/formulas/run?{query}` | Same as RunFormula with a URL-encoded query (start, end, formula, parameters, limit) |

## Prerequisites

1. A Seeq server the broker host can reach. Seeq SaaS sites look like `https://<company>.seeq.site`. An on-premises server listens on `http://<host>:34216` by default, or on HTTPS behind 443 / 8443.
2. A Seeq **access key** and its password (profile menu → **Access Keys**). Access keys work with every directory, including OAuth 2.0 / OpenID Connect single sign-on. Access key creation is off by default for non-admin users (`Authentication/AccessKey/Creation/Enabled`). An admin can turn it on or create the key for you. A Seeq directory user name and password also work.
3. Write access to the signals and conditions you push to. A signal or condition created through this connector belongs to the access key's user and has global scope unless you set `scopedTo` to a workbook ID.

## Authentication

Seeq uses a **session token** in the `x-sq-auth` header:

1. Log in: publish `{ "body": { "username": "<access key>", "password": "<access key password>" } }` to `historian/seeq/session/create`. Leave `authProviderClass` and `authProviderId` out to use the Seeq directory, which access keys require. For a directory user (for example LDAP), set both to the directory's datasource class and ID from `GET /api/auth/providers`.
2. Seeq returns the token in the **`x-sq-auth` response header**. The response body (`historian/seeq/session/create/response`) is the user record, not the token. The connector publishes the body, so get the token another way, for example with a one-off call from the broker host, and store it as a Hub secret:

```bash theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
curl -s -D - -o /dev/null -X POST https://<server>/api/auth/login \
  -H "Accept: application/vnd.seeq.v1+json" -H "Content-Type: application/vnd.seeq.v1+json" \
  -d '{"username":"<access key>","password":"<access key password>"}' | grep -i '^x-sq-auth'
```

3. Send `"auth": "<token>"` with every other event. The connector puts it in the `x-sq-auth` header.
4. Seeq ends a session after a period of inactivity (the user's `sessionDuration`). A `Ping` every few minutes keeps it alive. A `401` on any response means the token has expired: log in again. Access keys also stop working when their user has not logged in to Seeq within `Authentication/AccessKey/ValidityWithoutUserLogin` (14 days by default).

`GetServerStatus` needs no token and is a good connectivity check.

> [!WARNING]
>
> Keep the access key, its password and the session token in Hub secrets and add them with `GET SECRET`. Never put them in the connector file or in retained topics.

## Configuration

* Replace `YOUR_SEEQ_SERVER` in `BASE_ADDRESS` with your Seeq host. For an on-premises server without TLS use `http://<host>:34216` and set `USE_SSL` to `"false"`.
* Every request sends `Accept: application/vnd.seeq.v1+json`, and every body uses `Content-Type: application/vnd.seeq.v1+json`. Seeq rejects other values: `406` for a different `Accept`, `415` for plain `application/json`. Keep these headers if you add your own events.
* Keys (timestamps) are ISO 8601, for example `2026-10-05T07:00:00Z`. Use `Z`. A `+hh:mm` offset in a query string must be URL-encoded (`%2B`).
* Signal, condition and item IDs are Seeq GUIDs. `CreateSignal` and `CreateCondition` return them in `id`. You can also find them with `SearchItems` (`filters=Name==Line1 Temperature&types=StoredSignal`) or copy them from Workbench (Item Properties).
* `GetSamples` and `GetCapsules` return at most `limit` entries. When more exist, the response carries a `continuationToken`.
* Errors are JSON `{ "statusMessage": "..." }`. `403` means the user lacks write access to the item, and `404` means the ID is unknown or archived.
* Seeq SaaS sits behind Cloudflare. Requests with the default Python `urllib` User-Agent are refused with Cloudflare error 1010. Requests with no User-Agent or a normal client User-Agent are accepted.

## Examples

Create a signal stored in Seeq for an MQTT value:

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
// publish to historian/seeq/signal/create
{ "auth": "<token>",
  "body": { "name": "Coreflux Line1 Temperature", "valueUnitOfMeasure": "degC",
            "interpolationMethod": "Linear", "maximumInterpolation": "1h" } }
// historian/seeq/signal/create/response (shortened)
{ "id": "0EF2C1F0-6E6B-7AF0-9C1A-2B3C4D5E6F70", "name": "Coreflux Line1 Temperature", "type": "StoredSignal", ... }
```

Push samples into the signal:

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
// publish to historian/seeq/sample/create
{ "auth": "<token>", "id": "<signal id>",
  "body": { "samples": [{ "key": "2026-10-05T07:00:00Z", "value": 21.4 }, { "key": "2026-10-05T07:00:10Z", "value": 21.5 }] } }
```

Read the last hour back (`start` and `end` are required):

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
// publish to historian/seeq/sample/list
{ "auth": "<token>", "id": "<signal id>", "start": "2026-10-05T06:00:00Z", "end": "2026-10-05T07:00:00Z", "limit": 1000 }
// historian/seeq/sample/list/response
{ "samples": [{ "key": "2026-10-05T06:00:10Z", "value": 20.9 }, ...], "valueUnitOfMeasure": "degC", "limit": 1000 }
```

Store an alarm as a capsule on a stored condition (create it first with `historian/seeq/condition/create` and `{ "name": "Line1 Alarms", "maximumDuration": "1d" }`):

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
// publish to historian/seeq/capsule/create
{ "auth": "<token>", "id": "<condition id>",
  "body": { "capsules": [{ "start": "2026-10-05T06:40:00Z", "end": "2026-10-05T06:55:00Z",
                            "properties": [{ "name": "Alarm", "value": "HighTemp", "unitOfMeasure": "string" }] }] } }
```

Run a Seeq Formula, here hourly averages of a signal (`parameters` binds `$t` to a signal ID):

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
// publish to historian/seeq/formula/run
{ "auth": "<token>",
  "body": { "formula": "$t.aggregate(average(), hours(), startKey())", "parameters": ["t=<signal id>"],
            "start": "2026-10-05T00:00:00Z", "end": "2026-10-05T07:00:00Z" } }
```

Example actions: keep the session alive, remember the IDs of new items, push an MQTT value as a sample, store a closed alarm as a capsule, and poll the latest value:

```lot theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
DEFINE ACTION SeeqKeepAlive
ON EVERY 5 MINUTES DO
    SET "auth" WITH GET SECRET "SEEQ_AUTH_TOKEN"
    PUBLISH TOPIC "historian/seeq/ping/get" WITH { "auth": {auth} }

DEFINE ACTION SeeqRememberSignalId
ON TOPIC "historian/seeq/signal/create/response" DO
    SET "id" WITH (GET JSON "id" IN PAYLOAD AS STRING)
    KEEP TOPIC "internal/seeq/signal-id/line1-temperature" WITH {id}

DEFINE ACTION SeeqRememberConditionId
ON TOPIC "historian/seeq/condition/create/response" DO
    SET "id" WITH (GET JSON "id" IN PAYLOAD AS STRING)
    KEEP TOPIC "internal/seeq/condition-id/line1-alarms" WITH {id}

DEFINE ACTION SeeqPushLine1Temperature
ON TOPIC "plant/line1/temperature" DO
    SET "auth" WITH GET SECRET "SEEQ_AUTH_TOKEN"
    SET "sid" WITH GET TOPIC "internal/seeq/signal-id/line1-temperature"
    SET "value" WITH PAYLOAD AS DOUBLE
    SET "ts" WITH TIMESTAMP "UTC"
    PUBLISH TOPIC "historian/seeq/sample/create" WITH { "auth": {auth}, "id": {sid}, "body": { "samples": [ { "key": {ts}, "value": {value} } ] } }

DEFINE ACTION SeeqStoreAlarmCapsule
ON TOPIC "plant/line1/alarm/closed" DO
    SET "auth" WITH GET SECRET "SEEQ_AUTH_TOKEN"
    SET "cid" WITH GET TOPIC "internal/seeq/condition-id/line1-alarms"
    SET "start" WITH (GET JSON "start" IN PAYLOAD AS STRING)
    SET "end" WITH (GET JSON "end" IN PAYLOAD AS STRING)
    SET "alarm" WITH (GET JSON "alarm" IN PAYLOAD AS STRING)
    PUBLISH TOPIC "historian/seeq/capsule/create" WITH { "auth": {auth}, "id": {cid}, "body": { "capsules": [ { "start": {start}, "end": {end}, "properties": [ { "name": "Alarm", "value": {alarm}, "unitOfMeasure": "string" } ] } ] } }

DEFINE ACTION SeeqPollLatestTemperature
ON EVERY 1 MINUTE DO
    SET "auth" WITH GET SECRET "SEEQ_AUTH_TOKEN"
    SET "sid" WITH GET TOPIC "internal/seeq/signal-id/line1-temperature"
    SET "now" WITH TIMESTAMP "UTC"
    PUBLISH TOPIC "historian/seeq/sample/get" WITH { "auth": {auth}, "id": {sid}, "key": {now}, "lookup": "AtOrBefore" }
```

`TIMESTAMP "UTC"` must give an ISO 8601 time for Seeq to accept the sample key. Check the format on your broker version before you rely on it.

## Testing

Technical preview, not yet live-tested. The app package's smoke script checks every event against the official Seeq Python SDK 66.208 (method, path, path and query parameters, body model, media types) and runs every event against a local mock Seeq Server. The mock run covers login with the token in the `x-sq-auth` response header, signal create → samples add / replace → read-back → latest sample, condition create → capsule add → read-back, formula run, archive and logout. Negative controls cover no, bad or logged-out tokens and a wrong password (`401`), wrong `Accept` (`406`), plain JSON (`415`), an unknown ID (`404`), a missing `start` (`400`), a write without permission (`403`), a capsule that ends before it starts (`400`) and an unbound formula variable (`400`). Unauthenticated calls against a real Seeq R66 server returned the expected results: open ping and server status `200`, `406` and `415` for the wrong media types, `401` for a bogus login, and `401` for every token event with a fake or empty token. A run with a real access key and a broker MQTT round-trip are still open. See `TEST.md` in the app package.

## Not covered

* Getting the session token inside the broker. Seeq returns it in the `x-sq-auth` response header, and the connector publishes only the response body (see Authentication).
* Workbooks, worksheets, Organizer topics and reports, assets and asset trees, signal / condition / scalar batch upserts, datasource-ID endpoints (`/signals/{datasourceClass}/{datasourceId}/{dataId}`) and calculated items. Use the same URL pattern and headers with your own event if you need them.
* Seeq Data Lab, SPy, Data Lab Functions, Add-ons and the Seeq Connector SDK.
* OData export (`/odata.svc`), which authenticates with the access key and its password directly.

## Related

* [REST API connectors](/latest/lot-language/routes/rest-api-routes)
* [REST API app catalog](/latest/lot-language/routes/rest-api-apps/index)
* [Seeq APIs and SDKs](https://support.seeq.com/latest/cloud/seeq-apis-and-sdks)
* [Working with Access Keys](https://support.seeq.com/latest/cloud/working-with-access-keys)


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