Skip to main content

Supported Protocols

The Haltless edge agent and direct ingestion system support multiple industrial protocols.

HTTP Push (Edge Agent)

The most common approach. Your agent collects data from any source and pushes it via HTTP.

Endpoint

POST /api/v1/ingest

Authentication

X-API-Key: your_api_key

Request body

{
"readings": [
{
"machine_identifier": "CNC-001",
"timestamp": "2026-04-04T10:30:00Z",
"metric_name": "temperature",
"value": 72.5,
"unit": "celsius",
"raw_tag": "ns2_i1001"
}
]
}

Batch limits

ParameterLimit
Max readings per batch1,000
Max request body size10 MB
Timestamp range3,650 days past to 5 minutes future

Response

HTTP 207 Multi-Status:

{
"accepted_count": 1,
"rejected_count": 0,
"errors": []
}

If some readings fail:

{
"accepted_count": 5,
"rejected_count": 2,
"errors": [
{
"index": 3,
"machine_identifier": "UNKNOWN-001",
"error": "Machine not found"
},
{
"index": 6,
"machine_identifier": "CNC-001",
"error": "Value must be finite"
}
]
}

Python example

import requests
import time

API_KEY = "hk_your_api_key"
API_URL = "https://api.haltless.io/api/v1/ingest"

readings = [
{
"machine_identifier": "CNC-001",
"timestamp": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
"metric_name": "temperature",
"value": 72.5,
"unit": "celsius",
},
{
"machine_identifier": "CNC-001",
"timestamp": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
"metric_name": "vibration",
"value": 3.2,
"unit": "mm/s",
},
]

response = requests.post(
API_URL,
json={"readings": readings},
headers={"X-API-Key": API_KEY},
)

print(response.json())
# {"accepted_count": 2, "rejected_count": 0, "errors": []}

TypeScript/Node.js example

const API_KEY = "hk_your_api_key";
const API_URL = "https://api.haltless.io/api/v1/ingest";

const response = await fetch(API_URL, {
method: "POST",
headers: {
"X-API-Key": API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
readings: [
{
machine_identifier: "CNC-001",
timestamp: new Date().toISOString(),
metric_name: "temperature",
value: 72.5,
unit: "celsius",
},
],
}),
});

const result = await response.json();
console.log(result);

OPC-UA

OPC-UA (Open Platform Communications Unified Architecture) is the standard for industrial automation.

Edge agent configuration

[[source]]
name = "cnc-mill-1"
machine_identifier = "CNC-001"
protocol = "opcua"

[source.opcua]
endpoint = "opc.tcp://192.168.1.100:4840"
security_mode = "SignAndEncrypt"
security_policy = "Basic256Sha256"
username = "haltless"
password = "secure_password"

[[source.opcua.nodes]]
node_id = "ns=2;i=1001"
metric_name = "spindle_temperature"
unit = "celsius"

[[source.opcua.nodes]]
node_id = "ns=2;s=Vibration.X"
metric_name = "vibration_x"
unit = "mm/s"

Direct ingestion (cloud polling)

If your OPC-UA server is accessible from the internet, you can use direct ingestion instead of an edge agent:

curl -X POST https://api.haltless.io/api/v1/ingest-sources \
-H "Authorization: Bearer YOUR_JWT" \
-H "Content-Type: application/json" \
-d '{
"machine_id": "MACHINE_UUID",
"name": "CNC Mill OPC-UA",
"protocol": "opcua",
"host": "opcua.yourfactory.com",
"port": 4840,
"poll_interval_seconds": 30,
"is_active": true,
"config": {
"nodes": [
{"node_id": "ns=2;i=1001", "metric_name": "temperature", "unit": "celsius"},
{"node_id": "ns=2;i=1002", "metric_name": "vibration", "unit": "mm/s"}
]
}
}'

Security modes

ModeDescription
NoneNo security (development only)
SignMessages are signed but not encrypted
SignAndEncryptFull security (recommended for production)

Node ID formats

FormatExample
Numericns=2;i=1001
Stringns=2;s=Temperature.Value
GUIDns=2;g=09087e75-8e5e-499b-954f-f2a9603db28a
Opaquens=2;b=M/RbKBsRVkePCePcx24oRA==

Modbus TCP

Modbus TCP is widely used for PLCs, sensors, and industrial controllers.

Edge agent configuration

[[source]]
name = "conveyor-motor"
machine_identifier = "CONV-001"
protocol = "modbus"

[source.modbus]
host = "192.168.1.101"
port = 502
unit_id = 1
poll_interval = 10

[[source.modbus.registers]]
address = 100
count = 1
register_type = "holding"
metric_name = "motor_temperature"
unit = "celsius"
scale = 0.1
offset = 0.0

[[source.modbus.registers]]
address = 102
count = 1
register_type = "input"
metric_name = "motor_speed"
unit = "rpm"
scale = 1.0
offset = 0.0

Direct ingestion (cloud polling)

curl -X POST https://api.haltless.io/api/v1/ingest-sources \
-H "Authorization: Bearer YOUR_JWT" \
-H "Content-Type: application/json" \
-d '{
"machine_id": "MACHINE_UUID",
"name": "Conveyor Motor Modbus",
"protocol": "modbus",
"host": "modbus.yourfactory.com",
"port": 502,
"poll_interval_seconds": 10,
"is_active": true,
"config": {
"registers": [
{
"address": 100,
"count": 1,
"register_type": "holding",
"metric_name": "temperature",
"unit": "celsius",
"scale": 0.1,
"offset": 0.0
}
]
}
}'

Register types

TypeModbus functionDescription
holdingFC 03Read/write registers (most common)
inputFC 04Read-only registers

Scaling

Raw Modbus values are often integers. Use scale and offset to convert:

actual_value = (raw_value * scale) + offset

Example: A temperature sensor returns 725 as a raw value with scale: 0.1 and offset: 0.0:

725 * 0.1 + 0.0 = 72.5 celsius

Testing connections

You can test direct ingestion connectivity before enabling:

curl -X POST https://api.haltless.io/api/v1/ingest-sources/SOURCE_ID/test-connection \
-H "Authorization: Bearer YOUR_JWT"
{
"success": true,
"message": "Connected successfully",
"latency_ms": 45
}