> ## Documentation Index
> Fetch the complete documentation index at: https://personal-9eca1d6c-claude-eager-cerf-wfbdlr.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# waproto

> Protocol Buffers definitions for WhatsApp messages

## Overview

`waproto` contains the Protocol Buffers definitions for all WhatsApp message types. It's auto-generated from `whatsapp.proto` using `prost` and provides strongly-typed Rust structs for working with WhatsApp's binary protocol.

```toml theme={null}
[dependencies]
waproto = "0.6"
```

## Structure

```
waproto/
├── src/
│   ├── lib.rs               # Module definition + tags re-export
│   ├── whatsapp.proto       # Source protobuf definitions
│   ├── whatsapp.desc        # Binary FileDescriptorSet (committed)
│   └── whatsapp.desc.sha256 # SHA-256 of descriptor and proto
└── build.rs                 # Always-on: generates whatsapp.rs + tags.rs → OUT_DIR
```

The build writes `whatsapp.rs` and `tags.rs` to `OUT_DIR`. Do not commit these files.

## Usage

All protobuf types are under the `waproto::whatsapp` module:

```rust theme={null}
use waproto::whatsapp as wa;

let message = wa::Message {
    conversation: Some("Hello, World!".to_string()),
    ..Default::default()
};
```

## Key message types

### Core message types

#### Message

The main message container used for all WhatsApp messages.

```rust theme={null}
pub struct Message {
    // Text message
    pub conversation: Option<String>,
    
    // Media messages
    pub image_message: Option<Box<ImageMessage>>,
    pub video_message: Option<Box<VideoMessage>>,
    pub audio_message: Option<Box<AudioMessage>>,
    pub document_message: Option<Box<DocumentMessage>>,
    pub sticker_message: Option<Box<StickerMessage>>,
    
    // Rich messages
    pub extended_text_message: Option<Box<ExtendedTextMessage>>,
    pub interactive_message: Option<Box<InteractiveMessage>>,
    pub template_message: Option<Box<TemplateMessage>>,
    pub buttons_message: Option<Box<ButtonsMessage>>,
    pub list_message: Option<Box<ListMessage>>,
    
    // Group messages
    pub sender_key_distribution_message: Option<SenderKeyDistributionMessage>,
    
    // System messages
    pub protocol_message: Option<Box<ProtocolMessage>>,
    pub ephemeral_message: Option<Box<EphemeralMessage>>,
    pub view_once_message: Option<Box<ViewOnceMessage>>,
    pub view_once_message_v2: Option<Box<ViewOnceMessageV2>>,
    pub view_once_message_v2_extension: Option<Box<FutureProofMessage>>,
    
    // Reactions and interactions
    pub reaction_message: Option<ReactionMessage>,
    pub edited_message: Option<Box<FutureProofMessage>>,
    pub keep_in_chat_message: Option<KeepInChatMessage>,
    
    // Album (grouped media)
    pub album_message: Option<Box<AlbumMessage>>,
    pub associated_child_message: Option<Box<FutureProofMessage>>,
    
    // Metadata
    pub message_context_info: Option<MessageContextInfo>,
    // ... and many more
}
```

**Usage in main library:**

```rust theme={null}
use waproto::whatsapp as wa;

// Construct a text message
let msg = wa::Message {
    conversation: Some("Hello!".to_string()),
    ..Default::default()
};

// Construct an image message
let img = wa::Message {
    image_message: Some(Box::new(wa::message::ImageMessage {
        url: Some(media_url),
        media_key: Some(media_key.to_vec()),
        file_sha256: Some(file_sha256.to_vec()),
        file_enc_sha256: Some(file_enc_sha256.to_vec()),
        caption: Some("Check this out!".to_string()),
        ..Default::default()
    })),
    ..Default::default()
};
```

#### MessageKey

Identifies a specific message in a conversation.

```rust theme={null}
pub struct MessageKey {
    pub remote_jid: Option<String>,  // Chat JID
    pub from_me: Option<bool>,       // Sent by me?
    pub id: Option<String>,          // Message ID
    pub participant: Option<String>, // Group participant JID
}
```

### Media Messages

