Supported recorders › Recorder API
Recorder API.
Any device that can see KNX bus traffic can become a KNXSENSE recorder. It sends the telegrams it reads to the KNXSENSE cloud, where they are stored, analysed and made available to the installer.
This is the same interface every recorder we support today uses — Wiser for KNX, spaceLYnk, LogicMachine, ABB and Busch-Jaeger APP-Control Server, xxter, 1Home, Elsner, Raspberry Pi and Windows/macOS.
Four things, and nothing else.
A recorder enrols once per installation, reads the bus, buffers what it sees and sends it on. It reads the bus and never writes to it — this interface carries telegrams out of the installation in one direction only.
If your platform supports Lua scripting, that is usually the smoothest path: several of our recorders are Lua scripts, and we can adapt one to your device. If not, the protocol below is small enough to implement in any language.
- EnrolRedeem a single-use install code and store the credentials
- ObserveTurn every telegram on the bus into a compact JSON record
- BufferKeep records on the device across restarts and outages
- SendPost batches and advance the buffer only on acknowledgement
One base URL, two ways to sign.
Every request goes to https://app.knxsense.com over HTTPS. All
timestamps are ISO-8601 in UTC.
Enrolment
The installation owner generates a single-use install code in the KNXSENSE commissioning wizard. The device redeems it once:
POST /api/v1/asenna/asetukset
Content-Type: application/json
{ "koodi": "<install-code>", "alusta": "<your-platform-id>" }
koodi is the install code. alusta is a short platform
identifier we agree with you during onboarding; your device includes it in the
enrolment request, and there is no separate endpoint to fetch it. On success the
server returns the
device’s long-lived credentials: hub_id (a UUID identifying this
recorder), token (a bearer token) and hmac_secret (a
32-byte secret, 64 hex characters, for request signing). Store all three
persistently — they are per-device and can be revoked individually.
Authentication
Every request carries X-Hub-Id: <hub_id>. Two schemes are
accepted, and HMAC takes precedence if both are present.
The simpler one is Authorization: Bearer <token>, which relies
on TLS for confidentiality. HMAC is recommended:
X-Hub-Id: <hub_id> X-Timestamp: <unix-seconds> X-Signature: sha256=<hex> signature = HMAC_SHA256( hmac_secret, timestamp + "." + raw_body ) X-Signature = "sha256=" + hex(signature)
The signature covers the raw request body. Sign the exact bytes you send: do not re-serialize or reorder keys after signing.
The accepted time window is ±300 seconds. If your clock falls outside
it, the response is 401 with the server time in the
X-Palvelimen-Aika header and in the body, so the device can correct its
offset and sign again.
Batches of up to 2000 telegrams.
Telegrams are posted to /api/v1/ingest as a single JSON object —
a batch. A batch holds at most 2000 telegrams and 4 MB. Delivery is
at-least-once: keep resending a batch until it is acknowledged, and the server
silently ignores records it has already stored.
Cadence. Send a batch as soon as it fills, or at least once a minute if it has not — the reference recorders send on a ~60-second heartbeat even when the queue is empty, which also keeps the health view current.
Batch object
| Field | Type | Required | Range | Description |
|---|---|---|---|---|
| boot_id | UUID | ✓ | — | A new UUID generated each time the recorder process starts. |
| capture_src | int | ✓ | 1–6 | How the bus was observed — see Capture modes below. |
| events | array | ✓ | ≤ 2000 | The telegrams. |
| script_version | string | — | Your recorder’s version. | |
| overflows | array | — | Timestamps of moments when the local queue overflowed and an unknown number of records was lost. | |
| katkot | array | — | Intervals during which the recorder was not listening to the bus. (The field name is Finnish; it is part of the wire format.) | |
| hb | object | — | Heartbeat — device state sent in the same request. Recommended. |
Telegram object
Field names are single letters to keep bandwidth low — even a single-family
home can produce hundreds of thousands of telegrams per day (the default daily limit
is 1 000 000). A minimal telegram is
{ "q": …, "t": …, "d": … }.
| Field | Type | Required | Range | Description |
|---|---|---|---|---|
| q | int | ✓ | 0 … 262 | Monotonic sequence number within the current boot_id. |
| t | datetime | ✓ | — | Edge timestamp: ISO-8601, UTC, milliseconds. |
| d | int | ✓ | 0 … 65535 | Destination group address, raw. 512 is 0/2/0. |
| a | int | 0 … 1023 | APCI. 0 = read, 1 = response, 2 = write (default). | |
| s | int | 0 … 65535 | Source individual address, raw. 0 means the recorder itself. | |
| r | string | ≤ 512 | Raw payload bytes as a hex string. Recommended — see below. | |
| dl | int | 0 … 254 | Payload length in bytes. 0 means the value is carried in the APCI byte. | |
| dp | string | ≤ 64 | Datapoint type if known, for example DPST-1-1 or DPT-9. | |
| v | float | — | Numeric value. Fallback only. | |
| vt | string | ≤ 512 | Textual value. Fallback only. | |
| o | string | ≤ 16 | Origin: bus, or us when the recorder sent it. | |
| y | int | 0 … 65535 | Gateway id. Only if you observe the same bus through more than one KNX/IP gateway, so duplicates can be reconciled. Omit otherwise. |
Send the raw bytes. Values are decoded on the server from the raw
payload in r, using the project’s datapoint types;
v and vt are only a fallback. Sending r
keeps the history re-decodable if the project definitions change later.
Raw-address alternative. If it is easier on your platform, you may send
human-readable fields instead and let the server convert them: ga
(1/3/5), pa (1.1.5), dpt
(9.001), tt (telegram type 0/1/2), and sz
with r. For a new implementation the single-letter fields above are
preferred: they are unambiguous and lighter.
KNX Data Secure telegrams are stored with their addresses and raw bytes. The encrypted value is not decoded.
Advance the buffer on ack_seq, not on 200.
A 200 response returns an acknowledgement object:
| Field | Description |
|---|---|
| ack_seq | The highest sequence number durably stored. Advance your buffer only up to this. |
| accepted | Number of telegrams stored. |
| duplicates | Number of already-seen sequence numbers in the batch. |
| throttled | true if the daily limit was reached and the batch was not stored. |
| lukittu | true if the account is inactive and no data is being collected. (Finnish for “locked”.) |
throttled and lukittu are not acknowledgements.
Keep the data buffered and retry later.
- Sequence numbers.
qmust be strictly monotonic within aboot_id. Generate a freshboot_idon restart, which also resets the counter; resends are de-duplicated automatically. The 262 ceiling is a deliberate sanity bound well below the signed 64-bit range and is never reached in practice. - Daily limit. Each recorder has a daily telegram limit, 1 000 000
by default, counted in the installation’s local timezone. When it is reached
the batch is rejected with
throttled: trueandack_seqdoes not advance. The data flows once the limit resets at local midnight. - Buffer on the device. Persist the queue with its
boot_idandqso it survives restarts, and resend unacknowledged batches. If your own queue overflows, drop the oldest records and report the moment inoverflows. - Keep the clock reasonable (NTP). Timestamps far from server time, or jumping backwards, are flagged.
Response codes
| Code | Meaning |
|---|---|
| 200 | Batch processed. Read the acknowledgement body for the result. |
| 401 | Authentication failed. See the clock-skew case above. |
| 422 | The body did not match the schema. Fix the record shape; do not retry it unchanged. |
| 500 | Transient server error. Resend the same batch. |
A single malformed record does not fail the whole batch: the valid records are kept.
Heartbeat
Send device state in the hb field of the same request: current
clock, queue depth and size, dropped count, IP address and KNX link state. The
heartbeat is what lets KNXSENSE show the recorder as healthy and warn the installer
when it falls silent or its queue starts to grow.
Tell us how you read the bus.
capture_src tells KNXSENSE how the telegrams were captured:
| Value | Mode | Description |
|---|---|---|
| 1 | Event-based | From the device’s own decoded event stream. |
| 2 | Resident | A continuously running script on the device reads the bus. |
| 3 | Bus monitor | Raw frames straight from the bus. |
| 4 | WebSocket | From a WebSocket feed the device exposes. |
| 5 | KNXnet/IP tunnelling | Through a tunnelling connection to a KNX/IP gateway. |
| 6 | KNXnet/IP routing | From the multicast group a KNX/IP router sends to. |
Choose whatever gives the complete bus stream with correct raw payloads. If your device already decodes the bus internally, emit from that stream. If it has a KNX/IP gateway, read through tunnelling or routing. A raw bus-monitor feed is ideal, because it preserves everything — write, read and response telegrams, raw bytes and secure frames — without lossy pre-decoding.
Four steps to a supported device.
- Tell us what your device can run — Lua, another language, or a firmware you extend — and how it sees the bus. We pick the lightest path together, adapting an existing Lua recorder where we can.
- We issue a test installation and an install code. Your device enrols and streams to a staging recorder.
- We confirm the round-trip together: telegrams arrive,
ack_seqadvances, and the heartbeat shows a healthy link. - Once your integration passes our compatibility check, your product gets its own page on knxsense.com/recorders and may be marketed as KNXSENSE-compatible under our brand-use terms.
Write to support@knxsense.com to start.