--- title: 62/STATUS-Payloads name: Status Message Payloads status: draft editor: r4bbit \ contributors: - Adam Babik \ - Andrea Maria Piana \ - Oskar Thoren \ - Samuel Hawksby-Robinson \ sidebar_position: 62 --- ## Abstract This specification describes how the payload of each message in Status looks like. It is primarily centered around chat and chat-related use cases. The payloads aims to be flexible enough to support messaging but also cases described in the [Status Whitepaper](https://status.im/whitepaper.pdf) as well as various clients created using different technologies. ## Wire Format Specification ### Payload wrapper The node wraps all payloads in a [protobuf record](https://developers.google.com/protocol-buffers/) record: ```protobuf message StatusProtocolMessage { bytes signature = 4001; bytes payload = 4002; } ``` `signature` is the bytes of the signed `SHA3-256` of the payload, signed with the key of the author of the message. The node needs the signature to validate authorship of the message, so that the message can be relayed to third parties. If a signature is not present, but an author is provided by a layer below, the message is not to be relayed to third parties, and it is considered plausibly deniable. ### Encoding The node encodes the payload using [Protobuf](https://developers.google.com/protocol-buffers) ### Types of messages #### ChatMessage The type `ChatMessage` represents a chat message exchanged between clients. #### Payload The protobuf description is: ```protobuf message ChatMessage { // Lamport timestamp of the chat message uint64 clock = 1; // Unix timestamps in milliseconds, currently not used as we use whisper as // more reliable, but here so that we don't rely on it uint64 timestamp = 2; // Text of the message string text = 3; // Id of the message that we are replying to string response_to = 4; // Ens name of the sender string ens_name = 5; // Chat id, this field is symmetric for public-chats and private group chats, // but asymmetric in case of one-to-ones, as the sender will use the chat-id // of the received, while the receiver will use the chat-id of the sender. // Probably should be the concatenation of sender-pk & receiver-pk in // alphabetical order string chat_id = 6; // The type of message (public/one-to-one/private-group-chat) MessageType message_type = 7; // The type of the content of the message ContentType content_type = 8; oneof payload { StickerMessage sticker = 9; ImageMessage image = 10; AudioMessage audio = 11; bytes community = 12; DiscordMessage discord_message = 99; } // Grant for community chat messages bytes grant = 13; // Message author's display name, introduced in version 1 string display_name = 14; ContactRequestPropagatedState contact_request_propagated_state = 15; repeated UnfurledLink unfurled_links = 16; enum ContentType { UNKNOWN_CONTENT_TYPE = 0; TEXT_PLAIN = 1; STICKER = 2; STATUS = 3; EMOJI = 4; TRANSACTION_COMMAND = 5; // Only local SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP = 6; IMAGE = 7; AUDIO = 8; COMMUNITY = 9; // Only local SYSTEM_MESSAGE_GAP = 10; CONTACT_REQUEST = 11; DISCORD_MESSAGE = 12; IDENTITY_VERIFICATION = 13; // Only local SYSTEM_MESSAGE_PINNED_MESSAGE = 14; // Only local SYSTEM_MESSAGE_MUTUAL_EVENT_SENT = 15; // Only local SYSTEM_MESSAGE_MUTUAL_EVENT_ACCEPTED = 16; // Only local SYSTEM_MESSAGE_MUTUAL_EVENT_REMOVED = 17; } } ``` | Field | Name | Type | Description | | ----- | ---- | ---- | ---- | | 1 | clock | `uint64` | The clock of the chat| | 2 | timestamp | `uint64` | The sender timestamp at message creation | | 3 | text | `string` | The content of the message | | 4 | response_to | `string` | The ID of the message replied to | | 5 | ens_name | `string` | The ENS name of the user sending the message | | 6 | chat_id | `string` | The local ID of the chat the message is sent to | | 7 | message_type | `MessageType` | The type of message, different for one-to-one, public or group chats | | 8 | content_type | `ContentType` | The type of the content of the message | | 9 | payload | `Sticker` I `Image` I `Audio` I `DiscordMessage` I `bytes` I nil` | The payload of the message based on the content type | | 13 | grant | `bytes` | Grant for community chat messages | | 14 | display_name | `string` | The message author's display name | | 15 | contact_request_propagated_state | `ContactRequestPropagatedState` | Contact request clock values | | 16 | unfurled_links | `UnfurledLink[]` | Unfurled links and their metadata that have been attached to the message | #### Content types A node requires content types for a proper interpretation of incoming messages. Not each message is plain text but may carry different information. The following content types MUST be supported: * `TEXT_PLAIN` identifies a message which content is a plaintext. There are other content types that MAY be implemented by the client: * `STICKER` * `STATUS` * `EMOJI` * `TRANSACTION_COMMAND` * `IMAGE` * `AUDIO` * `COMMUNITY` * `CONTACT_REQUEST` * `DISCORD_MESSAGE` * `IDENTITY_VERIFICATION` ##### Mentions A mention MUST be represented as a string with the `@0xpk` format, where `pk` is the public key of the [user account](https://specs.status.im/spec/2) to be mentioned, within the `text` field of a message with content_type `TEXT_PLAIN`. A message MAY contain more than one mention. This specification RECOMMENDs that the application does not require the user to enter the entire pk. This specification RECOMMENDs that the application allows the user to create a mention by typing @ followed by the related ENS or 3-word pseudonym. This specification RECOMMENDs that the application provides the user auto-completion functionality to create a mention. For better user experience, the client SHOULD display a known [ens name or the 3-word pseudonym corresponding to the key](https://specs.status.im/spec/2#contact-verification) instead of the `pk`. ##### Sticker content type A `ChatMessage` with `STICKER` `Content/Type` MUST also specify the ID of the `Pack` and the `Hash` of the pack, in the `Sticker` field of `ChatMessage` ```protobuf message StickerMessage { string hash = 1; int32 pack = 2; } ``` ##### Image content type A `ChatMessage` with `IMAGE` `Content/Type` MUST also specify the `payload` of the image and the `type`. Clients MUST sanitize the payload before accessing its content, in particular: - Clients MUST choose a secure decoder - Clients SHOULD strip metadata if present without parsing/decoding it - Clients SHOULD NOT add metadata/exif when sending an image file for privacy and security reasons - Clients MUST make sure that the transport layer constraints the size of the payload to limit they are able to handle securely ```protobuf message ImageMessage { bytes payload = 1; ImageType type = 2; enum ImageType { UNKNOWN_IMAGE_TYPE = 0; PNG = 1; JPEG = 2; WEBP = 3; GIF = 4; } } ``` ##### Audio content type A `ChatMessage` with `AUDIO` `Content/Type` MUST also specify the `payload` of the audio, the `type` and the duration in milliseconds (`duration_ms`). Clients MUST sanitize the payload before accessing its content, in particular: - Clients MUST choose a secure decoder - Clients SHOULD strip metadata if present without parsing/decoding it - Clients SHOULD NOT add metadata/exif when sending an audio file for privacy and security reasons - Clients MUST make sure that the transport layer constraints the size of the payload to limit they are able to handle securely ```protobuf message AudioMessage { bytes payload = 1; AudioType type = 2; uint64 duration_ms = 3; enum AudioType { UNKNOWN_AUDIO_TYPE = 0; AAC = 1; AMR = 2; ``` ##### Community content type A `ChatMessage` with `COMMUNITY` `Content/Type` MUST also specify the `payload` of the community as bytes from a [CommunityDescription](#communitydescription). ##### DiscordMessage content type A `ChatMessage` with `DISCORD_MESSAGE` `Content/Type` MUST also specify the `payload` of the `DiscordMessage`. ```protobuf message DiscordMessage { string id = 1; string type = 2; string timestamp = 3; string timestampEdited = 4; string content = 5; DiscordMessageAuthor author = 6; DiscordMessageReference reference = 7; repeated DiscordMessageAttachment attachments = 8; } message DiscordMessageAuthor { string id = 1; string name = 2; string discriminator = 3; string nickname = 4; string avatarUrl = 5; bytes avatarImagePayload = 6; string localUrl = 7; } message DiscordMessageReference { string messageId = 1; string channelId = 2; string guildId = 3; } message DiscordMessageAttachment { string id = 1; string messageId = 2; string url = 3; string fileName = 4; uint64 fileSizeBytes = 5; string contentType = 6; bytes payload = 7; string localUrl = 8; } ``` #### Message types A node requires message types to decide how to encrypt a particular message and what metadata needs to be attached when passing a message to the transport layer. For more on this, see [10/WAKU2](../../waku/standards/core/10/waku2.md). \