#### ImageMessage

```rust theme={null}
pub struct ImageMessage {
    pub url: Option<String>,
    pub mimetype: Option<String>,
    pub caption: Option<String>,
    pub file_sha256: Option<Vec<u8>>,
    pub file_length: Option<u64>,
    pub height: Option<u32>,
    pub width: Option<u32>,
    pub media_key: Option<Vec<u8>>,
    pub file_enc_sha256: Option<Vec<u8>>,
    pub jpeg_thumbnail: Option<Vec<u8>>,
    pub context_info: Option<ContextInfo>,
    // ...
}
```

#### VideoMessage

```rust theme={null}
pub struct VideoMessage {
    pub url: Option<String>,
    pub mimetype: Option<String>,
    pub caption: Option<String>,
    pub file_sha256: Option<Vec<u8>>,
    pub file_length: Option<u64>,
    pub seconds: Option<u32>,
    pub media_key: Option<Vec<u8>>,
    pub file_enc_sha256: Option<Vec<u8>>,
    pub jpeg_thumbnail: Option<Vec<u8>>,
    pub gif_playback: Option<bool>,
    // ...
}
```

#### AudioMessage

```rust theme={null}
pub struct AudioMessage {
    pub url: Option<String>,
    pub mimetype: Option<String>,
    pub file_sha256: Option<Vec<u8>>,
    pub file_length: Option<u64>,
    pub seconds: Option<u32>,
    pub ptt: Option<bool>,  // Push-to-talk (voice note)
    pub media_key: Option<Vec<u8>>,
    pub file_enc_sha256: Option<Vec<u8>>,
    // ...
}
```

#### DocumentMessage

```rust theme={null}
pub struct DocumentMessage {
    pub url: Option<String>,
    pub mimetype: Option<String>,
    pub title: Option<String>,
    pub file_sha256: Option<Vec<u8>>,
    pub file_length: Option<u64>,
    pub page_count: Option<u32>,
    pub media_key: Option<Vec<u8>>,
    pub file_enc_sha256: Option<Vec<u8>>,
    pub file_name: Option<String>,
    pub jpeg_thumbnail: Option<Vec<u8>>,
    // ...
}
```

#### StickerMessage

```rust theme={null}
pub struct StickerMessage {
    pub url: Option<String>,
    pub file_sha256: Option<Vec<u8>>,
    pub file_enc_sha256: Option<Vec<u8>>,
    pub media_key: Option<Vec<u8>>,
    pub mimetype: Option<String>,
    pub height: Option<u32>,
    pub width: Option<u32>,
    pub is_animated: Option<bool>,
    // ...
}
```

### Rich content messages

#### ExtendedTextMessage

Text with formatting, links, and quoted messages.

```rust theme={null}
pub struct ExtendedTextMessage {
    pub text: Option<String>,
    pub matched_text: Option<String>,
    pub canonical_url: Option<String>,
    pub description: Option<String>,
    pub title: Option<String>,
    pub thumbnail: Option<Vec<u8>>,
    pub context_info: Option<ContextInfo>,
    // ...
}
```

#### InteractiveMessage

Buttons, lists, and other interactive elements.

```rust theme={null}
pub struct InteractiveMessage {
    pub header: Option<interactive_message::Header>,
    pub body: Option<interactive_message::Body>,
    pub footer: Option<interactive_message::Footer>,
    pub context_info: Option<ContextInfo>,
    // One of:
    pub native_flow_message: Option<InteractiveMessage>,
    pub shop_storefront_message: Option<ShopMessage>,
    // ...
}
```

#### ButtonsMessage

```rust theme={null}
pub struct ButtonsMessage {
    pub content_text: Option<String>,
    pub footer_text: Option<String>,
    pub context_info: Option<ContextInfo>,
    pub buttons: Vec<buttons_message::Button>,
    pub header_type: Option<i32>,
    // ...
}
```

#### ListMessage

```rust theme={null}
pub struct ListMessage {
    pub title: Option<String>,
    pub description: Option<String>,
    pub button_text: Option<String>,
    pub list_type: Option<i32>,
    pub sections: Vec<list_message::Section>,
    pub context_info: Option<ContextInfo>,
    // ...
}
```

