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

# GE Vernova Proficy Historian

> Client-mode REST API connector for GE Vernova Proficy Historian: get a Proficy Authentication (UAA) OAuth2 token, read current, raw, interpolated, calculated and sampled tag data, write samples from MQTT into the historian, and list, inspect, add, update and delete tags through the Historian REST API

Technical Preview

## Overview

Proficy Historian (GE Vernova, formerly GE Digital) stores plant time-series data. Its **Historian REST API** is installed with the Historian **web-based clients** and lives under `https://<host>/historian-rest-api/v1/`. Calls carry an OAuth2 bearer token issued by **Proficy Authentication** (UAA) on the same host at `/uaa/oauth/token`.

The **ProficyHistorian** connector covers the token request, server and system status, tag management, every read mode (current value, raw, interpolated, calculated, sampled) and writing samples with `datapoints/create`. Each event publishes the server's reply on `<topic>/response`.

| Event | Topic | Request | Notes |
| - | - | - | - |
| GetToken | `historian/proficy-historian/token/create` | `POST /uaa/oauth/token` | Proficy Authentication (UAA) client\_credentials token; authorization = Basic base64(client\_id:client\_secret) -> access\_token |
| GetUserToken | `historian/proficy-historian/user-token/create` | `POST /uaa/oauth/token` | Password grant for a Proficy Authentication user (e.g. client historian\_public\_rest\_api) -> access\_token |
| GetServerProperties | `historian/proficy-historian/server-property/get` | `GET /historian-rest-api/v1/serverproperties` | Storages, data stores and archiver services (connectivity probe) |
| GetSystemStats | `historian/proficy-historian/system-stat/get` | `GET /historian-rest-api/v1/systemstats` | Utilization, queue sizes, compression ratio |
| ListTags | `historian/proficy-historian/tag/list` | `GET /historian-rest-api/v1/tags?nameMask={nameMask}&maxNumber={maxNumber}` | Tag names matching a mask (\* and ?); maxNumber 0 = all, ErrorCode 14 = more tags than requested |
| ListTagsPaged | `historian/proficy-historian/tag-page/list` | `GET /historian-rest-api/v1/tagslist?{query}` | Tags with properties, paged (pageno, pagesize default 128, lastmodified); first/prev/next/last links |
| GetTagProperties | `historian/proficy-historian/tag-property/get` | `GET /historian-rest-api/v1/tags/properties/{tag}` | All properties of one tag (unknown tag returns an error) |
| AddTag | `historian/proficy-historian/tag/create` | `POST /historian-rest-api/v1/tags/addtag` | Add one tag; body needs Name + DataType (existing tag: new properties applied) |
| UpdateTagProperties | `historian/proficy-historian/tag-property/update` | `PUT /historian-rest-api/v1/tags/properties/{tag}` | Set tag properties, e.g. \{"Description": "..."} (no rename) |
| DeleteTag | `historian/proficy-historian/tag/delete` | `DELETE /historian-rest-api/v1/tags/{tag}?permanentDelete={permanentDelete}` | Delete a tag; permanentDelete true also removes it from the archive index |
| GetCurrentValue | `historian/proficy-historian/current-value/get` | `GET /historian-rest-api/v1/datapoints/currentvalue?tagNames={tagNames}` | Latest sample (TimeStamp, Value, Quality) per tag; tagNames separated by ; |
| GetRawData | `historian/proficy-historian/raw-data/get` | `GET /historian-rest-api/v1/datapoints/raw/{tagNames}/{start}/{end}/{direction}/{count}` | Raw samples; count 0 = by time, count > 0 = by number; direction 0 forward, 1 backward |
| GetInterpolatedData | `historian/proficy-historian/interpolated-data/get` | `GET /historian-rest-api/v1/datapoints/interpolated/{tagNames}/{start}/{end}/{count}/{intervalMs}` | Interpolated samples by count or interval |
| GetCalculatedData | `historian/proficy-historian/calculated-data/get` | `GET /historian-rest-api/v1/datapoints/calculated/{tagNames}/{start}/{end}/{calculationMode}/{count}/{intervalMs}` | Calculated samples (calculationMode 1 = Average, see CalculationModeType) |
| GetSampledData | `historian/proficy-historian/sampled-data/get` | `GET /historian-rest-api/v1/datapoints/sampled?{query}` | Any sampling mode via query (tagNames, start, end, samplingMode, calculationMode, direction, count, intervalMs) |
| CreateDataPoints | `historian/proficy-historian/data-point/create` | `POST /historian-rest-api/v1/datapoints/create` | Write samples: \{"TagName": ..., "samples": \[\{"TimeStamp", "Value", "Quality": 3}]} (REST API admin or write permission) |

