Skip to content

IoT contract

N2E ingests telemetry through a dedicated iot service. This page is the contract devices and integrators must follow.

Endpoints

PathMethodTransportAuthPurpose
/iot/telemetryWebSocket (streamIn)bearerLong-lived stream — devices push telemetry frames continuously.
/iot/trip-endPOSTHTTPSbearerOne-shot event when a trip completes (includes video metadata).
/iot/telemetry/emitPOSTHTTPSbearerDemo helper — emit synthetic telemetry for a set of vehicleIds.
/iot/trip-end/emitPOSTHTTPSbearerDemo helper — emit a synthetic trip-end event for a vehicle.

All endpoints require a valid session token (Authorization header Bearer <token> from /auth/signin). The two emit* endpoints are intended for demos and integration testing only.

Once published the events fan out via Encore PubSub topics (telemetryTopic, tripEndTopic) into the telemetry-store service for persistence and into the predictive-maintenance service for AI risk analysis.

Telemetry payload

The shape devices must send on the /iot/telemetry stream:

ts
interface TelemetryEvent {
  vehicle_id: string;          // matches the vehicle's `vehicleId` from /truck
  timestamp: string;           // ISO-8601 with timezone, e.g. "2026-05-19T08:32:11.500Z"
  powertrain: {
    engine_rpm: number;        // revolutions per minute
    engine_torque_pct: number; // 0–100, percent of max torque
    fuel_rate_lph: number;     // litres per hour (instantaneous)
    coolant_temp_c: number;    // °C
    oil_pressure_kpa: number;  // kPa
    boost_pressure_kpa: number;// kPa
    nox_ppm: number;           // parts per million (after-treatment NOx)
  };
  speed_kmh: number;           // current ground speed, km/h
  odometer_km: number;         // total distance, km, monotonically increasing
  engine_hours: number;        // total engine on-time, hours
  coordinates: {
    lat: number;               // WGS-84 decimal degrees
    long: number;              // WGS-84 decimal degrees (note: field is `long`, not `lng`)
  };
}

Field naming

The platform uses snake_case on the wire and long (not lng/longitude). Stick to it exactly — the predictive-maintenance rules and storage schema match these names.

Example frame

json
{
  "vehicle_id": "KR-SEED-TRK-01",
  "timestamp": "2026-05-19T08:32:11.500Z",
  "powertrain": {
    "engine_rpm": 1850,
    "engine_torque_pct": 62,
    "fuel_rate_lph": 24.3,
    "coolant_temp_c": 88.4,
    "oil_pressure_kpa": 410,
    "boost_pressure_kpa": 175,
    "nox_ppm": 18
  },
  "speed_kmh": 78.2,
  "odometer_km": 142307.1,
  "engine_hours": 8423.5,
  "coordinates": { "lat": 37.5665, "long": 126.9780 }
}

Trip-end payload

Sent once per completed trip via REST:

ts
interface TripEndEvent {
  vehicle_id: string;
  trip_id: string;             // unique id generated by the device or dispatch system
  end_timestamp: string;       // ISO-8601
  video_metadata: {
    file_size_gb: number;
    duration_minutes: number;
  };
}

Example

bash
curl -X POST https://<gateway>/iot/trip-end \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "vehicle_id": "KR-SEED-TRK-01",
    "trip_id": "trip-2026-05-19-0001",
    "end_timestamp": "2026-05-19T14:05:00Z",
    "video_metadata": { "file_size_gb": 4.7, "duration_minutes": 312 }
  }'

Cadence & batching

SignalRecommended rate
Idle / parked1 sample / 30 s
Moving (urban)1 sample / 1 s
Moving (highway)1 sample / 2 s
Critical event (hard brake, fault)burst at 10 Hz for 5 s

The WebSocket endpoint accepts back-pressure; the device may buffer locally during connectivity loss and flush on reconnect. Use monotonically increasing timestamp values.

Authentication

Each device gets a service-account user with role driver (or a dedicated device role you create). The flow:

  1. Device authenticates once with /auth/signin using its email + password.
  2. Stores the returned bearer token (HttpOnly cookie or local secure storage on RN).
  3. Sends Authorization: Bearer <token> on the WebSocket upgrade and on every /iot/trip-end POST.
  4. On 401, re-runs sign-in and retries.

Best practice

Issue per-device credentials (one user per VIN) rather than a shared key. This keeps audit logs meaningful and lets you revoke a single device without taking the whole fleet offline.

Validation & errors

CodeMeaningAction
200 / OK frameAcceptedcontinue
400Schema mismatchlog + drop frame
401Token expiredrefresh and reconnect
409Stale timestamp (older than last)drop frame
429Rate limitedback off, then retry
5xxUpstream issuebuffer locally, retry with jitter

The server does not ACK every frame — assume success unless the connection drops. On reconnect, replay anything you buffered since the last successful flush.

Downstream effects

When a frame lands in telemetryTopic the following happens:

  1. telemetry-store writes a row in telemetry_records.
  2. predictive-maintenance applies its rule set (NOx, coolant, oil, fuel rate, RPM bands) and may emit alerts.
  3. notification fans critical alerts to the operator UI and (if configured) email/SMS.
  4. dashboard widgets re-render with the latest summary.

The end-to-end latency from device to operator UI is sub-second on a healthy connection.

See also

N2E Fleet Management User Guide.