### Encryption Messages

#### SenderKeyDistributionMessage

Used for group message encryption.

```rust theme={null}
pub struct SenderKeyDistributionMessage {
    pub group_id: Option<String>,
    pub axolotl_sender_key_distribution_message: Option<Vec<u8>>,
}
```

#### PreKeySignalMessage

Used for establishing 1:1 encryption.

```rust theme={null}
pub struct PreKeySignalMessage {
    // Signal Protocol encrypted message
}
```

### System & protocol messages

#### ProtocolMessage

For protocol-level operations.

```rust theme={null}
pub struct ProtocolMessage {
    pub key: Option<MessageKey>,
    pub r#type: Option<i32>,  // DELETE, REVOKE, etc.
    pub ephemeral_expiration: Option<u32>,
    pub ephemeral_setting_timestamp: Option<i64>,
    // ...
}
```

**Common types:**

* `DELETE` - Delete message for everyone
* `REVOKE` - Revoke sent message
* `EPHEMERAL_SETTING` - Ephemeral message setting

#### ReactionMessage

```rust theme={null}
pub struct ReactionMessage {
    pub key: Option<MessageKey>,
    pub text: Option<String>,  // Emoji
    pub group_by_key: Option<bool>,
    pub sender_timestamp_ms: Option<i64>,
    pub unread: Option<bool>,
}
```

#### EditMessage

```rust theme={null}
pub struct EditMessage {
    pub key: Option<MessageKey>,
    pub message: Option<Box<Message>>,  // New message content
    pub timestamp_ms: Option<i64>,
}
```

#### AlbumMessage

Parent message for grouped media albums. Declares expected image/video counts so WhatsApp clients know how many items to group together.

```rust theme={null}
pub struct AlbumMessage {
    pub expected_image_count: Option<u32>,
    pub expected_video_count: Option<u32>,
    pub context_info: Option<Box<ContextInfo>>,
}
```

Each child media message is wrapped in `associated_child_message` (a `FutureProofMessage`) and linked to the parent via a `MessageAssociation`:

```rust theme={null}
pub struct MessageAssociation {
    pub association_type: Option<i32>,       // MediaAlbum = 1
    pub parent_message_key: Option<MessageKey>,
    pub message_index: Option<i32>,
}
```

