Interface control document
1. Identification
| Item | Value |
|---|---|
| Document | ICD-CAPTUREAPP-001 rev 1 |
| Product | HEAT Capture |
| Product versions covered | main at 170a1eca, four commits after v2.0.34 |
| Host | Windows x64 |
| Module SDK | HEAT.Capture.ModuleSDK 2.0.5 |
| Data model | HEAT ProtoLib 0.37.0, commit 05270c5d |
| Date | 2026-09-01 |
| Owner | VRAI Simulation |
2. Scope
This document defines the supported integration boundary around HEAT Capture:
- REST session control and operational monitoring
- WebSocket frame publishing by simulator plugins and other publishers
- WebSocket event, live-view and administrator streams
- the named-pipe protocol between HEAT Capture and an isolated capture module
- the HEAT platform calls consumed for authentication, sessions and data delivery
Settings, package, inference, after-action and system-management routes used by the browser UI are private interfaces. They are not a supported third-party contract and may change with the UI. Their network exposure is still material; see Section 12.
Individual gaze, simulator, physiology and other payload components are defined by HEAT ProtoLib and the module or plugin ICD that populates them.
3. Interface inventory
| ID | Name | Direction | Transport | Peer |
|---|---|---|---|---|
| IF-CAPTUREAPP-01 | Session control and monitoring | Bidirectional | JSON over HTTP or HTTPS | Operator tool or simulator plugin |
| IF-CAPTUREAPP-02 | Frame publish | Peer to HEAT Capture | Binary WebSocket | HEAT Capture Plugin or custom publisher |
| IF-CAPTUREAPP-03 | Events and live monitoring | Product to peer, with subscription controls from peer | JSON WebSocket | Browser or monitoring client |
| IF-CAPTUREAPP-04 | Isolated module transport | Bidirectional | Windows named pipe | HEAT Capture Module Host |
| IF-CAPTUREAPP-05 | HEAT platform service | Bidirectional | JSON and protobuf over HTTP or HTTPS | HEAT platform |
4. IF-CAPTUREAPP-01 Session control and monitoring
4.1 Transport and addressing
| Item | Desktop default |
|---|---|
| Scheme | HTTP |
| Bind address | 0.0.0.0 |
| Port | 5005 |
| Base path | /api |
| JSON | UTF-8, camel-case properties |
| HTTPS | Disabled; default HTTPS port is the HTTP port plus 1 |
WebSettings:Host, Port, EnableHttps and HttpsPort configure the listener and require a
restart. The HTTPS certificate is self-signed. HTTPS binds every interface regardless of Host.
4.2 Lifecycle and access control
A user signs in through HEAT Capture, then the peer starts, optionally pauses or resumes, and stops the session. Authentication state belongs to the process, not to the HTTP client. Session routes return 401 when no user is signed in. Storage administration requires the Admin role.
Pause rejects new packets before local storage and delivery. Modules and plugins may continue producing data, but data received during the pause is discarded. Resume accepts newly arriving packets; it cannot recover packets produced during the pause.
4.3 Messages
| Endpoint | Method | Success | Purpose |
|---|---|---|---|
/api/session/start-session | POST | 200 with session | Create and start a session |
/api/session/pause-session | POST | 200, empty | Reject new packets before storage and delivery |
/api/session/resume-session | POST | 200, empty | Accept newly arriving packets again |
/api/session/stop-session | POST | 200, empty | Drain, finalise and close the session |
/api/session/current-session | GET | 200 with state | Read active state and session details |
/api/session/reset-session | POST | 200, empty | Force-clear local session state; does not close the platform session |
/api/session/launch-sim | POST | 200, empty | Launch the configured simulator |
/api/session/stop-sim | POST | 200, empty | Stop the launched simulator |
/api/session/simulation-status | GET | 200 with isRunning | Read simulator process state |
/api/health | GET | 200 with status: ok | Process liveness; unauthenticated |
/api/ui/version | GET | 200 | Product version; unauthenticated |
/api/storage/capacity | GET | 200 | Capture-drive capacity and canStartCapture |
/api/operations/summary | GET | 200 | Storage, delivery, module, socket and process state |
/api/storage/pending-sessions | GET | 200 | Admin-only undelivered-session inventory |
/api/storage/pending-sessions/{id}/retry | POST | 200 | Admin-only delivery retry |
/api/storage/pending-sessions/{id} | DELETE | 200 | Admin-only permanent discard |
GET requests to the start, pause, resume and stop action paths return 400 with
{"error":"Invalid request, use post method"}.
4.4 Data elements
| Field | Type | Unit | Range | Reference | Optionality |
|---|---|---|---|---|---|
active | boolean | n/a | true or false | Process session state | Required from current-session |
session.userId | UUID string | n/a | RFC 4122 UUID | Signed-in user | Present when active |
session.sessionId | UUID string | n/a | RFC 4122 UUID | Platform session | Present when active |
session.startTime | date-time string | UTC | ISO 8601 representable range | HEAT Capture clock | Present when active |
session.endTime | date-time string or null | UTC | ISO 8601 representable range | HEAT Capture clock | Present when active |
session.sessionDetails.projectId | signed integer | n/a | 32-bit signed | HEAT project | Present when active |
session.sessionDetails.sessionTemplateId | signed integer | n/a | 32-bit signed | HEAT template | Present when active |
isRunning | boolean | n/a | true or false | Simulator process | Required from simulation-status |
capacity.path | string | n/a | Valid Windows path | Capture store | Required |
capacity.availableBytes | signed integer | bytes | 0 to 9,223,372,036,854,775,807 | Filesystem | Required |
capacity.minimumBytes | signed integer | bytes | 0 to 9,223,372,036,854,775,807 | Configuration | Required |
capacity.warningBytes | signed integer | bytes | 0 to 9,223,372,036,854,775,807 | Configuration | Required |
capacity.canStartCapture | boolean | n/a | true or false | Available versus minimum | Required |
The platform-owned session object can also contain project, sessionTemplate, metadataJson,
sessionUsers and nodeInstances. Clients must tolerate null, absent and additional fields.
4.5 Timing, ordering and errors
State-changing requests are serialised. Callers must wait for each response before the next transition. Stopping allows up to 15 seconds for in-flight delivery, 30 seconds to drain disk writes and a further 30 seconds for final delivery.
| Condition | Status | Behaviour |
|---|---|---|
| No signed-in process user | 401 | User not authenticated |
| Start while active | 409 | A session is already active |
| Start below free-space minimum | 507 | Error plus capacity snapshot |
| Pause, resume or stop while inactive | 404 | Error naming the missing session |
| Session or simulator operation fails | 500 | Error text; detail in log |
| Wrong action method | 400 | Invalid request, use post method |
| Non-Admin storage operation | 403 | Refused |
There are no idempotency keys. After a lost response, read current-session before retrying.
5. IF-CAPTUREAPP-02 Frame publish
5.1 Transport, lifecycle and authentication
Open /ws/publish on the IF-CAPTUREAPP-01 listener, using ws for HTTP or wss for HTTPS. The
server keep-alive interval is 10 seconds. A user must already be signed in to the HEAT Capture
process; the client presents no token. Otherwise the upgrade returns HTTP 401.
Each complete binary WebSocket message is one serialized google.protobuf.Any. Fragmentation is
allowed. The socket may stay connected without an active session, but messages sent then are
discarded. Reconnecting creates an independent ingress stream.
5.2 Message and data elements
| Field | Type | Unit | Range | Reference | Optionality |
|---|---|---|---|---|---|
| WebSocket type | enum | n/a | Binary | WebSocket | Required; text is ignored |
| Message length | unsigned integer | bytes | 1 to 10,485,760 inclusive | Reassembled message | Required |
Any.type_url | protobuf string | n/a | Non-empty UTF-8 | HEAT ProtoLib message type | Required and non-empty |
Any.value | protobuf bytes | bytes | 0 to less than 10,485,760 after envelope overhead | Serialized named message | Required by Any |
HEAT Capture wraps accepted data in a DataPacket, stamps signed 64-bit milliseconds since the
Unix epoch from its UTC wall clock, and injects the signed-in user’s UUID when no origin is present.
There is no application acknowledgement.
5.3 Timing, ordering and errors
The interface has no prescribed period, frequency or latency budget. Messages on one socket are parsed sequentially in arrival order; there is no global order across sockets.
| Condition | Observable | Behaviour |
|---|---|---|
| Not a WebSocket upgrade | HTTP 400 | No socket |
| No signed-in user | HTTP 401 | No socket |
| Over 10 MiB | Close 1009, Message exceeds maximum size | Message not stored |
Invalid protobuf or empty type_url | Warning once per connection | Discarded; socket remains open |
| No session | No reply | Discarded |
| Session paused | No reply | Discarded before storage and delivery |
| Text message | No reply | Ignored |
| Disconnect | Information log | Accepted data remains on disk; client reconnects |
6. IF-CAPTUREAPP-03 Events and live monitoring
6.1 Paths and access
| Path | Purpose | Access |
|---|---|---|
/ws/events | Product events | None |
/ws/live | Lossy live data | None |
/ws/operator | Logs and operations | Process user must have Admin role |
For events and operator streams, send {"op":"subscribe","topics":[...]}. It replaces the current
subscription set. Event topics are session, config, packages and auth; operator topics are
logs and operations. Unknown topics are ignored. There is no replay.
If the Admin user signs out or loses the role, HEAT Capture closes /ws/operator and checks the
role again before each send. /ws/live ignores client data except close frames.
6.2 Data elements
| Field | Type | Unit | Range | Reference | Optionality |
|---|---|---|---|---|---|
op | string | n/a | subscribe | Client control | Required for subscription update |
topics | string array or null | n/a | Allowed topic names | Replaces current set | Optional; null clears |
topic | string | n/a | Subscribed topic | Event envelope | Required |
name | string | n/a | Event-specific name | Event envelope | Required |
ts | date-time string | UTC | ISO 8601 representable range | HEAT Capture clock | Required |
data | JSON value | n/a | Event-specific | Event envelope | Required; may be null |
Live type | string | n/a | dataPacket, simulationFrame, videoFrame | Live envelope | Required |
Live data | JSON object | n/a | Selected by type | HEAT data model | Required |
Non-finite live floating-point values are JSON null.
6.3 Timing and errors
These streams are deliberately lossy and are not durable capture feeds. Events and operator streams hold 512 messages per connection and drop the oldest when full. Live streams hold eight messages per type per connection and drop the oldest of that type. Slow viewers never back-pressure capture.
Malformed subscription JSON and unknown topics are ignored without closing the socket. An unserialisable outbound value is dropped. A non-upgrade request returns 400; a non-Admin operator upgrade returns 403.
7. IF-CAPTUREAPP-04 Isolated module transport
7.1 Addressing and framing
HEAT Capture creates one full-duplex byte-mode named pipe per module. Its name is
heat.capture.module. followed by 32 random uppercase hexadecimal characters. It permits one
server instance and grants full control only to the Windows user that launched HEAT Capture.
The module host receives --pipe, --module-file and --module-type, then connects locally. Each
frame is:
| Offset | Size | Type | Meaning |
|---|---|---|---|
| 0 | 4 bytes | unsigned little-endian | Payload length, excluding header |
| 4 | 1 byte | unsigned | Channel: 0 control, 1 data |
| 5 | Declared length | bytes | Payload, maximum 16,777,216 bytes |
7.2 Lifecycle and trust
- HEAT Capture verifies the module package signature.
- It creates the pipe and starts the module process.
- The module has 10 seconds to connect.
- HEAT Capture sends
init, negotiates the maximum protocol version, then sendsstart. - It sends
pingevery 10 seconds. Two missed heartbeats mark the module crashed. - On stop it sends
stopwith a 15-second RPC timeout. A process that does not exit within 5 seconds is killed.
There is no protocol credential. Trust comes from package verification, the unpredictable pipe name passed to the child and the current-user pipe ACL.
7.3 Control messages
Channel 0 is a UTF-8 JSON envelope.
| Field | Type | Unit | Range | Reference | Optionality |
|---|---|---|---|---|---|
id | signed integer | n/a | 0 to 9,223,372,036,854,775,807 | Request correlation; 0 for events | Required |
kind | string | n/a | req, res, evt | Control protocol | Required |
method | string or null | n/a | Method table | Control protocol | Required for request/event |
body | JSON value or null | n/a | Method-specific | Control protocol | Optional |
error | string or null | n/a | UTF-8 JSON string | Failed response | Present on failure |
| Method | Direction | Purpose |
|---|---|---|
init, start, stop, configUpdate, ping | HEAT Capture to module | Lifecycle, settings and heartbeat |
getSchema, evaluateCondition, getAsyncValues, getDebugDescriptor | HEAT Capture to module | Module settings and debug UI metadata |
sessionChanged, event.dispatch | HEAT Capture to module | Session state and curated host events |
debugState, transportTelemetry | Module to HEAT Capture | Best-effort diagnostics |
startSession, stopSession, sessionState | Module to HEAT Capture | Automatic-mode session control and state |
log | Module to HEAT Capture | {level, message, exception} |
http.send | Module to HEAT Capture | Brokered HTTP request and response |
Protocol version is integer 3 at this product ref. Initialization and configuration contain either
typed settingsJson or flattened settingsValues, plus locale and localized strings. http.send
uses required method and uri, multi-value headers, optional Base64 body and a 32-bit signed HTTP
status response. Every control frame remains subject to the 16 MiB limit.
7.4 Data channel, timing and errors
Channel 1 is four bytes of signed little-endian destination node id followed by one serialized HEAT
DataPacket. Node id range is -2,147,483,648 to 2,147,483,647. Total channel payload must not exceed
16,777,216 bytes. There is no per-packet acknowledgement. During pause the frame is accepted from
the pipe, but its packet is rejected before storage.
Writes retain frame order per pipe. Normal RPC timeout is 15 seconds; asynchronous value discovery allows 45 seconds. Framing errors, unknown channels and partial writes close and poison the connection. Two missed heartbeats mark the module crashed. Failed graceful stop leads to process termination and may quarantine the module for the application run.
8. IF-CAPTUREAPP-05 HEAT platform service
8.1 Addressing, authentication and lifecycle
HEATSettings:HEAT_URL is the base URI. Production deployments must use HTTPS. The operator signs
in with username and password; HEAT Capture then sends a bearer access token and refreshes the token
pair when required. Changing the URL signs the user out and recreates HTTP clients.
A session creates or joins a platform shared session, resolves template nodes to session node instances, uploads locally stored packets, and closes the session. Network failure does not stop capture; packets remain on disk.
8.2 Messages
| Endpoint | Method | Content | Purpose |
|---|---|---|---|
/api/authorization/token | POST | JSON username and password | Obtain tokens and user |
/api/authorization/refresh | POST | JSON refresh token | Rotate tokens |
/api/authorization/validate | POST | JSON access token | Validate restored credentials |
/api/v2/session/session_templates | GET | JSON | Read templates |
/api/v2/Session/shared_session?projectId={id} | POST | JSON | Create or join shared session |
/api/v2/session/{sessionId} | GET | JSON | Resolve session nodes |
/api/v2/node-instance/{nodeId}/outputs/data | POST | Protobuf DataPacket as application/octet-stream | Deliver one stored packet |
/api/v2/Session/{sessionId}/close | POST | JSON | Close session |
| Session field | Type | Unit | Range | Reference | Optionality |
|---|---|---|---|---|---|
name, simulationName | string | n/a | Non-empty UTF-8 | Session configuration | Required |
email | string | n/a | Valid email | Signed-in user | Required |
sessionTemplateId | signed integer | n/a | 32-bit signed | HEAT template | Required |
startTimeUtc | date-time string | UTC | ISO 8601 representable range | HEAT Capture clock | Required |
machineGroup | signed integer | n/a | 32-bit signed | Simulation group | Required |
timeWindowSeconds | signed integer or null | seconds | 1 to 2,147,483,647; default 300 | Join window | Optional |
projectId query | signed integer | n/a | 32-bit signed; default 1 | HEAT project | Required |
Close email, reason | string | n/a | Non-empty; valid email for email | User and product | Required |
closeAt | date-time string | UTC | ISO 8601 representable range | HEAT Capture clock | Required |
nodeId path | signed integer | n/a | 1 to 2,147,483,647 | Session node | Required |
Delivery retries with exponential backoff from 250 ms to 5 seconds for 10 attempts by default. A
failed packet is then parked for a later launch. Replay requires a signed-in user and an exact match
between the stored platform URL and current HEAT_URL. The interface does not promise exactly-once
delivery.
9. Data model, units and conventions
HEAT Capture Module SDK 2.0.5 supplies HEAT.ProtoLib.CSharp 0.37.0, pinned by its assembly product
version to commit
05270c5d.
IF-CAPTUREAPP-02 accepts any protobuf Any with a non-empty type_url. IF-CAPTUREAPP-04 and
IF-CAPTUREAPP-05 carry DataPacket. Module and plugin ICDs define the message types they produce.
| Concept | Convention |
|---|---|
| Protobuf values | Encoding, units and fields defined by the named HEAT ProtoLib message |
| Named-pipe integers | Little-endian |
| JSON | UTF-8, camel-case properties |
| JSON UTC time | ISO 8601 emitted by .NET System.Text.Json |
| Publish timestamp | Signed 64-bit milliseconds since Unix epoch, assigned by HEAT Capture |
| Coordinate frame, handedness and datum | Defined by payload schema and producer ICD |
10. Configuration affecting interfaces
| Setting | Effect |
|---|---|
WebSettings:Host, Port | IF-01 to IF-03 listener; restart required |
WebSettings:EnableHttps, HttpsPort | IF-01 to IF-03 HTTPS/WSS listener; restart required |
HEATSettings:HEAT_URL | IF-05 base URI and replay identity |
HEATSettings:TemplateID, InputNodeID | IF-05 template and upload node |
StorageSettings:MinimumFreeSpaceBytes | IF-01 start returns 507 below this value |
StorageSettings:MaxBundleRetries | IF-05 retry count |
StorageSettings:RetryBackoffMs, RetryBackoffMaxMs | IF-05 retry timing |
ModuleSecurity:AllowUnsignedModules | IF-04 may launch unsigned packages; invalid signatures remain blocked |
Modules:AllowedModules | Limits IF-04 peers when enforcement is enabled |
11. Compatibility and versioning
- JSON clients must ignore unknown properties and event names. Optional nested session values may be null or absent.
- Protobuf peers must tolerate unknown fields and use messages compatible with HEAT ProtoLib 0.37.0.
- IF-CAPTUREAPP-04 peers negotiate their maximum integer protocol version in
init; this ref supports up to 3. Unknown frame channels close the pipe. - IF-CAPTUREAPP-05 depends on the platform’s
/api/authorizationand/api/v2contracts. - An interface identifier remains assigned if the interface is deprecated or withdrawn.
12. Security considerations
The embedded server is not a security perimeter. It binds to 0.0.0.0 by default, most private UI
routes are unauthenticated, and authenticated routes share the workstation operator’s process-global
sign-in state. Do not expose the port to the internet or a general-purpose user network.
Bind to localhost unless a remote peer needs access. Otherwise use a host firewall allowlist,
enable HTTPS and establish explicit trust for the self-signed certificate.
/ws/eventsand/ws/livedisclose product and capture data without authentication./ws/publishchecks process sign-in, not peer identity. Any reachable client can publish under the active user’s session.- Private package, settings and restart routes are unauthenticated.
- Module trust depends on package signatures and the current-user named-pipe ACL.
- Platform tokens are encrypted, but their master key is stored on the same workstation.
- A Module Library token in
heat.modules.jsonis clear text. Remove it from support bundles.
13. Conformance
13.1 REST and publish peer
- Start HEAT Capture, sign in, and verify
/api/healthreturns 200 withstatus: ok. - Verify
/api/storage/capacityreturnscanStartCapture: true. - POST
start-session; expect 200 and a non-empty session UUID. - Open
/ws/publish, send a valid binary protobufAny, and verify the accepted-packet counter in/api/operations/summaryincreases. - POST
pause-session, send another valid message, and verify the stored-packet counter does not increase. - POST
resume-session, send another message, and verify the counter increases again. - POST
stop-session; expect 200 andcurrent-sessionto reportactive: false.
13.2 Event peer
- Open
/ws/eventsand subscribe tosession. - Start and stop a session.
- Verify
SessionStartedEventandSessionStoppedEventenvelopes with ISO 8601tsvalues. - Send malformed subscription JSON and verify the socket remains usable.
13.3 Module peer
- Install a valid signed package compatible with Module SDK 2.0.5.
- Connect within 10 seconds and return
ok: truefrominitandstart. - Negotiate protocol version 3 or lower.
- During an active session, publish a channel-1 node id plus valid
DataPacket; verify storage counters increase. - Pause and publish another frame; verify storage counters do not increase.
- Answer
pingfor 30 seconds, then returnok: truefromstopand exit within 5 seconds.
14. Revision history
| Rev | Date | Product version | Change |
|---|---|---|---|
| 1 | 2026-09-01 | main at 170a1eca, after v2.0.34 | Initial issue. |