Part 05 — Identity, Discovery, Onboarding and the Session ChannelLink to the section Part 05 — Identity, Discovery, Onboarding and the Session Channel
On this page
Maturity: Draft · Profiles: all
5.1 IdentityLink to the section 5.1 Identity
Every UNIVIP Device has:
| Member | Type | Rule |
|---|---|---|
device_id |
string | Stable, globally unique, [A-Za-z0-9._~:-]{1,128}. RECOMMENDED form: urn:univip:<manufacturer>:<serial> or a UUID. MUST NOT change across firmware updates or re-onboarding. In a URL it is one path segment; : is a valid path character (RFC 3986 pchar) and is sent unencoded, and servers MUST also accept it percent-encoded (%3A). |
manufacturer, model, serial_number, firmware_version |
string | As for ONVIF GetDeviceInformation. |
univip_version |
string | Highest specification version implemented, e.g. 0.2.0. |
remote_id |
object, optional | { "serial": "...", "session_id": "..." } as broadcast under ASTM F3411 / EU Remote ID, if any, to let clients correlate with Remote ID receivers. |
implementation_mode |
enum | NATIVE, CONTROLLER, GATEWAY. |
domain |
enum | AIR, UNDERWATER, SURFACE, GROUND, MULTI. Selects which domain-specific members, commands and conformance groups apply. |
gateway |
object, optional | { "vendor": "...", "product": "...", "version": "...", "adapter": "mavlink" } when mode is GATEWAY. |
Payloads carry payload_id unique within the device. Operations carry session_id (string), newly generated for each flight; see Part 07.
5.2 Discovery and onboardingLink to the section 5.2 Discovery and onboarding
A device learns its client endpoint by at least one of:
- Configured endpoint. The operator enters the client's UNIVIP endpoint URL and credentials into the device, dock, controller or gateway. REQUIRED for all devices.
- Claim code. The device displays or prints a short-lived claim code (or QR code) encoding
univip://claim?endpoint=<url>&code=<code>; the client-side enrollment service exchanges it for device credentials (Part 13 §13.3). RECOMMENDED for consumer-friendly onboarding. - DNS-SD on the local network. Devices on a LAN SHOULD advertise
_univip._tcpwith TXT recordsid=<device_id>,v=<univip_version>,profiles=S,C,path=/univip/v1. Clients MAY browse for this service and offer the operator a one-click onboarding that supplies the configured endpoint. A device MUST NOT grant access to anyone merely because they discovered it.
ONVIF WS-Discovery is NOT used by UNIVIP. A gateway that also acts as an ONVIF device MAY answer WS-Discovery for its ONVIF persona.
5.3 Session establishmentLink to the section 5.3 Session establishment
After an authenticated secure WebSocket is established, the Device sends hello and the Client sends welcome. The Device verifies the Client identity, sends capabilities, and begins telemetry and events. Video negotiation follows the media specification.
Scroll horizontally to see the whole diagram.
View Mermaid source
sequenceDiagram
accTitle: The device starts the connection
accDescr: After an authenticated secure WebSocket is established, the Device sends hello and the Client sends welcome. The Device verifies the Client identity, sends capabilities, and begins telemetry and events. Video negotiation follows the media specification.
participant D as UNIVIP Device
participant C as UNIVIP Client
D->>C: Open authenticated WSS session over TLS 1.3
D->>C: hello: device identity and version
C-->>D: welcome: client identity and session settings
Note over D: Verify configured client identity
D->>C: capabilities: supported features
D->>C: telemetry and events
Note over D,C: Negotiate video using the advertised media capabilitiesThis is the successful connection path for one device. A gateway repeats hello, welcome and capabilities for each vehicle it presents. The steps below also define refusal, keepalive and reconnection behavior.
- Device performs TLS 1.3 to
wss://<endpoint-host>/univip/v1/session. - Device authenticates with one of the methods in Part 13 (mTLS client certificate, or OAuth 2.0 bearer token presented in the
Authorizationheader of the WebSocket upgrade request). - Device sends a
helloenvelope for each device it presents on the session (one for a native device; one per vehicle for a multiplexing gateway). The client answers eachhellowith awelcomecarrying the same envelopedevice_id, or refuses that device with anerrorenvelope carrying itsdevice_idand codeUNAUTHORIZEDorFORBIDDEN_SCOPE. - Device then sends
capabilities(the full capability document) for each welcomed device before any other message for that device.ping,ponganderrorMAY precede it. - Real-time traffic begins. A side that has neither sent nor received anything on the session for 30 s sends
ping; the peer MUST answer withpong. A ping is unanswered when nothing at all arrives from the peer before the next ping is due; after three consecutive unanswered pings the side MUST close the connection with WebSocket close code 4000. - On disconnect the device MUST reconnect with exponential backoff (initial 1 s, cap 60 s, full jitter) and resend
helloandcapabilities.
Refusing one device of a multiplexed session MUST NOT close the session or affect the other devices on it. The device MAY offer a refused device again with a new hello on the same session, not more often than once every 60 s; a later welcome attaches it. A welcome without a device_id (0.1 clients) answers every hello pending on the session.
5.3.1 Client identityLink to the section 5.3.1 Client identity
The device learns which client it is talking to from its own configuration of the endpoint, never from the welcome alone: at onboarding the operator configures the endpoint URL, the trust anchor (or pinned certificate) that authenticates it in TLS, and the client's client_id. A device MUST refuse a session whose welcome.client_id differs from the client_id configured for that endpoint (error with code UNAUTHORIZED, then close). The resulting verified client identity is used to route messages that belong to one client: command_status and lease envelopes for a command or lease submitted over the device's own REST listener go to the sessions whose verified client identity equals the client_id of the credential that submitted it, and those for a request received through the session proxy go to the session that carried the request (§5.5.1).
5.4 Envelope formatLink to the section 5.4 Envelope format
Every message on the session channel is one JSON text frame:
{
"schema": "univip.envelope.v0.2",
"type": "telemetry",
"device_id": "urn:univip:acme:SN12345",
"msg_id": "01J9ZC3V3Q6W1K9Z8Q0T6B4K7A",
"timestamp": "2026-10-15T10:32:15.125Z",
"payload": { }
}| Member | Rule |
|---|---|
type |
One of hello, welcome, capabilities, telemetry, event, command_status, signal, lease, request, response, ping, pong, error. Vendor types use reverse-DNS names. |
device_id |
REQUIRED on every device-originated message (allows gateway multiplexing) and on client-originated messages addressed to one device (welcome, signal, request). Absent on ping and pong, which belong to the session. On error it is present when the error concerns one device and absent when it cannot be attributed (for example a frame that is not JSON). |
msg_id |
REQUIRED; unique per sender per session; RECOMMENDED ULID. |
timestamp |
Time the message was created, not the time of the data inside it. |
payload |
An object validating against the schema for type (univip.telemetry.v0.2, univip.event.v0.2, univip.command_status.v0.2, univip.capabilities.v0.2, ...); the envelope schema defines the payloads of hello, welcome, signal, request, response, pong and error. |
5.4.1 hello payloadLink to the section 5.4.1 hello payload
{ "univip_version": "0.2.0", "device_id": "urn:univip:acme:SN12345",
"supported_schemas": ["univip.telemetry.v0.2", "univip.event.v0.2"],
"resume_token": null }5.4.2 welcome payloadLink to the section 5.4.2 welcome payload
{ "client_id": "vms-site-7", "univip_version": "0.2.0",
"telemetry": { "requested_rate_hz": 5 },
"server_time": "2026-10-15T10:32:14.990Z" }The envelope carries the device_id of the hello it answers. A client MAY request a telemetry rate; the device MUST honor it if within the range advertised in capabilities and otherwise MUST clamp it to that range. Either way it reports the rate it applies in telemetry.applied_rate_hz of the next capabilities message. The rate is per device and shared by its sessions; when sessions request different rates the device applies one of them (the reference gateways apply the latest request) and every session's capabilities report the rate actually applied. The requested rate is an upper bound: a device never repeats a sample to reach it (Part 07 §7.11).
5.4.3 signal payloadLink to the section 5.4.3 signal payload
Carries WebRTC signaling (SDP offers and answers, ICE candidates, teardown) for the media plane; the payload is defined in Part 09 §9.3.
5.4.4 error payloadLink to the section 5.4.4 error payload
{ "code": "UNSUPPORTED_SCHEMA", "message": "...", "ref_msg_id": "..." }Standard codes: UNAUTHORIZED, FORBIDDEN_SCOPE, UNSUPPORTED_SCHEMA, UNSUPPORTED_EXTENSION, MALFORMED (fails its schema or is not JSON), PROTOCOL_VIOLATION (valid but out of order, such as telemetry before capabilities), RATE_LIMITED, UNKNOWN_STREAM, CODEC_UNSUPPORTED, BUSY (for example a stream at its viewer limit), INTERNAL.
5.4.5 ping and pong payloadsLink to the section 5.4.5 ping and pong payloads
ping carries an empty object. pong carries { "ref_msg_id": "<msg_id of the ping>" }.
5.5 REST surfaceLink to the section 5.5 REST surface
The REST API (../api/univip-v1.openapi.yaml) exposes under /univip/v1/devices/{device_id}:
| Resource | Methods | Purpose |
|---|---|---|
/ |
GET | Identity |
/capabilities |
GET | Capability document |
/telemetry/latest |
GET | Last telemetry sample (for clients that do not hold a session channel) |
/events |
GET | Recent events, filterable by topic and time |
/media/streams |
GET | Stream descriptors |
/media/streams/{stream_id}/webrtc |
POST | Alternative WebRTC signaling via HTTP (WHEP-style) for clients that prefer it; the Location of the response names the session resource |
/media/streams/{stream_id}/webrtc/{resource_id} |
DELETE | Tear down that WebRTC session (only its creator may; others receive 404) |
/commands |
POST | Submit a command (camera.* or vehicle.*) |
/commands/{command_id} |
GET, DELETE | Status; cancel |
/leases |
GET, POST | List the caller's own leases (all leases with univip.admin), acquire |
/leases/{lease_id} |
GET, PATCH, DELETE | Status, heartbeat/extend, release |
/config |
GET, PATCH | Device configuration subset exposed to clients (telemetry rate, stream defaults) |
All responses are JSON except the SDP bodies of the WebRTC resources. Errors use RFC 9457 Problem Details with the type URIs registered in §5.5.2. HTTP 403 means only that the credential lacks the required scope; a command refused for a lease or safety reason is answered 422 with a REJECTED command status, so the client always receives a status it can show (Part 10 §10.1).
5.5.1 Session proxyLink to the section 5.5.1 Session proxy
A device declaring transports.rest.session_proxy: true serves its REST surface through request and response envelopes on the session channel, so that a client can reach a device that accepts no inbound connections.
{ "request_id": "req-0001", "method": "POST", "path": "/commands",
"headers": { "content-type": "application/json" },
"auth": { "client_id": "vms-site-7", "scopes": ["univip.view", "univip.camera"], "operator_user": "jdoe" },
"body": { "schema": "univip.command.v0.2", "...": "..." } }{ "request_id": "req-0001", "status": 202, "headers": { "content-type": "application/json" },
"body": { "schema": "univip.command_status.v0.2", "state": "ACCEPTED", "...": "..." } }pathis relative to/univip/v1/devices/{device_id}(empty for the identity resource);querycarries query parameters as strings;headerscarries onlycontent-type,if-none-matchandif-match, in lower case.bodyis the JSON body, or a string for other media types (application/sdp).- The client-hosted endpoint authenticates and authorizes its own users and states the result in
auth: theclient_id(which MUST equal the session's verified client identity, §5.3.1), the UNIVIP scopes of the user's credential, andoperator_userwhere known. The device MUST process the request exactly as if it had arrived on its own listener from a principal with those scopes, limited to the scopes the operator allowed for that endpoint at onboarding; by defaultunivip.vehicle,univip.configandunivip.adminare not allowed. - The device answers every request with exactly one
responsecarrying the samerequest_id, the HTTP status it would have returned, thecontent-type,etagandlocationheaders where applicable, and the body. Command status and lease envelopes for proxied commands and leases go to the session that carried the request. Requests on one session MAY be answered out of order. - A device MAY refuse request bodies larger than 1 MiB (status 413) and SHOULD answer within 10 s; the client-hosted endpoint answers its caller 504 when no response arrives within 30 s.
5.5.2 Problem typesLink to the section 5.5.2 Problem types
Problem type URIs are https://univip.org/problems/<slug>; vendor problems use a vendor URI. Where a UNIVIP code applies, the problem carries it as univip_code.
| Slug | Status | univip_code |
Meaning |
|---|---|---|---|
malformed |
400 | MALFORMED |
Body or parameters fail their schema; also used with HTTP 413 for a body over the size limit |
unsupported-extension |
400 | UNSUPPORTED_EXTENSION |
Unknown must-understand member (Part 01 §1.4) |
unauthorized |
401 | UNAUTHORIZED |
Missing or invalid credential |
forbidden-scope |
403 | FORBIDDEN_SCOPE |
Credential lacks the scope, or a proxied request asserts a client other than the session's |
lease-scope |
403 | LEASE_SCOPE |
Lease operation by a client that does not hold the lease, or a lease request whose client_id is not the caller's |
unsupported |
403 | UNSUPPORTED_COMMAND |
The device does not offer the profile or feature (for example a vehicle lease without Profile N) |
flight-control-disabled |
403 | FLIGHT_CONTROL_DISABLED |
Profile N is disabled by the operator |
not-found |
404 | — | Unknown device, stream, command, lease or resource |
duplicate-command |
409 | — | command_id already used |
command-terminal |
409 | — | Cancel of a command that already ended |
command-not-cancellable |
409 | A command rejection reason, e.g. BUSY or LINK_LOST |
The adapter cannot confirm cancellation; the original command remains active and movement may continue |
lease-conflict |
409 | — | An active lease with this scope is held by another client |
lease-state |
409 | — | Operation not valid in the lease's state |
stream-busy |
409 | BUSY |
Stream at its viewer limit |
lease-gone |
410 | LEASE_EXPIRED |
Heartbeat or extension of a lease that has ended; the body is the lease |
method-not-allowed |
405 | — | Method not defined for the resource |
unsupported-media-type |
415 | — | Wrong Content-Type |
rate-limited |
429 | RATE_LIMITED |
Too many requests |
internal |
500 | INTERNAL |
Unexpected device error |
device-error |
502 | — | Client-hosted endpoint: the session to the device failed while the request was outstanding |
device-unavailable |
503 | — | Client-hosted endpoint: the device has no session, or offers no session proxy |
device-timeout |
504 | — | Client-hosted endpoint: no response within 30 s |
Each URI resolves to a page on univip.org describing the problem.
5.6 MQTT alternativeLink to the section 5.6 MQTT alternative
A device that declares transports.realtime: ["WSS", "MQTT5"] MAY offer the real-time plane over MQTT 5 with the topic structure in Part 08 §8.7. The REST plane remains HTTPS. Conformance to the MQTT alternative is a separate optional test group.