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

# Infraspeak

> Client-mode REST API connector for Infraspeak maintenance management: create work orders from alarms, list open and closed work orders, update and archive them, read assets with their metering statistics, sync assets, and reschedule planned job orders

Technical Preview

## Overview

Infraspeak is a maintenance management platform (CMMS) for work orders, planned maintenance, assets, locations, stock and procurement. Its **Public REST API v3** (`https://api.infraspeak.com/v3`) is documented on the [Infraspeak Developer Portal](https://developer.infraspeak.com/documentation), with an official OpenAPI spec behind the [API Reference](https://developer.infraspeak.com/api-reference).

The API uses Infraspeak's own names for some objects. A work order is a **Failure** (`/failures`), an asset is an **Element** (`/elements`), a planned job is a **Work** (`/works`), and a planned job order is a **Scheduled Work** (`/works/scheduled`). The topics below use the names you see in the Infraspeak app (`work-order`, `asset`, `planned-job`, `planned-job-order`).

The **InfraspeakApi** connector maps 22 MQTT topics onto that API. Typical uses: open a work order when an alarm is raised, add live readings to its observations, poll open work orders back onto the broker, read an asset's metering statistics, and move a planned job order when a line stops. Each event publishes the Infraspeak reply on `<topic>/response`.

| Event | Topic | Request | Use |
| - | - | - | - |
| `ListLocations` | `cmms/infraspeak/location/list` | `GET /v3/locations?{query}` | Locations (buildings, folders, locations); smoke: cheapest token check, e.g. query limit=1 or s\_code=HQ.F1.R101 |
| `GetLocation` | `cmms/infraspeak/location/get` | `GET /v3/locations/{id}` | One location by id |
| `ListClients` | `cmms/infraspeak/client/list` | `GET /v3/clients?{query}` | Clients (client\_id is required to create a work order) |
| `ListOperators` | `cmms/infraspeak/operator/list` | `GET /v3/operators?{query}` | Operators (technicians / users) |
| `ListProblemAreas` | `cmms/infraspeak/problem-area/list` | `GET /v3/problems?{query}` | Problem Areas (e.g. HVAC, Electric); query filter\[client\_id]=... optional |
| `ListProblemTypes` | `cmms/infraspeak/problem-type/list` | `GET /v3/problems/{id}/subproblems` | Problem Types of an Area (id = area id); their problem\_id goes into CreateWorkOrder |
| `ListCategories` | `cmms/infraspeak/category/list` | `GET /v3/categories?{query}` | Asset categories ('folder-like'); category\_id is required to create an asset |
| `ListAssets` | `cmms/infraspeak/asset/list` | `GET /v3/elements?{query}` | Assets (Infraspeak Elements), e.g. query s\_local\_id=4456257\&limit=50 or s\_code=PUMP-101 |
| `GetAsset` | `cmms/infraspeak/asset/get` | `GET /v3/elements/{id}?{query}` | One asset; query showMeteringData=true adds metering statistics (min / max / avg / last value), or "" |
| `CreateAsset` | `cmms/infraspeak/asset/create` | `POST /v3/elements` | body \{category\_id, local\_id, maintenance\_policy\_id (required), code?, observation?, bar\_code?, nfc\_code?, latitude?, longitude?, ...} |
| `UpdateAsset` | `cmms/infraspeak/asset/update` | `PATCH /v3/elements/{id}` | Change only the fields sent (local\_id to relocate, observation, code, stoppage\_cost, ...) |
| `CreateWorkOrder` | `cmms/infraspeak/work-order/create` | `POST /v3/failures` | Work order (Infraspeak Failure) from an alarm: body \{client\_id, problem\_id, priority 1-4, local\_id (required), description, observations, ...} |
| `ListWorkOrders` | `cmms/infraspeak/work-order/list` | `GET /v3/failures?{query}` | All work orders, e.g. query s\_state=WAITING\_RESOLUTION or s\_state\_in=WAITING\_RESOLUTION,IN\_RESOLUTION\&s\_local\_id=300 |
| `ListOpenWorkOrders` | `cmms/infraspeak/work-order-open/list` | `GET /v3/failures/open?{query}` | Open work orders (not COMPLETED / ARCHIVED), e.g. query s\_priority=4\&sort=created\_at |
| `ListClosedWorkOrders` | `cmms/infraspeak/work-order-closed/list` | `GET /v3/failures/closed?{query}` | Closed (COMPLETED) work orders, e.g. query date\_min\_completed\_date=2026-10-01T00:00:00 |
| `GetWorkOrder` | `cmms/infraspeak/work-order/get` | `GET /v3/failures/{id}?{query}` | One work order by failure id (query expanded=location,problem or "") |
| `UpdateWorkOrder` | `cmms/infraspeak/work-order/update` | `PATCH /v3/failures/{id}` | Change description, observations, priority, local\_id, external\_id, ... (state transitions are not in the public API) |
| `DeleteWorkOrder` | `cmms/infraspeak/work-order/delete` | `DELETE /v3/failures/{id}` | Delete a work order (lifecycle: becomes ARCHIVED) |
| `ListPlannedJobs` | `cmms/infraspeak/planned-job/list` | `GET /v3/works?{query}` | Planned jobs (Infraspeak Works: preventive maintenance plans) |
| `ListPlannedJobOrders` | `cmms/infraspeak/planned-job-order/list` | `GET /v3/works/scheduled?{query}` | Planned job orders (Scheduled Works), e.g. query s\_state=SCHEDULED\&date\_max\_start\_date=2026-10-12T00:00:00 |
| `GetPlannedJobOrder` | `cmms/infraspeak/planned-job-order/get` | `GET /v3/works/scheduled/{id}` | One planned job order by id |
| `UpdatePlannedJobOrder` | `cmms/infraspeak/planned-job-order/update` | `PATCH /v3/works/scheduled/{id}` | Reschedule / reassign: body \{date (Y-m-dTH:i:s), description, assignees \{force\_replace, operators \{attach\_ids, detach\_ids}}} |

## Prerequisites

* An Infraspeak account, and a **Personal Access Token (PAT)** from Infraspeak. Infraspeak issues tokens on request: ask for a **sandbox** token first (describe your application and integration), then for a production token once the integration is validated. Sandbox and production tokens are separate. A token from one environment does not work in the other.
* The PAT acts as a "System" user of your account. Changes it makes show up in the Infraspeak history as that user. It needs permission for the objects you call: work orders, assets, locations, clients, problems and planned jobs.
* The ids your account uses: a `client_id`, a `problem_id` (a Problem *Type*, not an Area), and a `local_id`. The `local_id` must be a location of type `location`, not a `building` or `location-folder`.
* Outbound HTTPS from the broker to `api.infraspeak.com` (or `api.sandbox.infraspeak.com`).

## Authentication

Every event sends `Authorization: {value.json.authorization}`, so the payload carries the full header value `Bearer <PAT>`. Store it as a Hub secret, for example `INFRASPEAK_AUTHORIZATION`, and read it with `GET SECRET` in the action that publishes to the connector. A missing or invalid token returns `401` with `"Authentication token invalid."`. A valid token without permission returns `403`.

The connector also sends `Accept: application/json` and a `User-Agent` that names the integration. Infraspeak asks integrations to identify themselves this way. Put your own contact in a fork.

## Configuration

| Setting | Value |
| - | - |
| `BASE_ADDRESS` | `https://api.infraspeak.com` (endpoints carry `/v3`). Sandbox: `https://api.sandbox.infraspeak.com` |
| `USE_SSL` | `"true"` |
| `DEFAULT_CONTENT_TYPE` | `application/json` |
| Payload fields | `authorization`, `id` (Infraspeak id of the work order, asset, location, problem area or planned job order), `query` (pre-encoded query string, `""` for none), `body` (JSON request body) |

List events take the whole query string in `query`. Infraspeak's filter syntax:

| Parameter | Example |
| - | - |
| `s_<field>` | `s_state=WAITING_RESOLUTION`, `s_local_id=300`, `s_priority=4` |
| `s_<field>_in` / `_notin` / `_like` | `s_state_in=WAITING_RESOLUTION,IN_RESOLUTION`, `s_name_like=pump` |
| `date_min_<field>` / `date_max_<field>` | `date_min_created_at=2026-10-01T00:00:00` |
| `expanded` | `expanded=location,problem,responsibles` |
| `sort` | `sort=priority-,created_at` (`-` means descending) |
| `limit`, `page` | `limit=50&page=2` (default 200, maximum 2000, pages start at 1) |

Responses use a JSON:API shape: `{"data": {"type", "id", "attributes"}, "meta": {"pagination"}, "links"}`. Errors look like `{"status": "error", "error": {"http_code", "message", "properties"}}`.

## Basic Syntax

```lot wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
# Coreflux REST_API template — Infraspeak Public REST API v3 (maintenance management / CMMS):
#   create work orders (Infraspeak "Failures") from alarms, list open / closed / filtered work orders, read, patch and
#   delete (archive) them, read assets (Infraspeak "Elements") with their metering statistics, create and patch assets,
#   look up locations, clients, operators, problem areas / types and categories, and read / reschedule planned jobs
#   ("Works") and planned job orders ("Scheduled Works").
# Hugo catalog #173, Tier 2 (cmms). Spec: official Infraspeak Public REST API OpenAPI 3.0.3 (v3.0.0) from the
#   Infraspeak Developer Portal, https://developer.infraspeak.com/api/openapi.yaml (fetched 2026-10-05, 82 paths,
#   curated slim in openapi-cache/infraspeak.json). Credentials are placeholders only.
# Docs: https://docs.coreflux.org/latest/lot-language/routes/rest-api-apps/infraspeak
#
# Host: production https://api.infraspeak.com (endpoints carry /v3). Sandbox: fork BASE_ADDRESS to
#   https://api.sandbox.infraspeak.com (production and sandbox tokens are separate; neither works on the other).
# Auth: Authorization: {value.json.authorization} carries the full header value "Bearer <Personal Access Token>"
#   (a JWT issued by Infraspeak on request; it acts as a "System" user of your Infraspeak account). Keep it in Hub
#   secrets (suggested INFRASPEAK_AUTHORIZATION) and map it into the payload with GET SECRET. Missing / invalid token:
#   401 "Authentication token invalid."; valid token without permission: 403.
# Headers: Accept and Authorization on every call, Content-Type on POST / PATCH, and a User-Agent naming the
#   integration (Infraspeak asks for one; change the contact in a fork).
# Rate limit: 60 requests per minute per token (rolling window, 429 + Retry-After). Poll every few minutes, not seconds.
# Queries: list events take the whole pre-encoded query string in "query" (JQL style): s_<field>=, s_<field>_in=,
#   s_<field>_like=, date_min_<field>= / date_max_<field>=, expanded=, sort=field,-field, limit= (default 200, max 2000)
#   and page= (1-based); "" for none. Example: s_state_in=WAITING_RESOLUTION,IN_RESOLUTION&s_priority=4&limit=50.
#   GetAsset accepts showMeteringData=true (metering statistics of the asset).
# Writes: POST creates, PATCH changes only the fields sent (there is no PUT). Work order state transitions (approve,
#   start, pause, close) are not exposed by the public API; DeleteWorkOrder archives (state ARCHIVED).
# Responses: JSON:API style {"data": {"type", "id", "attributes", "relationships"?}, "included"?, "meta", "links"};
#   errors {"status": "error", "error": {"http_code", "message", "properties"?}}: 400 validation, 401, 403, 404, 405,
#   429, 500. Successful writes return 200.
# Meter readings: the public v3 spec has no endpoint to write meter readings (read them via GetAsset with
#   showMeteringData=true). Not packaged until Infraspeak documents one.
# Webhooks: configured in the Infraspeak UI (Settings > Integrations > Webhooks), not through the API; receiving them
#   needs a separate ENABLE_SERVER companion route (see docs).
#
# Payload fields (control fields stay out of bodies; request bodies come from {value.json.body}):
#   authorization, id, query, body
#     CreateWorkOrder        body = {"client_id": 11406, "problem_id": 227352, "priority": 3, "local_id": 4456257,
#                                    "description": "Compressor C-101 over-temperature 92.4 C (Coreflux alarm TT-101)"}
#                            (required: client_id, problem_id (a Problem Type, not an Area), priority 1-4, local_id of a
#                             location of type "location")
#     UpdateWorkOrder        id = "18472556", body = {"observations": "Temperature back to 71 C", "external_id": "TT-101-0001"}
#     ListOpenWorkOrders     query = "s_local_id=4456257&s_priority=4&sort=created_at"
#     GetAsset               id = "12", query = "showMeteringData=true"
#     UpdatePlannedJobOrder  id = "771", body = {"date": "2026-10-06T08:00:00", "description": "Moved by Coreflux (line stop)"}

DEFINE ROUTE InfraspeakApi WITH TYPE REST_API
    ADD REST_API_CONFIG
        WITH BASE_ADDRESS "https://api.infraspeak.com"
        WITH ENABLE_CLIENT "true"
        WITH USE_SSL "true"
        WITH REQUEST_TIMEOUT '30'
        WITH DEFAULT_CONTENT_TYPE "application/json"
        # Smoke: ListLocations (limit=1) -> ListClients / ListProblemAreas / ListProblemTypes -> CreateWorkOrder -> ListOpenWorkOrders -> UpdateWorkOrder -> GetWorkOrder -> DeleteWorkOrder.
    ADD EVENT ListLocations
        WITH SOURCE_TOPIC "cmms/infraspeak/location/list"
        WITH DESTINATION_TOPIC "cmms/infraspeak/location/list/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/v3/locations?{value.json.query}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
            ADD "User-Agent" "Coreflux-Broker REST_API route (https://www.coreflux.org)"
    ADD EVENT GetLocation
        WITH SOURCE_TOPIC "cmms/infraspeak/location/get"
        WITH DESTINATION_TOPIC "cmms/infraspeak/location/get/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/v3/locations/{value.json.id}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
            ADD "User-Agent" "Coreflux-Broker REST_API route (https://www.coreflux.org)"
    ADD EVENT ListClients
        WITH SOURCE_TOPIC "cmms/infraspeak/client/list"
        WITH DESTINATION_TOPIC "cmms/infraspeak/client/list/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/v3/clients?{value.json.query}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
            ADD "User-Agent" "Coreflux-Broker REST_API route (https://www.coreflux.org)"
    ADD EVENT ListOperators
        WITH SOURCE_TOPIC "cmms/infraspeak/operator/list"
        WITH DESTINATION_TOPIC "cmms/infraspeak/operator/list/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/v3/operators?{value.json.query}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
            ADD "User-Agent" "Coreflux-Broker REST_API route (https://www.coreflux.org)"
    ADD EVENT ListProblemAreas
        WITH SOURCE_TOPIC "cmms/infraspeak/problem-area/list"
        WITH DESTINATION_TOPIC "cmms/infraspeak/problem-area/list/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/v3/problems?{value.json.query}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
            ADD "User-Agent" "Coreflux-Broker REST_API route (https://www.coreflux.org)"
    ADD EVENT ListProblemTypes
        WITH SOURCE_TOPIC "cmms/infraspeak/problem-type/list"
        WITH DESTINATION_TOPIC "cmms/infraspeak/problem-type/list/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/v3/problems/{value.json.id}/subproblems"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
            ADD "User-Agent" "Coreflux-Broker REST_API route (https://www.coreflux.org)"
    ADD EVENT ListCategories
        WITH SOURCE_TOPIC "cmms/infraspeak/category/list"
        WITH DESTINATION_TOPIC "cmms/infraspeak/category/list/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/v3/categories?{value.json.query}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
            ADD "User-Agent" "Coreflux-Broker REST_API route (https://www.coreflux.org)"
    ADD EVENT ListAssets
        WITH SOURCE_TOPIC "cmms/infraspeak/asset/list"
        WITH DESTINATION_TOPIC "cmms/infraspeak/asset/list/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/v3/elements?{value.json.query}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
            ADD "User-Agent" "Coreflux-Broker REST_API route (https://www.coreflux.org)"
    ADD EVENT GetAsset
        WITH SOURCE_TOPIC "cmms/infraspeak/asset/get"
        WITH DESTINATION_TOPIC "cmms/infraspeak/asset/get/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/v3/elements/{value.json.id}?{value.json.query}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
            ADD "User-Agent" "Coreflux-Broker REST_API route (https://www.coreflux.org)"
    ADD EVENT CreateAsset
        WITH SOURCE_TOPIC "cmms/infraspeak/asset/create"
        WITH DESTINATION_TOPIC "cmms/infraspeak/asset/create/response"
        WITH METHOD "POST"
        WITH ENDPOINT "/v3/elements"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
            ADD "User-Agent" "Coreflux-Broker REST_API route (https://www.coreflux.org)"
            ADD "Content-Type" "application/json"
        WITH BODY "{value.json.body}"
    ADD EVENT UpdateAsset
        WITH SOURCE_TOPIC "cmms/infraspeak/asset/update"
        WITH DESTINATION_TOPIC "cmms/infraspeak/asset/update/response"
        WITH METHOD "PATCH"
        WITH ENDPOINT "/v3/elements/{value.json.id}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
            ADD "User-Agent" "Coreflux-Broker REST_API route (https://www.coreflux.org)"
            ADD "Content-Type" "application/json"
        WITH BODY "{value.json.body}"
    ADD EVENT CreateWorkOrder
        WITH SOURCE_TOPIC "cmms/infraspeak/work-order/create"
        WITH DESTINATION_TOPIC "cmms/infraspeak/work-order/create/response"
        WITH METHOD "POST"
        WITH ENDPOINT "/v3/failures"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
            ADD "User-Agent" "Coreflux-Broker REST_API route (https://www.coreflux.org)"
            ADD "Content-Type" "application/json"
        WITH BODY "{value.json.body}"
    ADD EVENT ListWorkOrders
        WITH SOURCE_TOPIC "cmms/infraspeak/work-order/list"
        WITH DESTINATION_TOPIC "cmms/infraspeak/work-order/list/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/v3/failures?{value.json.query}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
            ADD "User-Agent" "Coreflux-Broker REST_API route (https://www.coreflux.org)"
    ADD EVENT ListOpenWorkOrders
        WITH SOURCE_TOPIC "cmms/infraspeak/work-order-open/list"
        WITH DESTINATION_TOPIC "cmms/infraspeak/work-order-open/list/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/v3/failures/open?{value.json.query}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
            ADD "User-Agent" "Coreflux-Broker REST_API route (https://www.coreflux.org)"
    ADD EVENT ListClosedWorkOrders
        WITH SOURCE_TOPIC "cmms/infraspeak/work-order-closed/list"
        WITH DESTINATION_TOPIC "cmms/infraspeak/work-order-closed/list/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/v3/failures/closed?{value.json.query}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
            ADD "User-Agent" "Coreflux-Broker REST_API route (https://www.coreflux.org)"
    ADD EVENT GetWorkOrder
        WITH SOURCE_TOPIC "cmms/infraspeak/work-order/get"
        WITH DESTINATION_TOPIC "cmms/infraspeak/work-order/get/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/v3/failures/{value.json.id}?{value.json.query}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
            ADD "User-Agent" "Coreflux-Broker REST_API route (https://www.coreflux.org)"
    ADD EVENT UpdateWorkOrder
        WITH SOURCE_TOPIC "cmms/infraspeak/work-order/update"
        WITH DESTINATION_TOPIC "cmms/infraspeak/work-order/update/response"
        WITH METHOD "PATCH"
        WITH ENDPOINT "/v3/failures/{value.json.id}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
            ADD "User-Agent" "Coreflux-Broker REST_API route (https://www.coreflux.org)"
            ADD "Content-Type" "application/json"
        WITH BODY "{value.json.body}"
    ADD EVENT DeleteWorkOrder
        WITH SOURCE_TOPIC "cmms/infraspeak/work-order/delete"
        WITH DESTINATION_TOPIC "cmms/infraspeak/work-order/delete/response"
        WITH METHOD "DELETE"
        WITH ENDPOINT "/v3/failures/{value.json.id}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
            ADD "User-Agent" "Coreflux-Broker REST_API route (https://www.coreflux.org)"
    ADD EVENT ListPlannedJobs
        WITH SOURCE_TOPIC "cmms/infraspeak/planned-job/list"
        WITH DESTINATION_TOPIC "cmms/infraspeak/planned-job/list/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/v3/works?{value.json.query}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
            ADD "User-Agent" "Coreflux-Broker REST_API route (https://www.coreflux.org)"
    ADD EVENT ListPlannedJobOrders
        WITH SOURCE_TOPIC "cmms/infraspeak/planned-job-order/list"
        WITH DESTINATION_TOPIC "cmms/infraspeak/planned-job-order/list/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/v3/works/scheduled?{value.json.query}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
            ADD "User-Agent" "Coreflux-Broker REST_API route (https://www.coreflux.org)"
    ADD EVENT GetPlannedJobOrder
        WITH SOURCE_TOPIC "cmms/infraspeak/planned-job-order/get"
        WITH DESTINATION_TOPIC "cmms/infraspeak/planned-job-order/get/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/v3/works/scheduled/{value.json.id}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
            ADD "User-Agent" "Coreflux-Broker REST_API route (https://www.coreflux.org)"
    ADD EVENT UpdatePlannedJobOrder
        WITH SOURCE_TOPIC "cmms/infraspeak/planned-job-order/update"
        WITH DESTINATION_TOPIC "cmms/infraspeak/planned-job-order/update/response"
        WITH METHOD "PATCH"
        WITH ENDPOINT "/v3/works/scheduled/{value.json.id}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
            ADD "User-Agent" "Coreflux-Broker REST_API route (https://www.coreflux.org)"
            ADD "Content-Type" "application/json"
        WITH BODY "{value.json.body}"
```

## Examples

Publish directly to a connector topic:

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
{"authorization": "Bearer <PAT>", "body": {"client_id": 11406, "problem_id": 227352, "priority": 4, "local_id": 4456257, "description": "Compressor C-101 over-temperature 92.4 C"}}
```

to `cmms/infraspeak/work-order/create`, then read `cmms/infraspeak/work-order/create/response`. The new work order starts in state `WAITING_APPROVAL`.

Actions that feed the connector from plant data:

```lot wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
# Example actions for the InfraspeakApi route (docs page). Not part of the route template.
# Secret: INFRASPEAK_AUTHORIZATION = "Bearer <Personal Access Token>" (request the PAT from Infraspeak; sandbox and
#   production tokens are separate).
# IDs below are examples: client_id from client/list, problem_id (a Problem Type) from problem-type/list, local_id (a
#   location of type "location") from location/list, asset id from asset/list. Replace them with your own.
# Rate limit: 60 requests per minute per token, so keep polling intervals in minutes.

DEFINE ACTION InfraspeakWorkOrderFromAlarm
ON TOPIC "plant/line1/alarm/raised" DO
    SET "auth" WITH GET SECRET "INFRASPEAK_AUTHORIZATION"
    SET "alarm" WITH (GET JSON "alarm" IN PAYLOAD AS STRING)
    SET "value" WITH (GET JSON "value" IN PAYLOAD AS STRING)
    SET "desc" WITH "Coreflux alarm " + {alarm} + " (value " + {value} + ")"
    PUBLISH TOPIC "cmms/infraspeak/work-order/create" WITH { "authorization": {auth}, "body": { "client_id": 11406, "problem_id": 227352, "priority": 4, "local_id": 4456257, "description": {desc} } }

DEFINE ACTION InfraspeakAnnotateWorkOrder
ON TOPIC "plant/line1/alarm/cleared" DO
    SET "auth" WITH GET SECRET "INFRASPEAK_AUTHORIZATION"
    SET "wo" WITH (GET JSON "failure_id" IN PAYLOAD AS STRING)
    SET "value" WITH (GET JSON "value" IN PAYLOAD AS STRING)
    SET "obs" WITH "Coreflux: alarm cleared, value " + {value}
    PUBLISH TOPIC "cmms/infraspeak/work-order/update" WITH { "authorization": {auth}, "id": {wo}, "body": { "observations": {obs} } }

DEFINE ACTION InfraspeakPollOpenWorkOrders
ON EVERY 15 MINUTES DO
    SET "auth" WITH GET SECRET "INFRASPEAK_AUTHORIZATION"
    PUBLISH TOPIC "cmms/infraspeak/work-order-open/list" WITH { "authorization": {auth}, "query": "s_local_id=4456257&sort=priority-,created_at&limit=50" }

DEFINE ACTION InfraspeakAssetMeteringSnapshot
ON EVERY 1 HOUR DO
    SET "auth" WITH GET SECRET "INFRASPEAK_AUTHORIZATION"
    PUBLISH TOPIC "cmms/infraspeak/asset/get" WITH { "authorization": {auth}, "id": "12", "query": "showMeteringData=true" }
```

Restrict who can publish to `cmms/infraspeak/#` with a rule. These payloads carry the token and can create and delete work orders.

## Work order states

`WAITING_APPROVAL` → `WAITING_RESOLUTION` (approved) → `IN_RESOLUTION` (started) → `PAUSED` / `COMPLETED`. Deleting a work order moves it to `ARCHIVED`. `ListOpenWorkOrders` returns everything except `COMPLETED` and `ARCHIVED`. `ListClosedWorkOrders` returns `COMPLETED`. The public API has no call to approve, start, pause or close a work order. `UpdateWorkOrder` changes fields only, so technicians drive state changes in the Infraspeak app.

Priorities are integers: `1` low, `2` normal, `3` high (same day), `4` critical.

## Webhooks

Infraspeak webhooks are set up in the Infraspeak web app (**Settings → Integrations → Webhooks**), not through the API. Events include `FAILURE_CREATED`, `FAILURE_STATE_CHANGED`, `FAILURE_CLOSED`, `ELEMENT_UPDATED` and others. Deliveries are `POST` (or `PUT`) with the resource in `data`, an `X-Is-Topic` header naming the event, and an optional HMAC-SHA256 signature in `X-Hook-Secret`. Receiving them needs a separate connector with `ENABLE_SERVER` reachable from the internet. That connector is not packaged here.

## Notes

* **Rate limit:** 60 requests per minute per token, on a rolling window. Above that the API returns `429` with `Retry-After`. Poll every few minutes, or use webhooks.
* **Meter readings:** the public v3 API documents no endpoint for *writing* meter readings. `GetAsset` with `query` `showMeteringData=true` returns each asset meter's statistics (min, max, average, last value). Infraspeak's IoT and meter ingestion is not in the public spec, so this connector does not package it.
* **Work orders and assets:** `CreateWorkOrder` takes a location (`local_id`), not an asset. The public spec has no asset field on create. Put the asset code in `description` or `observations`.
* `GetAsset` can answer `302` when the asset you asked for was merged into a network element.
* Errors come back on the response topic: `400` validation (field errors in `error.properties`), `401` bad token, `403` permission, `404` unknown id or path, `405` wrong method (for example `PUT`, which the API does not use), `429` rate limit.

## Testing

The connector passes static checks against the official OpenAPI spec and a local contract mock that covers all 22 events. It was also probed against the real API without a token: every event returns `401 Authentication token invalid.`, while unknown paths return `404`. A run with a real token (sandbox or production) and a broker MQTT round-trip are still open.

## Not covered

Stock, warehouses and materials, buy and sell orders, quotes, suppliers, cost centers, other costs, files, requests, creating and editing planned jobs, and the webhook receiver. All of these except the webhook receiver are in the Infraspeak API and can be added in a fork.

## Related

* [REST API Connectors](/latest/lot-language/routes/rest-api-routes)
* [REST API app templates](/latest/lot-language/routes/rest-api-apps/index)
* [MaintainX](/latest/lot-language/routes/rest-api-apps/maintainx)
* [HxGN EAM](/latest/lot-language/routes/rest-api-apps/hxgn-eam)


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