Skip to main content

Machines

Machines are the core resource in Haltless. Every alert, work order, and downtime record is attached to a machine, and so is every reading of a tag assigned to it. A machine lives inside a System, the connection the edge agent reads, and is made of the System tags assigned to it. This page also covers machine groups, tag mappings, and unit preferences. All endpoints require a bearer JWT.

Endpoints​

MethodPathDescription
POST/api/v1/machinesCreate a machine
GET/api/v1/machinesList machines
GET/api/v1/machines/{machine_id}Get a machine
PATCH/api/v1/machines/{machine_id}Update a machine
DELETE/api/v1/machines/{machine_id}Deactivate a machine
POST/api/v1/machines/importBulk import from CSV or XLSX
POST/api/v1/machine-groupsCreate a group
GET/api/v1/machine-groupsList groups
GET/api/v1/machine-groups/treeGroup hierarchy as a tree
GET/api/v1/machine-groups/{group_id}Get a group with members
PUT/api/v1/machine-groups/{group_id}Update a group
DELETE/api/v1/machine-groups/{group_id}Delete a group
PUT/api/v1/machine-groups/{group_id}/membersReplace a group's members
POST/api/v1/tag-mappings/auto-mapSuggest standardized names for raw tags
PATCH/api/v1/tag-mappings/{mapping_id}Correct a tag mapping
POST/api/v1/tag-mappings/{mapping_id}/confirmConfirm a tag mapping
GET/api/v1/units/supportedList supported units and conversions
GET/api/v1/settings/unitsGet unit preferences
PATCH/api/v1/settings/unitsUpdate unit preferences

Create a machine​

POST /api/v1/machines

Requires an operator or administrator role. A machine is created in one of two shapes:

  • In an existing System: pass system_id. The machine is read the way its System is, so it takes no protocol. Adding a second machine to a System ends that System's auto-assignment: new tags then wait, unassigned, on the System's page.
  • On its own (the shape before Systems): omit system_id and pass protocol. Haltless creates a System with the same identifier and routes every tag it sends to this machine, until another machine joins the System. 409 if a System already answers to that identifier.

Request body

FieldTypeRequiredDescription
namestringYesHuman-readable name (1–255 chars)
machine_identifierstringYesThe machine's code, unique per company (1–255 chars)
system_iduuidNoThe System to create the machine in. 404 if it is not one of yours
protocolstringWithout system_idOne of opc_ua, modbus_tcp, modbus_rtu, s7, ethernet_ip, melsec, fins, ads, bacnet_ip, mqtt, sparkplug_b, pi_web_api, csv, json; 422 if both are missing
locationstringNoPhysical location (up to 500 chars)
{
"name": "Press 2",
"machine_identifier": "PRESS-002",
"system_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"location": "Building A, Line 3"
}
{
"name": "CNC Mill #1",
"machine_identifier": "CNC-001",
"protocol": "json",
"location": "Building A, Line 3"
}

Response: 201 Created

{
"id": "550e8400-e29b-41d4-a716-446655440000",
"tenant_id": "3f2504e0-4f89-41d3-9a0c-0305e82c3301",
"name": "CNC Mill #1",
"machine_identifier": "CNC-001",
"protocol": "json",
"status": "offline",
"connection": "offline",
"health": "healthy",
"last_seen_at": null,
"location": "Building A, Line 3",
"is_active": true,
"system_id": "550e8400-e29b-41d4-a716-446655440000",
"system_name": "CNC Mill #1",
"created_at": "2026-08-07T10:00:00Z",
"updated_at": "2026-08-07T10:00:00Z"
}

List machines​

GET /api/v1/machines

Query parameters

ParameterTypeDefaultDescription
pageinteger1Page number
page_sizeinteger20Items per page (max 100)
group_iduuidFilter by machine group
system_iduuidOnly the machines of this System
searchstringMatch name or identifier (up to 200 chars)
statusstringLive status: one of healthy, warning, critical, offline
connectionstringonline or offline
healthstringhealthy, warning or critical, whether or not the machine is online
sort_bystringnameOne of name, machine_identifier, status, connection, health, location, updated_at, created_at. health sorts by severity
sort_dirstringascasc or desc

Response: 200 OK

{
"items": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"tenant_id": "3f2504e0-4f89-41d3-9a0c-0305e82c3301",
"name": "CNC Mill #1",
"machine_identifier": "CNC-001",
"protocol": "json",
"status": "critical",
"connection": "online",
"health": "critical",
"last_seen_at": "2026-08-07T10:04:58Z",
"location": "Building A, Line 3",
"is_active": true,
"system_id": "550e8400-e29b-41d4-a716-446655440000",
"system_name": "CNC Mill #1",
"created_at": "2026-08-07T10:00:00Z",
"updated_at": "2026-08-07T10:00:00Z"
}
],
"pagination": {
"total": 1,
"page": 1,
"page_size": 20
}
}

Get a machine​

GET /api/v1/machines/{machine_id}

Returns a single machine. Returns 404 if the machine does not exist or is not accessible to you.

Update a machine​

PATCH /api/v1/machines/{machine_id}

Requires an operator or administrator role. Include only the fields you want to change.

FieldTypeDescription
namestringNew name (1–255 chars)
locationstringNew location
statusstringOne of healthy, warning, critical, offline. Stored only: the status the API reports is always the live one (see Machine statuses)
is_activebooleanActive flag

