> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hiroleague.com/llms.txt
> Use this file to discover all available pages before exploring further.

# UnifiedMessage reference

> Field reference, validation rules, constants, and wire examples for the canonical Hiro message envelope.

`UnifiedMessage` is the canonical message envelope used by Hiro Server, channel plugins, Hiro Gate device traffic, and device apps.

Use this page as the detailed field reference for the `UnifiedMessage` part of the [Protocol contract](/architecture/protocol/protocol-contract).

## Top-level envelope

| Field          | Type                   | Required                          | Default     | Meaning                                                                |
| -------------- | ---------------------- | --------------------------------- | ----------- | ---------------------------------------------------------------------- |
| `version`      | string                 | yes                               | `"0.1"`     | Protocol version. The only valid value is `"0.1"`.                     |
| `message_type` | string                 | yes                               | `"message"` | Communication intent. See [Message types](#message-types).             |
| `request_id`   | string or null         | only for `request` and `response` | `null`      | Correlation ID generated by the requester and echoed by the responder. |
| `routing`      | `MessageRouting`       | yes                               | none        | Sender, recipient, channel, direction, timestamp, and metadata.        |
| `content`      | `ContentItem[]`        | yes                               | `[]`        | Ordered payload items.                                                 |
| `event`        | `EventPayload` or null | only for `event`                  | `null`      | Event payload for `message_type: "event"`.                             |

## Message types

| Value      | Status      | Required shape                                                                                                    |
| ---------- | ----------- | ----------------------------------------------------------------------------------------------------------------- |
| `message`  | implemented | `content` has at least one item. `event` is absent or null.                                                       |
| `event`    | implemented | `event` is present. `content` is empty.                                                                           |
| `request`  | implemented | `request_id` is present. `content` contains at least one `json` content item. `event` is absent or null.          |
| `response` | implemented | `request_id` matches the request. `content` contains at least one `json` content item. `event` is absent or null. |
| `stream`   | reserved    | Accepted by the model. No streaming shape is finalized yet.                                                       |

## MessageRouting

| Field          | Type                    | Required | Default                      | Meaning                                                             |
| -------------- | ----------------------- | -------- | ---------------------------- | ------------------------------------------------------------------- |
| `id`           | string                  | yes      | generated UUID hex in Python | Message identifier.                                                 |
| `channel`      | string                  | yes      | none                         | Channel name, such as `devices`, `telegram`, or `echo`.             |
| `direction`    | `inbound` or `outbound` | yes      | none                         | Direction from the Hiro Server perspective.                         |
| `sender_id`    | string                  | yes      | none                         | Originating device, user, service, or server actor.                 |
| `recipient_id` | string or null          | no       | `null`                       | Target device, user, service, or null for server-directed messages. |
| `timestamp`    | ISO date-time string    | no       | current UTC time in Python   | Message timestamp.                                                  |
| `metadata`     | object                  | no       | `{}`                         | Protocol and channel routing extras.                                |

Direction is server-relative:

| Value      | Meaning                                                              |
| ---------- | -------------------------------------------------------------------- |
| `inbound`  | Arriving into Hiro Server from a device, plugin, or third-party app. |
| `outbound` | Leaving Hiro Server toward a device, plugin, or third-party app.     |

## ContentItem

| Field          | Type        | Required | Default | Meaning                                            |
| -------------- | ----------- | -------- | ------- | -------------------------------------------------- |
| `content_type` | string enum | yes      | none    | Payload kind. See [Content types](#content-types). |
| `body`         | string      | no       | `""`    | Payload value.                                     |
| `metadata`     | object      | no       | `{}`    | Content-specific extras.                           |

Content item order is meaningful. Consumers preserve the order emitted by the sender.

## Content types

| Value      | Constant                | `body` contains                    |
| ---------- | ----------------------- | ---------------------------------- |
| `text`     | `CONTENT_TYPE_TEXT`     | Plain text.                        |
| `json`     | `CONTENT_TYPE_JSON`     | JSON encoded as a string.          |
| `image`    | `CONTENT_TYPE_IMAGE`    | URL, path, or encoded image value. |
| `audio`    | `CONTENT_TYPE_AUDIO`    | URL, path, or encoded audio value. |
| `video`    | `CONTENT_TYPE_VIDEO`    | URL, path, or encoded video value. |
| `file`     | `CONTENT_TYPE_FILE`     | URL, path, or encoded file value.  |
| `location` | `CONTENT_TYPE_LOCATION` | Coordinate string or JSON string.  |

The repo-level JSON schema constrains `content_type` to these values.

## EventPayload

| Field    | Type           | Required | Default | Meaning                                             |
| -------- | -------------- | -------- | ------- | --------------------------------------------------- |
| `type`   | string enum    | yes      | none    | Dotted event name. See [Event types](#event-types). |
| `ref_id` | string or null | no       | `null`  | ID of the message or entity the event refers to.    |
| `data`   | object         | no       | `{}`    | Event-specific payload.                             |

## Event types

| Value                   | Constant                           | Purpose                                                |
| ----------------------- | ---------------------------------- | ------------------------------------------------------ |
| `message.received`      | `EVENT_TYPE_MESSAGE_RECEIVED`      | Acknowledges that an inbound message was accepted.     |
| `message.transcribed`   | `EVENT_TYPE_MESSAGE_TRANSCRIBED`   | Adds transcript data for an audio message.             |
| `message.voiced`        | `EVENT_TYPE_MESSAGE_VOICED`        | Adds synthesized voice data for a text reply.          |
| `message.content_added` | `EVENT_TYPE_MESSAGE_CONTENT_ADDED` | Attaches supplementary content to an existing message. |
| `resource.changed`      | `EVENT_TYPE_RESOURCE_CHANGED`      | Tells devices to refresh a named workspace resource.   |

The repo-level JSON schema constrains `event.type` to these values.

## Request body

Request messages use `message_type: "request"` and carry a JSON content item.

```json theme={null}
{
  "method": "channels.list",
  "params": {}
}
```

Implemented request methods:

| Method             | Purpose                                  |
| ------------------ | ---------------------------------------- |
| `channels.list`    | List conversation channels.              |
| `messages.history` | Read message history for a channel.      |
| `policy.get`       | Read the current client policy snapshot. |

## Response body

Successful responses use `status: "ok"`.

```json theme={null}
{
  "status": "ok",
  "data": {}
}
```

Error responses use `status: "error"`.

```json theme={null}
{
  "status": "error",
  "error": {
    "code": "method_not_found",
    "message": "Unknown method"
  }
}
```

## Metadata keys

| Key                   | Location           | Meaning                                                       |
| --------------------- | ------------------ | ------------------------------------------------------------- |
| `channel_id`          | `routing.metadata` | Conversation or channel grouping key.                         |
| `device_name`         | `routing.metadata` | Human-readable device name resolved by the server or gateway. |
| `sender_device_id`    | `routing.metadata` | Device ID attached by the gateway or devices channel.         |
| `friendly_name`       | `routing.metadata` | Display name for a device or participant.                     |
| `request_voice_reply` | `routing.metadata` | Requests a voice reply when the server can produce one.       |

Metadata may contain channel-specific extras, but these keys are protocol-significant because server or client behavior depends on them.

## Wire examples

### Text message

```json theme={null}
{
  "version": "0.1",
  "message_type": "message",
  "routing": {
    "id": "msg-text-1",
    "channel": "devices",
    "direction": "outbound",
    "sender_id": "device-1",
    "timestamp": "2026-04-28T18:00:00Z",
    "metadata": {
      "channel_id": "1"
    }
  },
  "content": [
    {
      "content_type": "text",
      "body": "Hello Hiro",
      "metadata": {}
    }
  ]
}
```

### Event

```json theme={null}
{
  "version": "0.1",
  "message_type": "event",
  "routing": {
    "id": "evt-transcribed-1",
    "channel": "devices",
    "direction": "outbound",
    "sender_id": "server",
    "recipient_id": "device-1",
    "timestamp": "2026-04-28T18:00:03Z",
    "metadata": {}
  },
  "content": [],
  "event": {
    "type": "message.transcribed",
    "ref_id": "msg-audio-1",
    "data": {
      "transcript": "Hello Hiro"
    }
  }
}
```

### Request

```json theme={null}
{
  "version": "0.1",
  "message_type": "request",
  "request_id": "req-1",
  "routing": {
    "id": "req-1",
    "channel": "devices",
    "direction": "inbound",
    "sender_id": "device-1",
    "timestamp": "2026-04-28T18:00:05Z",
    "metadata": {}
  },
  "content": [
    {
      "content_type": "json",
      "body": "{\"method\":\"channels.list\",\"params\":{}}",
      "metadata": {}
    }
  ]
}
```

### Response

```json theme={null}
{
  "version": "0.1",
  "message_type": "response",
  "request_id": "req-1",
  "routing": {
    "id": "resp-1",
    "channel": "devices",
    "direction": "outbound",
    "sender_id": "server",
    "recipient_id": "device-1",
    "timestamp": "2026-04-28T18:00:06Z",
    "metadata": {}
  },
  "content": [
    {
      "content_type": "json",
      "body": "{\"status\":\"ok\",\"data\":{\"channels\":[]}}",
      "metadata": {}
    }
  ]
}
```

## Implementation references

| File                                                            | Role                               |
| --------------------------------------------------------------- | ---------------------------------- |
| `protocol/unified-message.schema.json`                          | Machine-readable contract.         |
| `protocol/fixtures/`                                            | Shared valid and invalid fixtures. |
| `hiroserver/hiro-channel-sdk/src/hiro_channel_sdk/models.py`    | Python Pydantic runtime model.     |
| `hiroserver/hiro-channel-sdk/src/hiro_channel_sdk/constants.py` | Python protocol constants.         |
| `device_apps/lib/data/remote/gateway/gateway_contract.dart`     | Dart protocol constants.           |

***

## See also

<CardGroup cols={2}>
  <Card title="Protocol contract" icon="code-branch" href="/architecture/protocol/protocol-contract">
    The wider protocol boundary across messages, gateway envelopes, auth frames, and pairing frames.
  </Card>

  <Card title="Communication Manager" icon="arrows-left-right" href="/architecture/concepts/communication-manager">
    How Hiro Server routes and validates UnifiedMessage payloads.
  </Card>

  <Card title="Channel Plugins" icon="plug" href="/architecture/concepts/channel-plugins">
    How channel plugins exchange UnifiedMessages with Hiro Server.
  </Card>
</CardGroup>