## Prerequisites

1. Proficy Historian 8.x, 9.x, 2022, 2023 or 2024 (Windows) with the **web-based clients** installed. That install adds the Historian REST API and Proficy Authentication. The broker host must reach the web-based clients node on HTTPS port **443**. Historian 7.x used port **8443** for both the REST API and UAA.
2. A Proficy Authentication **client** (client ID and secret) for the `client_credentials` grant, or a Historian web user plus the `historian_public_rest_api` client for the password grant. Writes (`datapoints/create`, tag add / update / delete) need the REST API administrator or a user with write permission.
3. The certificate of the web-based clients node, trusted on the broker host. The default install uses a self-signed certificate.
4. Store the client credentials in a Hub secret, for example `PROFICY_HISTORIAN_CLIENT` holding `Basic <base64 of client_id:client_secret>`.

## Authentication

1. Publish `{ "authorization": "Basic <base64 of client_id:client_secret>" }` to `historian/proficy-historian/token/create`. The response carries `access_token`, `token_type` `bearer` and `expires_in` (seconds).
2. Send `"authorization": "Bearer <access_token>"` with every other event. Request a new token before `expires_in` runs out.

As an alternative, `historian/proficy-historian/user-token/create` uses the password grant: `client_id` (`historian_public_rest_api`), `client_secret` (set during install), `username` (default `<machinename>.admin`) and `password` go in the payload. It sends no `Authorization` header.

> [!WARNING]
>
> Keep client secrets and passwords in Hub secrets and add them with `GET SECRET`. Never put them in the connector file or in retained topics.

## Configuration

* Replace `YOUR_HISTORIAN_HOST` in `BASE_ADDRESS` with the web-based clients node. For Historian 7.x use `https://<host>:8443`.
* Tag names go into the URL as given. URL-encode special characters (`#` becomes `%23`). Separate several tags in `tagNames` with `;`.
* Timestamps are ISO 8601 UTC, for example `2026-10-05T07:00:00.000Z`.
* Responses are JSON `{ "ErrorCode": 0, "ErrorMessage": null, "Data": ... }`. Check `ErrorCode` as well as the HTTP status. `ErrorCode` `14` on the tag list means more tags exist than `maxNumber`.
* The server also serves Swagger UI at `https://<host>/historian-rest-api/swagger-ui.html` for the exact API of your version.

## Examples

Get the current value of two tags:

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
// publish to historian/proficy-historian/current-value/get
{ "authorization": "Bearer <token>", "tagNames": "Line1.Temperature;Line1.Pressure" }
// historian/proficy-historian/current-value/get/response
{ "ErrorCode": 0, "ErrorMessage": null,
  "Data": [{ "TagName": "Line1.Temperature", "ErrorCode": 0, "DataType": "DoubleFloat",
             "Samples": [{ "TimeStamp": "2026-10-05T06:59:58.000Z", "Value": "21.4", "Quality": 3 }] }, ...] }
```

Read raw samples for the last hour (`count` 0 reads by time; a positive `count` reads that many samples; `direction` 0 is forward):

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
// publish to historian/proficy-historian/raw-data/get
{ "authorization": "Bearer <token>", "tagNames": "Line1.Temperature",
  "start": "2026-10-05T06:00:00.000Z", "end": "2026-10-05T07:00:00.000Z", "direction": 0, "count": 0 }
```

Ten-minute averages (`calculationMode` 1 is Average):

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
// publish to historian/proficy-historian/calculated-data/get
{ "authorization": "Bearer <token>", "tagNames": "Line1.Temperature",
  "start": "2026-10-05T06:00:00.000Z", "end": "2026-10-05T07:00:00.000Z", "calculationMode": 1, "count": 0, "intervalMs": 600000 }