Deactivate a machine​

DELETE /api/v1/machines/{machine_id}

Requires an operator or administrator role. Deactivates the machine (a soft delete); its tags return to its System, unassigned, so their new readings wait there until they are placed on another machine. Returns 204 No Content.

Bulk import​

POST /api/v1/machines/import

Requires an operator or administrator role. Upload a CSV or XLSX file as multipart/form-data under the file field. Up to 500 rows per upload.

  • Required columns: name, machine_identifier
  • Optional columns: system (the identifier of an existing System to create the machine in), protocol (required on rows without a system: the machine gets a System of its own), location
  • Valid protocols: opc_ua, modbus_tcp, modbus_rtu, s7, ethernet_ip, melsec, fins, ads, bacnet_ip, mqtt, sparkplug_b, pi_web_api, csv, json

Response: 200 OK

{
"total_rows": 48,
"success_count": 45,
"failed_count": 3,
"errors": [
{ "row": 12, "reason": "Duplicate machine_identifier: CNC-003" }
],
"created_machine_ids": ["550e8400-e29b-41d4-a716-446655440000"]
}

Machine groups​

Organize machines into a hierarchy of sites, lines, and departments.

Create a group​

POST /api/v1/machine-groups

Requires an operator or administrator role.

FieldTypeRequiredDescription
namestringYesGroup name (1–200 chars)
group_typestringNoOne of site, line, department, custom (default custom)
descriptionstringNoFree-text description
colorstringNoHex color, for example #3B82F6
parent_iduuidNoParent group for nesting
machine_idsarray of uuidNoMachines to add on creation

Response: 201 Created

{
"id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"name": "Building A",
"group_type": "site",
"description": "Main production facility",
"color": "#3B82F6",
"machine_count": 0,
"parent_id": null,
"created_at": "2026-08-07T10:00:00Z"
}

List groups and tree​

GET /api/v1/machine-groups returns a flat list of groups. GET /api/v1/machine-groups/tree returns the same groups as a nested hierarchy, with each node carrying a children array.

Get, update, and delete a group​

GET /api/v1/machine-groups/{group_id} returns a group including its machine_ids. PUT /api/v1/machine-groups/{group_id} and DELETE /api/v1/machine-groups/{group_id} require an operator or administrator role.

Replace group members​

PUT /api/v1/machine-groups/{group_id}/members

Requires an operator or administrator role. Replaces the group's members with the supplied list.

{
"machine_ids": [
"550e8400-e29b-41d4-a716-446655440000",
"7c9e6679-7425-40de-944b-e07fc1f90ae7"
]
}

Tag mappings​

Tag mappings translate a System's raw tag names into standardized metric names; the name is kept on the System's tag. To list the tags assigned to a machine, with their names, see Sensor Data.

Suggest mappings​

POST /api/v1/tag-mappings/auto-map

Requires an operator or administrator role. Submits raw tags and returns standardized-name suggestions, which are also saved for review.

FieldTypeRequiredDescription
tagsarrayYes1–50 raw-tag entries
tags[].raw_tagstringYesOriginal tag name (1–500 chars)
tags[].system_iduuidYesSystem the tag is sent on
tags[].contextstringNoOptional hint about the tag
{
"tags": [
{
"system_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"raw_tag": "ns2_i1001_temp_motor_1"
}
]
}

Response: 200 OK

{
"results": [
{
"raw_tag": "ns2_i1001_temp_motor_1",
"system_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"standardized_name": "motor_temperature",
"unit": "celsius",
"confidence_score": 0.94
}
],
"saved_count": 1
}

Correct or confirm a mapping​

PATCH /api/v1/tag-mappings/{mapping_id} updates a mapping's standardized name and unit. POST /api/v1/tag-mappings/{mapping_id}/confirm marks a suggested mapping as confirmed without changes. Both require an operator or administrator role.

{
"standardized_name": "motor_temperature",
"unit": "celsius"
}

Units​

GET /api/v1/units/supported returns supported unit types and the available conversion pairs. It does not require authentication.

{
"conversions": [
{ "from_unit": "celsius", "to_unit": "fahrenheit" }
],
"default_preferences": {
"temperature": "celsius",
"pressure": "psi"
}
}

GET /api/v1/settings/units returns your account's unit preferences. PATCH /api/v1/settings/units updates them and requires an operator or administrator role.

{
"unit_preferences": {
"temperature": "fahrenheit",
"pressure": "bar"
}
}

Machine statuses​

The status is the machine's live state, worked out when it is asked for (the portal shows healthy as Online):

StatusDescription
healthyReporting, with no open warning or critical alert
warningAn open (unacknowledged, unresolved) warning alert
criticalAn open critical alert
offlineSilent for longer than its own pace allows: five times its usual gap between readings, and at least 2 minutes. With too little history to tell its pace, 15 minutes. A machine that has never reported is offline

Offline outranks the others: a machine that has stopped reporting is offline whatever its alerts say.

Each machine also carries the two parts its status is made of, which the portal's machine list shows as separate columns:

FieldValuesDescription
connectiononline, offlineWhether it is reporting, by the offline rule above
healthhealthy, warning, criticalWhat its open alerts say, whether or not it is online, so a machine that stopped mid-alarm reads offline and critical
last_seen_attimestamp or nullIts newest reading; null if it has never reported