Use `whatsapp_rust::proto_helpers::wrap_as_album_child` to construct album children. See [Sending Messages - Album messages](/guides/sending-messages#album-messages) for usage examples.

### AI & bot messages

#### AiRichResponseMessage

```rust theme={null}
pub struct AiRichResponseMessage {
    pub r#type: Option<i32>,
    pub sub_messages: Vec<AiRichResponseSubMessage>,
    // ...
}
```

#### BotFeedbackMessage

```rust theme={null}
pub struct BotFeedbackMessage {
    pub message_key: Option<MessageKey>,
    pub kind: Option<i32>,  // Thumbs up/down
    pub text: Option<String>,
    // ...
}
```

### Metadata & Context

#### MessageContextInfo

```rust theme={null}
pub struct MessageContextInfo {
    pub device_list_metadata: Option<DeviceListMetadata>,
    pub device_list_metadata_version: Option<i32>,
    pub message_secret: Option<Vec<u8>>,
    pub padding: Option<Vec<u8>>,
    pub message_add_on_duration_in_secs: Option<u32>,
    pub message_association: Option<MessageAssociation>, // Album/child linking
    // ...
}
```

#### ContextInfo

Quoted messages, mentions, and forwarding info.

```rust theme={null}
pub struct ContextInfo {
    pub stanza_id: Option<String>,
    pub participant: Option<String>,
    pub quoted_message: Option<Box<Message>>,
    pub remote_jid: Option<String>,
    pub mentioned_jid: Vec<String>,
    pub conversion_source: Option<String>,
    pub forwarding_score: Option<u32>,
    pub is_forwarded: Option<bool>,
    // ...
}
```

## Device & identity types

### ADV Messages

Account Device Verification messages.

```rust theme={null}
pub struct AdvDeviceIdentity {
    pub raw_id: Option<u32>,
    pub timestamp: Option<u64>,
    pub key_index: Option<u32>,
    pub account_type: Option<i32>,
    pub device_type: Option<i32>,
}

pub struct AdvSignedDeviceIdentity {
    pub details: Option<Vec<u8>>,
    pub account_signature_key: Option<Vec<u8>>,
    pub account_signature: Option<Vec<u8>>,
    pub device_signature: Option<Vec<u8>>,
}

pub struct AdvKeyIndexList {
    pub raw_id: Option<u32>,
    pub timestamp: Option<u64>,
    pub current_index: Option<u32>,
    pub valid_indexes: Vec<u32>,
    pub account_type: Option<i32>,
}
```

### Signal protocol structures

```rust theme={null}
pub struct PreKeyRecordStructure {
    pub id: Option<u32>,
    pub public_key: Option<Vec<u8>>,
    pub private_key: Option<Vec<u8>>,
}

pub struct SignedPreKeyRecordStructure {
    pub id: Option<u32>,
    pub public_key: Option<Vec<u8>>,
    pub private_key: Option<Vec<u8>>,
    pub signature: Option<Vec<u8>>,
    pub timestamp: Option<u64>,
}
```

## Handshake & connection types

### HandshakeMessage

Used during initial connection handshake.

```rust theme={null}
pub struct HandshakeMessage {
    pub client_hello: Option<ClientHello>,
    pub server_hello: Option<ServerHello>,
    pub client_finish: Option<ClientFinish>,
}
```

### ClientPayload

Device and client information during pairing.

```rust theme={null}
pub struct ClientPayload {
    pub username: Option<u64>,
    pub passive: Option<bool>,
    pub user_agent: Option<UserAgent>,
    pub web_info: Option<WebInfo>,
    pub push_name: Option<String>,
    pub session_id: Option<i32>,
    pub short_connect: Option<bool>,
    pub connect_type: Option<i32>,
    pub connect_reason: Option<i32>,
    // ...
}
```

## History sync types

### HistorySyncNotification

```rust theme={null}
pub struct HistorySyncNotification {
    pub file_sha256: Option<Vec<u8>>,
    pub file_length: Option<u64>,
    pub media_key: Option<Vec<u8>>,
    pub file_enc_sha256: Option<Vec<u8>>,
    pub direct_path: Option<String>,
    pub sync_type: Option<i32>,
    pub chunk_order: Option<u32>,
    pub original_message_id: Option<String>,
}
```

### HistorySync

```rust theme={null}
pub struct HistorySync {
    pub sync_type: Option<i32>,
    pub conversations: Vec<Conversation>,
    pub status_v3_messages: Vec<WebMessageInfo>,
    pub chunk_order: Option<u32>,
    pub progress: Option<u32>,
    // ...
}
```

## Media reference types

### ExternalBlobReference

References to uploaded media files.

```rust theme={null}
pub struct ExternalBlobReference {
    pub media_key: Option<Vec<u8>>,
    pub direct_path: Option<String>,
    pub handle: Option<String>,
    pub file_size_bytes: Option<u64>,
    pub file_sha256: Option<Vec<u8>>,
    pub file_enc_sha256: Option<Vec<u8>>,
}
```

## App state types

### SyncActionValue

App state synchronization actions.

```rust theme={null}
pub struct SyncActionValue {
    pub timestamp: Option<i64>,
    // One of many action types:
    pub contact_action: Option<ContactAction>,
    pub mute_action: Option<MuteAction>,
    pub pin_action: Option<PinAction>,
    pub security_notification_setting: Option<SecurityNotificationSetting>,
    pub push_name_setting: Option<PushNameSetting>,
    pub archive_chat_action: Option<ArchiveChatAction>,
    pub delete_chat_action: Option<DeleteChatAction>,
    pub star_action: Option<StarAction>,
    // ... and many more
}
```

## Enums

waproto includes many enum types (as i32 values with const definitions):

```rust theme={null}
// Message types
pub mod protocol_message {
    pub enum Type {
        Revoke = 0,
        EphemeralSetting = 3,
        EphemeralSyncResponse = 4,
        HistorySyncNotification = 5,
        AppStateSyncKeyShare = 6,
        AppStateSyncKeyRequest = 7,
        Delete = 8,
        // ...
    }
}

// Media types
pub mod video_message {
    pub enum Attribution {
        None = 0,
        Giphy = 1,
        Tenor = 2,
    }
}
```

## Feature flags

| Feature             | Description                                                                                                                                                                                     | Implies             |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- |
| `serde-deserialize` | Adds `#[derive(serde::Deserialize)]` and `#[serde(default)]` to all types. Use when you need to parse protobuf types from JSON.                                                                 | —                   |
| `serde-snake-case`  | Adds `#[serde(rename_all(deserialize = "snake_case"))]` to all types. Allows snake\_case enum variant names during deserialization (prost generates PascalCase). Serialize output is unchanged. | `serde-deserialize` |

<Note>
  The `generate` feature was removed in [#836](https://github.com/oxidezap/whatsapp-rust/pull/836). Code generation is now always-on — `prost-build`, `heck`, and `prost-types` are unconditional build dependencies. Remove `--features generate` from any build scripts.
</Note>

## Serde support

All generated types derive `serde::Serialize` by default. Deserialization and snake\_case renaming are behind optional feature flags (`serde-deserialize` and `serde-snake-case` above).

Enable them in your `Cargo.toml`:

```toml theme={null}
[dependencies]
waproto = { version = "0.6", features = ["serde-snake-case"] }
```

### Default behavior (no feature flags)

All types derive `Serialize` only:

```rust theme={null}
#[derive(serde::Serialize)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Message {
    // ...
}
```

This allows JSON serialization for debugging:

```rust theme={null}
let json = serde_json::to_string_pretty(&message)?;
println!("Message: {}", json);
```

### With `serde-deserialize`

All types also derive `Deserialize` with `#[serde(default)]`, matching protobuf semantics where missing fields use default values:

```rust theme={null}
#[derive(serde::Serialize)]
#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
#[cfg_attr(feature = "serde-deserialize", serde(default))]
pub struct Message {
    // ...
}
```

### With `serde-snake-case`

All types additionally accept snake\_case during deserialization. This primarily affects enum and oneof variants (prost generates PascalCase names), while struct fields are already snake\_case. Serialization output remains unchanged.

```rust theme={null}
// Without serde-snake-case: must use PascalCase
let json = r#"{"accountType": "Enterprise"}"#;

// With serde-snake-case: snake_case also accepted
let json = r#"{"account_type": "enterprise"}"#;
```

<Note>
  The `serde-snake-case` feature is primarily useful for WASM bridge scenarios where JavaScript sends snake\_case JSON to the Rust backend. For most Rust-only use cases, you only need the default `Serialize` support.
</Note>

## waproto::tags

The build generates the `waproto::tags` module from the compiled protobuf descriptor. You get one `pub mod` per proto message with one `pub const FIELD_NAME: u32 = N;` per field. Nested messages produce nested modules.

```rust theme={null}
use waproto::tags;

// Field numbers derived directly from whatsapp.proto
let _ = tags::web_message_info::KEY;           // 1
let _ = tags::web_message_info::MESSAGE;       // 2
let _ = tags::message::MESSAGE_CONTEXT_INFO;   // 35
let _ = tags::history_sync::CONVERSATIONS;     // 2
let _ = tags::history_sync::PUSHNAMES;         // 7
```

The history-sync wire walkers use these constants internally, and compile-time `assert!` blocks pin them in the hand-written mirror structs. If `whatsapp.proto` renumbers a field the consts update automatically on next build; if a field referenced by the walkers is renamed or removed, compilation fails rather than the decoder silently reading the wrong wire data.

## Code generation

The build generates protobuf code — `build.rs` always runs. It reads the committed binary descriptor (`src/whatsapp.desc`), verifies its SHA-256 against `src/whatsapp.desc.sha256`, and writes two files into `OUT_DIR`:

* **`whatsapp.rs`** — full prost-generated structs and enums
* **`tags.rs`** — `waproto::tags` field-number constants (see [waproto::tags](#waprototags) above)

Neither generated file is committed. `prost-build`, `heck`, and `prost-types` are unconditional build dependencies.

**To update after modifying `whatsapp.proto`:**

```bash theme={null}
scripts/regenerate-proto-desc.sh   # writes waproto/src/whatsapp.desc + .sha256
cargo build -p waproto             # regenerates whatsapp.rs and tags.rs
```

The build aborts with a clear message if the descriptor SHA-256 does not match.

<Note>
  The `generate` feature flag was removed. Code generation is now always-on and does not require any feature flags. Remove `--features generate` from any existing build scripts.
</Note>

## Usage Examples

### Constructing Messages

```rust theme={null}
use waproto::whatsapp as wa;

// Text message
let text = wa::Message {
    conversation: Some("Hello!".to_string()),
    ..Default::default()
};

// Image with caption
let image = wa::Message {
    image_message: Some(Box::new(wa::message::ImageMessage {
        url: Some(media_url),
        media_key: Some(media_key.to_vec()),
        file_sha256: Some(file_sha256.to_vec()),
        file_enc_sha256: Some(file_enc_sha256.to_vec()),
        caption: Some("Nice photo!".to_string()),
        jpeg_thumbnail: Some(thumbnail),
        ..Default::default()
    })),
    ..Default::default()
};

// Quoted reply
let reply = wa::Message {
    extended_text_message: Some(Box::new(wa::message::ExtendedTextMessage {
        text: Some("Great question!".to_string()),
        context_info: Some(Box::new(wa::message::ContextInfo {
            stanza_id: Some(original_message_id),
            participant: Some(original_sender),
            quoted_message: Some(Box::new(original_message)),
            ..Default::default()
        })),
        ..Default::default()
    })),
    ..Default::default()
};
```

### Pattern Matching

```rust theme={null}
match &proto_msg {
    wa::Message { conversation: Some(text), .. } => {
        println!("Text: {}", text);
    }
    wa::Message { image_message: Some(img), .. } => {
        println!("Image from: {}", img.url.as_ref().unwrap());
    }
    wa::Message { video_message: Some(vid), .. } => {
        println!("Video: {} seconds", vid.seconds.unwrap_or(0));
    }
    _ => println!("Other message type"),
}
```

### Media Downloads

See [Media Handling](/guides/media-handling) for complete examples.

```rust theme={null}
use waproto::whatsapp as wa;
use wacore::download::{Downloadable, MediaType};

if let Some(img) = &message.image_message {
    // Use the Downloadable trait to download and decrypt
    let data = client.download(img).await?;
}
```

## WhatsApp Version

The protobuf definitions are based on:

```rust theme={null}
// This file is @generated by prost-build.
// WhatsApp Version: 2.3000.1035617621
```

This version is automatically included in the generated file header.

## Relationship with wacore

wacore provides utilities for working with waproto messages:

* **`proto_helpers`** - Conversion between protobuf and internal types
* **`download`** - `Downloadable` trait for media messages
* **`upload`** - Media encryption for upload
* **`messages`** - Message encryption/decryption
* **`send`** - Message building and sending

Example:

```rust theme={null}
use wacore::proto_helpers;
use waproto::whatsapp as wa;

// Convert internal JID to protobuf MessageKey
let key = proto_helpers::message_key(&jid, &message_id, from_me);

// Build delete message
let delete = wa::Message {
    protocol_message: Some(wa::ProtocolMessage {
        key: Some(key),
        r#type: Some(wa::protocol_message::Type::Delete as i32),
        ..Default::default()
    }),
    ..Default::default()
};
```

## Next Steps

<CardGroup cols={2}>
  <Card title="wacore" icon="cube" href="/api/wacore">
    Platform-agnostic protocol implementation
  </Card>

  <Card title="Sending Messages" icon="message" href="/guides/sending-messages">
    Sending and receiving messages
  </Card>

  <Card title="Media Handling" icon="image" href="/guides/media-handling">
    Working with media uploads and downloads
  </Card>

  <Card title="Signal Protocol" icon="shield" href="/advanced/signal-protocol">
    End-to-end encryption details
  </Card>
</CardGroup>