```

Write a sample from MQTT into the historian (`Quality` 3 is Good):

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
// publish to historian/proficy-historian/data-point/create
{ "authorization": "Bearer <token>",
  "body": { "TagName": "Coreflux.Line1.Temperature",
            "samples": [{ "TimeStamp": "2026-10-05T07:00:00.000Z", "Value": "21.4", "Quality": 3 }] } }
// historian/proficy-historian/data-point/create/response
{ "ErrorCode": 0, "ErrorMessage": "" }
```

Add a tag before writing to it (`Name` and `DataType` are required):

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
// publish to historian/proficy-historian/tag/create
{ "authorization": "Bearer <token>", "body": { "Name": "Coreflux.Line1.Temperature", "DataType": 3 } }
```

Example actions: refresh and keep the token, poll two tags, store an MQTT value in the historian, and a health check:

```lot theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
DEFINE ACTION ProficyRefreshToken
ON EVERY 1 HOUR DO
    SET "client" WITH GET SECRET "PROFICY_HISTORIAN_CLIENT"
    PUBLISH TOPIC "historian/proficy-historian/token/create" WITH { "authorization": {client} }

DEFINE ACTION ProficyKeepToken
ON TOPIC "historian/proficy-historian/token/create/response" DO
    SET "token" WITH GET JSON "access_token" IN PAYLOAD AS STRING
    KEEP TOPIC "internal/proficy-historian/authorization" WITH "Bearer " + {token}

DEFINE ACTION ProficyPollLine1
ON EVERY 10 SECONDS DO
    SET "auth" WITH GET TOPIC "internal/proficy-historian/authorization"
    PUBLISH TOPIC "historian/proficy-historian/current-value/get" WITH { "authorization": {auth}, "tagNames": "Line1.Temperature;Line1.Pressure" }

DEFINE ACTION ProficyStoreLine1Temperature
ON TOPIC "plant/line1/temperature" DO
    SET "auth" WITH GET TOPIC "internal/proficy-historian/authorization"
    SET "value" WITH PAYLOAD AS STRING
    SET "ts" WITH TIMESTAMP "UTC"
    PUBLISH TOPIC "historian/proficy-historian/data-point/create" WITH { "authorization": {auth}, "body": { "TagName": "Coreflux.Line1.Temperature", "samples": [ { "TimeStamp": {ts}, "Value": {value}, "Quality": 3 } ] } }

DEFINE ACTION ProficyHealthCheck
ON EVERY 5 MINUTES DO
    SET "auth" WITH GET TOPIC "internal/proficy-historian/authorization"
    PUBLISH TOPIC "historian/proficy-historian/system-stat/get" WITH { "authorization": {auth} }
```

## Testing

Technical preview, not yet live-tested. The app package's smoke script checks every event against GE Vernova's Historian 2024 REST API documentation (static) and runs every event against a local mock Historian (Proficy Authentication token endpoint with client credentials and password grant, bearer-protected REST API, tag add / update / delete and write → current value read-back), plus negative controls (no token, bad client secret, bad user password, expired token `401`; unknown tag `ErrorCode`; bad timestamp `400`; write without write permission `403`). A run against a real Proficy Historian server and a broker MQTT round-trip are still open. See `TEST.md` in the app package.

## Not covered

* POST variants of the read APIs (tagNames in the body), trend data (`datapoints/trend`), tag rename, add many tags (`tags/addtags`) and data store / collection settings. Use the same URL pattern with your own event if you need them.
* Systems administration (machines, mirror groups, storages, DHS services, performance counters), Historian model, collectors and collector instances, data stores, and alarms and events.
* Proficy Operations Hub, the Historian Web Admin console, the Historian SDK / User API / OLE DB provider, and Historian collectors (including the MQTT collector, which can ingest from this broker directly).

## Related

* [REST API connectors](/latest/lot-language/routes/rest-api-routes)
* [REST API app catalog](/latest/lot-language/routes/rest-api-apps/index)
* [Proficy Historian REST APIs: Managing Tags](https://www.gevernova.com/software/documentation/historian/version2024/r_managing_tags_apis.html)
* [Proficy Historian: About Security and Authentication](https://www.gevernova.com/software/documentation/historian/version2024/c_about_security_and_authentication.html)


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