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

# Critical Manufacturing MES

> Client-mode REST API connector for Critical Manufacturing MES: track materials in and out, hold and release, record losses, log machine state events and post data collection readings from MQTT, and read materials, dispatch lists, resources and production orders through the MES REST API

Technical Preview

## Overview

[Critical Manufacturing MES](https://www.criticalmanufacturing.com/) (CM MES) runs material tracking, dispatch, resources, data collection and quality for complex discrete and semiconductor plants. Every MES service is exposed as REST on the MES host. This connector lets plant logic on MQTT track materials in and out, post machine readings and log machine state changes, without custom code.

**CriticalManufacturingMesApi** (`CriticalManufacturingMesRestApi.lot`) is one client connector on `https://YOUR_CMF_SERVER` with 37 events: 2 Security Portal token events, 17 reads and 18 writes. No event deletes, terminates or removes anything.

> [!NOTE]
>
> The events follow CM's public [REST API catalog](https://developer.criticalmanufacturing.com/11.2/reference/api-rest/index.html), which publishes one Swagger 2.0 file per service (for example `Material.swagger.json`), and the [Host API reference](https://developer.criticalmanufacturing.com/11.2/reference/api-host/index.html) for input and business objects. The catalog has 66 services and about 2,000 operations. This app packages the shop-floor slice. To add another operation, copy an event and change the endpoint to `/api/<Service>/<Operation>`.

## Server host

CM MES is installed per customer, on premises or hosted by CM. Replace `YOUR_CMF_SERVER` with the host of your MES UI, with no trailing slash. REST services live under `/api/<Service>/<Operation>`. The Security Portal is on the same host under `/SecurityPortal`. If your Security Portal runs on a different host, copy the two token events into a second connector on that host.

## Authentication

> [!WARNING]
>
> A Personal Access Token (PAT) acts as its MES user. Keep PATs and client secrets in Hub secrets, map them in with `GET SECRET`, and never publish them on a topic other clients can read.

CM MES uses the Security Portal (OAuth 2.0). Pick one of these:

1. **Personal Access Token.** In the MES UI, open your **User Profile** and create an access token for the Coreflux service user. Publish `{"tenant": "<TenantName>", "client_id": "MES", "pat": "<PAT>"}` on `mes/critical-manufacturing-mes/token/create`. The Security Portal validates the PAT with the `refresh_token` grant and returns a Bearer `access_token`. Use the Security Portal client ID set on your environment (`/Cmf/System/Configuration/SecurityPortal/ClientId/`, usually `MES`).
2. **Client credentials.** For application-to-application calls with no user, publish `{"tenant": "<TenantName>", "client_id": "<id>", "client_secret": "<secret>"}` on `mes/critical-manufacturing-mes/token-client/create`.

Then send `"authorization": "Bearer <access_token>"` in every other payload. Tokens expire, so request a new one on a timer (the example actions use 30 minutes).

A PAT does **not** work as a Bearer token. CM's community answer is to send it with Basic authentication instead, as `"authorization": "Basic <base64 of <PAT>:>"`, that is the PAT as user name with an empty password. That form comes from a community answer and has not been tested here. The token flow is the documented path.

`TenantName` is the tenant configured for your environment. Calls run with the MES roles and data groups of the PAT owner or client application.

Suggested secrets: `CMF_PAT` and `CMF_TENANT`, or `CMF_CLIENT_ID` and `CMF_CLIENT_SECRET`.

## Payload conventions

* **Body.** Almost every service is `POST`. `"body"` is sent unchanged as the operation's input object, with the PascalCase properties from the Swagger file, for example `ComplexTrackInMaterialInput` has `Material`, `Resource`, `CurrentDataCollectionPoints` and `SkipDCValidation`.
* **Entity references.** Reference materials, resources and other entities by `Name` (or `Id`) with a `"$type"`, for example `{"$type": "Cmf.Navigo.BusinessObjects.Material, Cmf.Navigo.BusinessObjects", "Name": "MAT-0001"}`. Resources use `Cmf.Navigo.BusinessObjects.Resource`, state models `Cmf.Foundation.BusinessObjects.StateModel, Cmf.Foundation.BusinessObjects`.
* **Readings.** A data collection point is `{"$type": "Cmf.Navigo.BusinessObjects.DataCollectionPoint, Cmf.Navigo.BusinessObjects", "TargetEntity": {"$type": "Cmf.Navigo.BusinessObjects.Parameter, Cmf.Navigo.BusinessObjects", "Name": "Temperature"}, "Value": 72.4, "ReadingNumber": 1, "SampleId": "Sample 1"}`.
* **Losses.** Loss lines are `LossBonusAffectedQuantity` objects with `Reason` and `ReasonPrimaryQuantity`. Hold lines are `MaterialHoldReason` objects with `TargetEntity` (the reason) and `Comment`.
* **Enums.** Enums are integers, for example `Direction` 0 Ascendant / 1 Descendant on `GetMaterialGenealogy`, and `ComplexPerformDataCollectionMode` 0 Material, 1 Resource, 2 first material in the resource, 3 all materials in the resource.
* **Query.** `GetObjectByName` and `GetObjectById` take `"query"` as the URL query string, for example `"query": "Type=Material&Name=MAT-0001&LevelsToLoad=1"`.
* **Token form.** The token body is form-encoded with raw substitution, so keep the tenant, client ID and secret free of `&` and `=`.

> [!NOTE]
>
> Two details are not shown in the public Swagger files: the exact `Type` value `GetObjectByName` expects (a short name such as `Material`, or the URL-encoded type name), and whether your host needs `"$type"` on every reference. The `"$type"` form matches CM's Connect IoT workflow samples. Check both against your MES before going live.

## Events

### Tokens and session

| Event | Request | Topic | Notes |
| - | - | - | - |
| GetTokenFromPat | `POST /SecurityPortal/api/tenant/{tenant}/oauth2/token` | `mes/critical-manufacturing-mes/token/create` | Exchange a Personal Access Token (User Profile > Access Tokens) for a Bearer access\_token with the refresh\_token grant; calls run as the PAT owner |
| GetTokenClientCredentials | `POST /SecurityPortal/api/tenant/{tenant}/oauth2/token` | `mes/critical-manufacturing-mes/token-client/create` | OAuth 2.0 client credentials grant for application-to-application calls with no user (Client Id / Secret configured on the environment) |
| Echo | `GET /api/Security/Echo` | `mes/critical-manufacturing-mes/echo/get` | Security Echo: connectivity and token check (returns a string) |
| GetCurrentUser | `POST /api/Security/GetCurrentUser` | `mes/critical-manufacturing-mes/current-user/get` | The MES user behind the token (PAT owner or client application) |

### Generic objects and saved queries

| Event | Request | Topic | Notes |
| - | - | - | - |
| GetObjectByName | `GET /api/GenericService/GetObjectByName?{query}` | `mes/critical-manufacturing-mes/object/get` | Any entity by type and name (query: Type, Name, Revision, Version, LevelsToLoad). The Type format is not shown in the spec: see caveats |
| GetObjectById | `GET /api/GenericService/GetObjectById?{query}` | `mes/critical-manufacturing-mes/object-id/get` | Any entity by type and Id (query: Type, Id, LevelsToLoad) |
| ExecuteQueryByName | `POST /api/Query/ExecuteQueryByName` | `mes/critical-manufacturing-mes/query/execute` | Run a saved MES query by name with parameters (read) |

### Materials, dispatch lists and production orders (read)

| Event | Request | Topic | Notes |
| - | - | - | - |
| GetMaterialBasicInformation | `POST /api/Material/GetMaterialBasicInformation` | `mes/critical-manufacturing-mes/material/get` | Material state, step, flow, quantity, resource and container relations |
| GetMaterialHistory | `POST /api/Material/GetMaterialHistory` | `mes/critical-manufacturing-mes/material-history/get` | Material operation history (optional Filters) |
| GetMaterialGenealogy | `POST /api/Material/GetMaterialGenealogy` | `mes/critical-manufacturing-mes/material-genealogy/get` | Material genealogy; Direction 0 Ascendant, 1 Descendant (required), optional StartDate |
| GetDispatchListForResource | `POST /api/Dispatch/GetDispatchListForResource` | `mes/critical-manufacturing-mes/dispatch-list/get` | Materials dispatchable to a resource (the machine work queue) |
| GetMaterialsForProductionOrder | `POST /api/Order/GetMaterialsForProductionOrder` | `mes/critical-manufacturing-mes/production-order-materials/list` | Materials of a production order (optional MaterialNameFilter, FilterCollection) |

### Material transactions (write)

| Event | Request | Topic | Notes |
| - | - | - | - |
| DispatchMaterial | `POST /api/Material/DispatchMaterial` | `mes/critical-manufacturing-mes/material/dispatch` | **Write.** Dispatch a material to a resource |
| TrackInMaterial | `POST /api/Material/TrackInMaterial` | `mes/critical-manufacturing-mes/material/track-in` | **Write.** Track-In a material at a resource (simple transaction) |
| ComplexTrackInMaterial | `POST /api/Material/ComplexTrackInMaterial` | `mes/critical-manufacturing-mes/material-complex/track-in` | **Write.** Track-In with data collection points, checklist, recipe and instruments in one call (what the MES UI wizard uses) |
| ComplexDispatchAndTrackInMaterial | `POST /api/Material/ComplexDispatchAndTrackInMaterial` | `mes/critical-manufacturing-mes/material/dispatch-track-in` | **Write.** Dispatch and Track-In in one call |
| TrackOutMaterial | `POST /api/Material/TrackOutMaterial` | `mes/critical-manufacturing-mes/material/track-out` | **Write.** Track-Out a material (simple transaction) |
| ComplexTrackOutMaterial | `POST /api/Material/ComplexTrackOutMaterial` | `mes/critical-manufacturing-mes/material-complex/track-out` | **Write.** Track-Out with losses, bonuses, data collection points and checklist parameters |
| ComplexTrackOutAndMoveMaterialToNextStep | `POST /api/Material/ComplexTrackOutAndMoveMaterialToNextStep` | `mes/critical-manufacturing-mes/material/track-out-move` | **Write.** Track-Out and move to the next step (optional FlowPath) |
| MoveMaterialToNextStep | `POST /api/Material/MoveMaterialToNextStep` | `mes/critical-manufacturing-mes/material/move-next` | **Write.** Move-Next a material (optional FlowPath) |
| AbortMaterialProcess | `POST /api/Material/AbortMaterialProcess` | `mes/critical-manufacturing-mes/material/abort` | **Write.** Abort a tracked-in material process (back to queued; nothing is deleted) |
| HoldMaterial | `POST /api/Material/HoldMaterial` | `mes/critical-manufacturing-mes/material/hold` | **Write.** Put a material on hold with hold reasons |
| ReleaseMaterial | `POST /api/Material/ReleaseMaterial` | `mes/critical-manufacturing-mes/material/release` | **Write.** Release hold reasons from a material |
| RecordMaterialLoss | `POST /api/Material/RecordMaterialLoss` | `mes/critical-manufacturing-mes/material-loss/post` | **Write.** Record scrap / loss quantities with loss reasons |
| ChangeMaterialQuantity | `POST /api/Material/ChangeMaterialQuantity` | `mes/critical-manufacturing-mes/material-quantity/change` | **Write.** Change a material's primary / secondary quantity with a reason |
| LogMaterialEvent | `POST /api/Material/LogMaterialEvent` | `mes/critical-manufacturing-mes/material-event/post` | **Write.** Log a material state model transition |

### Resources (machines)

| Event | Request | Topic | Notes |
| - | - | - | - |
| GetResourceByName | `POST /api/Resource/GetResourceByName` | `mes/critical-manufacturing-mes/resource/get` | One resource (machine / line / area equipment) by name |
| GetResourceMaterialInformation | `POST /api/Resource/GetResourceMaterialInformation` | `mes/critical-manufacturing-mes/resource-materials/get` | Materials in process / dispatched at a resource |
| GetResourcePossibleTransitions | `POST /api/Resource/GetResourcePossibleTransitions` | `mes/critical-manufacturing-mes/resource-transitions/get` | State transitions allowed from the resource's current state (names for LogResourceEvent) |
| GetResourceKPIs | `POST /api/Resource/GetResourceKPIs` | `mes/critical-manufacturing-mes/resource-kpi/get` | KPIs of a resource |
| LogResourceEvent | `POST /api/Resource/LogResourceEvent` | `mes/critical-manufacturing-mes/resource-event/post` | **Write.** Log a resource state transition (machine state change, for example Productive to Standby) |

### Data collection (EDC)

| Event | Request | Topic | Notes |
| - | - | - | - |
| GetDataCollectionInstancesForMaterial | `POST /api/DataCollection/GetDataCollectionInstancesForMaterial` | `mes/critical-manufacturing-mes/dc-instance-material/list` | Open data collection instances of a material |
| GetDataCollectionInstancesForResource | `POST /api/DataCollection/GetDataCollectionInstancesForResource` | `mes/critical-manufacturing-mes/dc-instance-resource/list` | Open data collection instances of a resource |
| GetDataCollectionPointsAsDataSet | `POST /api/DataCollection/GetDataCollectionPointsAsDataSet` | `mes/critical-manufacturing-mes/dc-points/get` | Points already posted on a data collection instance |
| PostDataCollectionPoints | `POST /api/DataCollection/PostDataCollectionPoints` | `mes/critical-manufacturing-mes/dc-points/post` | **Write.** Post readings (parameter, value, reading number, sample) to an open data collection instance |
| ComplexPerformDataCollection | `POST /api/DataCollection/ComplexPerformDataCollection` | `mes/critical-manufacturing-mes/data-collection/post` | **Write.** Ad-hoc data collection in one call; ComplexPerformDataCollectionMode 0 Material, 1 Resource, 2 first material in resource, 3 all materials in resource |

### Production orders (write)

| Event | Request | Topic | Notes |
| - | - | - | - |
| ReleaseProductionOrders | `POST /api/Order/ReleaseProductionOrders` | `mes/critical-manufacturing-mes/production-order/release` | **Write.** Release production orders to the shop floor |

Every event replies on its topic plus `/response`.

## Example: connector excerpt

```lot theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
DEFINE ROUTE CriticalManufacturingMesApi WITH TYPE REST_API
    ADD REST_API_CONFIG
        WITH BASE_ADDRESS "https://YOUR_CMF_SERVER"
        WITH ENABLE_CLIENT "true"
        WITH USE_SSL "true"
        WITH REQUEST_TIMEOUT '60'
        WITH DEFAULT_CONTENT_TYPE "application/json"
    ADD EVENT GetTokenFromPat
        WITH SOURCE_TOPIC "mes/critical-manufacturing-mes/token/create"
        WITH DESTINATION_TOPIC "mes/critical-manufacturing-mes/token/create/response"
        WITH METHOD "POST"
        WITH ENDPOINT "/SecurityPortal/api/tenant/{value.json.tenant}/oauth2/token"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Content-Type" "application/x-www-form-urlencoded"
        WITH BODY "grant_type=refresh_token&client_id={value.json.client_id}&refresh_token={value.json.pat}"
    ADD EVENT ComplexTrackInMaterial
        WITH SOURCE_TOPIC "mes/critical-manufacturing-mes/material-complex/track-in"
        WITH DESTINATION_TOPIC "mes/critical-manufacturing-mes/material-complex/track-in/response"
        WITH METHOD "POST"
        WITH ENDPOINT "/api/Material/ComplexTrackInMaterial"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Content-Type" "application/json"
            ADD "Authorization" "{value.json.authorization}"
        WITH BODY "{value.json.body}"
```

## Example: plant actions

These actions get a token every 30 minutes, keep it on an internal topic, track a material in and out when the press loads and finishes it, send the press temperature to an ad-hoc data collection, log machine state transitions and poll the dispatch list.

```lot theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
DEFINE ACTION CmfMesLogin
ON EVERY 30 MINUTES DO
    SET "pat" WITH GET SECRET "CMF_PAT"
    SET "tenant" WITH GET SECRET "CMF_TENANT"
    PUBLISH TOPIC "mes/critical-manufacturing-mes/token/create" WITH { "tenant": {tenant}, "client_id": "MES", "pat": {pat} }

DEFINE ACTION CmfMesKeepToken
ON TOPIC "mes/critical-manufacturing-mes/token/create/response" DO
    SET "token" WITH GET JSON "access_token" IN PAYLOAD AS STRING
    KEEP TOPIC "internal/critical-manufacturing-mes/authorization" WITH "Bearer " + {token}

DEFINE ACTION CmfMesTrackIn
ON TOPIC "porto/line1/press01/material-loaded" DO
    SET "auth" WITH GET TOPIC "internal/critical-manufacturing-mes/authorization" AS STRING
    SET "mat" WITH PAYLOAD AS STRING
    PUBLISH TOPIC "mes/critical-manufacturing-mes/material-complex/track-in" WITH { "authorization": {auth}, "body": { "Material": { "$type": "Cmf.Navigo.BusinessObjects.Material, Cmf.Navigo.BusinessObjects", "Name": {mat} }, "Resource": { "$type": "Cmf.Navigo.BusinessObjects.Resource, Cmf.Navigo.BusinessObjects", "Name": "PRESS-01" } } }

DEFINE ACTION CmfMesTrackOut
ON TOPIC "porto/line1/press01/material-done" DO
    SET "auth" WITH GET TOPIC "internal/critical-manufacturing-mes/authorization" AS STRING
    SET "mat" WITH PAYLOAD AS STRING
    PUBLISH TOPIC "mes/critical-manufacturing-mes/material-complex/track-out" WITH { "authorization": {auth}, "body": { "Material": { "$type": "Cmf.Navigo.BusinessObjects.Material, Cmf.Navigo.BusinessObjects", "Name": {mat} } } }

DEFINE ACTION CmfMesTemperatureToEdc
ON TOPIC "porto/line1/press01/temperature" DO
    SET "auth" WITH GET TOPIC "internal/critical-manufacturing-mes/authorization" AS STRING
    SET "temp" WITH PAYLOAD AS DOUBLE
    PUBLISH TOPIC "mes/critical-manufacturing-mes/data-collection/post" WITH { "authorization": {auth}, "body": { "DataCollection": { "$type": "Cmf.Navigo.BusinessObjects.DataCollection, Cmf.Navigo.BusinessObjects", "Name": "PRESS-01 Process" }, "ComplexPerformDataCollectionMode": 1, "Resource": { "$type": "Cmf.Navigo.BusinessObjects.Resource, Cmf.Navigo.BusinessObjects", "Name": "PRESS-01" }, "DataCollectionPointCollection": [ { "$type": "Cmf.Navigo.BusinessObjects.DataCollectionPoint, Cmf.Navigo.BusinessObjects", "TargetEntity": { "$type": "Cmf.Navigo.BusinessObjects.Parameter, Cmf.Navigo.BusinessObjects", "Name": "Temperature" }, "Value": {temp}, "ReadingNumber": 1, "SampleId": "Sample 1" } ] } }

DEFINE ACTION CmfMesMachineState
ON TOPIC "porto/line1/press01/state-transition" DO
    SET "auth" WITH GET TOPIC "internal/critical-manufacturing-mes/authorization" AS STRING
    SET "transition" WITH PAYLOAD AS STRING
    PUBLISH TOPIC "mes/critical-manufacturing-mes/resource-event/post" WITH { "authorization": {auth}, "body": { "Resource": { "$type": "Cmf.Navigo.BusinessObjects.Resource, Cmf.Navigo.BusinessObjects", "Name": "PRESS-01" }, "StateModel": { "$type": "Cmf.Foundation.BusinessObjects.StateModel, Cmf.Foundation.BusinessObjects", "Name": "SEMI E10" }, "StateModelTransition": { "$type": "Cmf.Foundation.BusinessObjects.StateModelTransition, Cmf.Foundation.BusinessObjects", "Name": {transition} }, "Reason": "Machine signal" } }

DEFINE ACTION CmfMesDispatchPoll
ON EVERY 5 MINUTES DO
    SET "auth" WITH GET TOPIC "internal/critical-manufacturing-mes/authorization" AS STRING
    PUBLISH TOPIC "mes/critical-manufacturing-mes/dispatch-list/get" WITH { "authorization": {auth}, "body": { "Resource": { "$type": "Cmf.Navigo.BusinessObjects.Resource, Cmf.Navigo.BusinessObjects", "Name": "PRESS-01" }, "LevelsToLoad": 1 } }
```

## Not packaged

* Every `Delete*`, `Remove*`, `Terminate*` and `Unterminate*` operation, by policy.
* Master data and configuration (`Create*`, `FullUpdate*`, `Update*` of products, flows, recipes, roles and data collections).
* `/api/Security/Login`. It is not in the public REST catalog; use the Security Portal token endpoint.
* Outbound webhooks. CM's public documentation lists no outbound webhook feature, so no receiver connector is packaged. Pushing MES events to MQTT is a job for Connect IoT or integration entries, configured inside MES.

## Status

| Check | Result |
| - | - |
| Static checks and local mock | Passed (see `TEST.md` in the package) |
| Public sources | The developer portal Swagger files and the Security Portal help page are reachable without a login |
| `lot_lint` | Passed for the connector and the example actions |
| Live CM MES server | Not run: no server, tenant or PAT was available |

The connector stays **blocked** until it is checked against a real CM MES 11.x server with the Security Portal: a token from a PAT, `Echo`, `GetCurrentUser`, `GetResourceByName` and `GetMaterialBasicInformation`, and a Track-In / Track-Out of a test material.

## Related

* [REST API connectors](/latest/lot-language/routes/rest-api-routes)
* [REST API app catalog](/latest/lot-language/routes/rest-api-apps/index)


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