### Spawn Bot Example
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/bot-api.md
Start the bot on its runtime and return a BotHandle for background control. This example shows how to spawn the bot and then wait for a shutdown signal.
```rust
let handle = bot.spawn();
tokio::signal::ctrl_c().await?;
handle.shutdown().await;
```
--------------------------------
### Install and Run evcxr REPL
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/agent_docs/debugging.md
Install the evcxr_repl tool using cargo binstall and run it from the project root for interactive debugging.
```bash
cargo binstall evcxr_repl -y
evcxr # run from project root
```
--------------------------------
### Get User Info Example
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/contacts-presence-api.md
Demonstrates how to retrieve detailed profile information for a specific user using their JID. Requires an active client connection.
```rust
let info = client.contacts().get_user_info(&user_jid).await?;
println!("Platform: {:?}", info.platform);
println!("Status: {:?}", info.status);
```
--------------------------------
### BotBuilder Example: Building a Bot with SqliteStore
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/bot-api.md
Demonstrates how to create a Bot instance by providing a SqliteStore as the backend using the BotBuilder.
```rust
let bot = Bot::builder()
.with_backend(SqliteStore::new("whatsapp.db").await?)
.build()
.await?;
```
--------------------------------
### Run Bot Example
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/bot-api.md
Run the bot on the current task until it shuts down. This example shows how to build and run a bot with a message handler.
```rust
#[tokio::main]
async fn main() -> Result<()> {
let bot = Bot::builder()
.with_backend(SqliteStore::new("whatsapp.db").await?)
.on_message(|ctx| async move {
let _ = ctx.reply("Hello!").await;
})
.build()
.await?;
bot.run().await;
Ok(())
}
```
--------------------------------
### Get Blocklist Example
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/contacts-presence-api.md
Retrieves the current blocklist and iterates through each entry, printing the blocked JID and timestamp. Ensure the client is initialized.
```rust
let blocklist = client.blocking().get_blocklist().await?;
for entry in blocklist {
println!("Blocked: {} at {}", entry.jid, entry.blocked_at);
}
```
--------------------------------
### Minimal Bot Configuration
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/configuration-errors.md
Sets up a basic bot with a SQLite storage backend and a simple message handler. This is a good starting point for new bots.
```rust
let bot = Bot::builder()
.with_backend(SqliteStore::new("bot.db").await?)
.on_message(|ctx| async move {
println!("Got message from {}", ctx.info.source.sender);
})
.build()
.await?;
bot.run().await;
```
--------------------------------
### Custom Backend Implementation Example
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/storage-backend.md
Provides a template for implementing a custom storage backend by fulfilling the `Backend` trait. Ensure thread/async safety and handle serialization/encoding as per notes.
```rust
#[async_trait]
impl Backend for MyCustomStore {
async fn get_device(&self) -> Result, StoreError> {
// Query your database
}
async fn put_device(&self, device: &Device) -> Result<(), StoreError> {
// Persist to your database
}
// ... implement all other trait methods ...
}
// Use with the bot
let store = MyCustomStore::new()?;
let bot = Bot::builder()
.with_backend(store)
.build()
.await?;
```
--------------------------------
### Upload and Send Media
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/INDEX.md
This example demonstrates how to upload media files (like images) and then send them as messages. Ensure the media file exists and is readable. The `upload_media` function handles encryption and returns necessary metadata for constructing the message.
```rust
let image_bytes = std::fs::read("photo.jpg").await?;
let uploaded = client.upload_media(
&image_bytes,
UploadOptions {
file_size: image_bytes.len() as u64,
media_type: MediaType::Image,
..Default::default()
}
).await?;
let msg = wa::Message {
image_message: Some(Box::new(wa::message::ImageMessage {
url: Some(uploaded.url),
file_length: Some(image_bytes.len() as u64),
media_key: Some(uploaded.media_key.into()),
mime_type: Some("image/jpeg".to_string()),
sha256: Some(uploaded.file_sha256.into()),
file_sha256: Some(uploaded.file_sha256.into()),
..Default::default()
})),
..Default::default()
};
client.send_message(&chat, msg).await?;
```
--------------------------------
### Minimal whatsapp-rust Dependency
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/INDEX.md
Example of how to configure the whatsapp-rust dependency in Cargo.toml with minimal features enabled.
```toml
[dependencies]
whatsapp-rust = { version = "0.6", default-features = false, features = ["tokio-runtime"] }
```
--------------------------------
### Lookup Contacts and Presence
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/INDEX.md
This example covers checking if a phone number is on WhatsApp, retrieving user information (like status and platform), subscribing to presence updates, setting your own presence status, and fetching profile pictures. It utilizes `client.contacts()` and `client.presence()` accessors.
```rust
// Check if number is on WhatsApp
let is_registered = client.contacts().is_on_whatsapp(&phone_jid).await?;
// Get user info
let info = client.contacts().get_user_info(&user_jid).await?;
println!("Platform: {:?}", info.platform);
println!("Status: {:?}", info.status);
// Subscribe to presence updates
client.presence().subscribe_presence(&user_jid).await?;
// Set your presence
client.presence().set_presence(PresenceStatus::Online).await?;
// Get profile picture
if let Some(pic) = client.contacts().get_profile_picture(&jid, true).await? {
println!("Picture URL: {}", pic.url);
}
```
--------------------------------
### Implementing a Custom Storage Backend
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/INDEX.md
Implement the `Backend` trait to provide a custom storage solution, such as persisting data to PostgreSQL. This involves defining methods for getting and putting device information.
```rust
#[async_trait]
impl Backend for MyPostgresStore {
async fn get_device(&self) -> Result , StoreError> {
// Query PostgreSQL
}
async fn put_device(&self, device: &Device) -> Result<(), StoreError> {
// Persist to PostgreSQL
}
// ... implement all other methods ...
}
let store = MyPostgresStore::new(connection_pool)?;
let bot = Bot::builder()
.with_backend(store)
.build()
.await?;
```
--------------------------------
### Query Group Info Example
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/groups-api.md
Queries and retrieves metadata for a specific group. Results are cached and returned as an Arc-wrapped GroupInfo object. Ensure the JID is correctly formatted.
```rust
let group_info = client.groups().query_info(&group_jid).await?;
println!("Group: {}", group_info.subject);
println!("Participants: {}", group_info.participants.len());
```
--------------------------------
### Enable Metrics Support
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/configuration-errors.md
Add the 'metrics' feature to your Cargo.toml and install a metrics recorder, such as Prometheus, to emit counters and histograms. This allows for monitoring application performance.
```toml
whatsapp-rust = { version = "0.6", features = ["metrics"] }
```
```rust
use metrics_exporter_prometheus::formatting::PrometheusBuilder;
PrometheusBuilder::new()
.install_recorder()
.unwrap();
```
--------------------------------
### Nibble Encoding Examples
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/agent_docs/debugging.md
Illustrates the expected input and output for nibble encoding, a method used for numeric strings in WhatsApp's binary protocol. Refer to `wacore/binary/src/nibble.rs` for the implementation.
```rust
// Decode: "100000000000001f" -> "100000000000001"
// Encode: "100000000000001" -> "100000000000001f"
```
--------------------------------
### Enable Tracing Support
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/configuration-errors.md
Add the 'tracing' feature to your Cargo.toml and install a tracing subscriber to emit structured logs. The subscriber can be configured using environment variables.
```toml
whatsapp-rust = { version = "0.6", features = ["tracing"] }
```
```rust
use tracing_subscriber::filter::EnvFilter;
tracing_subscriber::fmt()
.with_env_filter(EnvFilter::from_default_env())
.init();
```
--------------------------------
### Shutdown BotHandle Example
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/bot-api.md
Gracefully stop the bot by calling the shutdown method on the BotHandle. This disconnects, flushes state, and waits for the run loop to exit.
```rust
let handle = bot.spawn();
// ... later ...
handle.shutdown().await;
```
--------------------------------
### Build and Launch
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/bot-api.md
Finalize configuration and construct the Bot instance.
```APIDOC
## async fn build(self) -> Result
### Description
Finalize configuration and construct the `Bot`. Only available when all required fields are `Provided`.
### Parameters
#### Path Parameters
- None
#### Query Parameters
- None
#### Request Body
- None
### Returns
- `Result`
### Errors
- `BotBuilderError::Store` — device store initialization failed
### Example
```rust
let bot = Bot::builder()
.with_backend(SqliteStore::new("whatsapp.db").await?)
.build()
.await?;
```
```
--------------------------------
### Build and Verify Project
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/AGENTS.md
Commands to format, lint, test, and run end-to-end tests for the project. Ensure the mock server is running for e2e tests.
```bash
cargo fmt --all
cargo clippy --all --tests
cargo test --all
cargo test -p e2e-tests # requires mock server running
```
--------------------------------
### Get Blocklist
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/contacts-presence-api.md
Retrieve the current list of blocked users.
```APIDOC
## get_blocklist
### Description
Get the current blocklist.
### Method
`async fn get_blocklist(&self) -> Result, BlockingError>`
### Response
#### Success Response (200)
- **blocklist** (`Vec`) - A list of blocked users, each with their JID and the timestamp they were blocked.
#### Response Example
```json
{
"blocklist": [
{
"jid": "user@example.com",
"blocked_at": 1678886400
}
]
}
```
#### Error Response
- `BlockingError` - Possible errors include IQ errors, invalid requests, or internal errors.
### Example
```rust
let blocklist = client.blocking().get_blocklist().await?;
for entry in blocklist {
println!("Blocked: {} at {}", entry.jid, entry.blocked_at);
}
```
```
--------------------------------
### Initialize and Run Bot with Tokio in Rust
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/INDEX.md
Demonstrates setting up the bot with a persistence backend and running it within the Tokio async runtime. The `bot.run()` method blocks until the bot disconnects.
```rust
#[tokio::main]
async fn main() {
let bot = Bot::builder()
.with_backend(store)
.build()
.await?;
bot.run().await; // Blocks until disconnect
}
```
--------------------------------
### Get Status
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/contacts-presence-api.md
Retrieves the client's current status text.
```APIDOC
## get_status
### Description
Get the client's status text.
### Method
`async fn get_status(&self) -> Result, ProfileError>`
### Response
#### Success Response
- `Option` - The current status text, or None if no status is set.
```
--------------------------------
### Get Invite Link
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/groups-api.md
Retrieves the current invite link for a given group.
```APIDOC
## get_invite_link
### Description
Get the group's invite link.
### Method
```rust
async fn get_invite_link(&self, jid: &Jid) -> Result
```
### Parameters
#### Path Parameters
- **jid** (`&Jid`) - Required - Group JID
### Returns
- `Result` - full invite URL
```
--------------------------------
### Initialize SQLite Store and Bot
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/storage-backend.md
Initializes the SQLite storage backend and the Bot with the configured store. Requires an async context.
```rust
use whatsapp_rust::store::SqliteStore;
let store = SqliteStore::new("whatsapp.db").await?;
let bot = Bot::builder()
.with_backend(store)
.build()
.await?;
```
--------------------------------
### message_key
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/bot-api.md
Gets the referential `MessageKey` for reactions, omitting the participant for 1-on-1 chats.
```APIDOC
## fn message_key(&self) -> wa::MessageKey
### Description
Get the referential `MessageKey` for reactions. Omits participant for 1-on-1 chats.
### Parameters
* None
### Returns
* **wa::MessageKey** - The message key for reactions.
```
--------------------------------
### Get Membership Requests
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/groups-api.md
Retrieves a list of pending join requests for approval groups.
```APIDOC
## get_membership_requests
### Description
Get pending join requests (approval groups only).
### Method
```rust
async fn get_membership_requests(&self, jid: &Jid) -> Result, GroupError>
```
### Parameters
#### Path Parameters
- **jid** (`&Jid`) - Required - Group JID
### Returns
- `Result, GroupError>`
```
--------------------------------
### Get User Info
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/contacts-presence-api.md
Retrieves detailed profile information for a given user JID.
```APIDOC
## get_user_info
### Description
Get detailed profile information for a user.
### Method
`async fn get_user_info(&self, jid: &Jid) -> Result`
### Parameters
#### Path Parameters
- **jid** (`&Jid`) - Required - User JID or phone number JID
### Response
#### Success Response (UserInfo)
- **jid** (`Jid`) - User JID (@s.whatsapp.net)
- **phone_number** (`Option`) - Phone number JID (PN addressing)
- **platform** (`Option`) - "android", "iphone", "web", etc.
- **exists_on_whatsapp** (`bool`) - Whether the number is registered
- **status** (`Option`) - User bio/status text
- **status_timestamp** (`Option`) - When status was set (Unix seconds)
- **verified_name** (`Option`) - Verified business name
- **business_profile** (`Option`) - Business account information
### Request Example
```rust
let info = client.contacts().get_user_info(&user_jid).await?;
println!("Platform: {:?}", info.platform);
println!("Status: {:?}", info.status);
```
```
--------------------------------
### Run Included Demo Bot
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/README.md
These bash commands show how to run the included demo bot from the command line with different options for pairing.
```bash
cargo run --example demo # QR code only
```
```bash
cargo run --example demo -- -p 15551234567 # Pair code + QR code
```
```bash
cargo run --example demo -- -p 15551234567 -c MYCODE # Custom pair code
```
--------------------------------
### Simplified IQ Execution
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/agent_docs/protocol_architecture.md
Shows how to use `Client::execute()` for a single-call IQ request and response handling, replacing manual build, send, and parse steps.
```rust
// Single call replaces manual build + send + parse
let response = client.execute(GroupQueryIq::new(&jid)).await?;
```
--------------------------------
### Get Invite Info
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/groups-api.md
Retrieves group metadata using an invite code without joining the group.
```APIDOC
## get_invite_info
### Description
Get group info from an invite code (without joining).
### Method
```rust
async fn get_invite_info(&self, invite_code: &str) -> Result
```
### Parameters
#### Path Parameters
- **invite_code** (`&str`) - Required - Invite code
### Returns
- `Result` - group metadata
```
--------------------------------
### Get Profile Picture
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/contacts-presence-api.md
Retrieves a user's profile picture, with an option to request the highest quality.
```APIDOC
## get_profile_picture
### Description
Get a user's profile picture.
### Method
`async fn get_profile_picture(&self, jid: &Jid, highest_quality: bool) -> Result, ContactError>`
### Parameters
#### Path Parameters
- **jid** (`&Jid`) - Required - User JID
- **highest_quality** (`bool`) - Required - Request highest resolution
### Response
#### Success Response (Option)
- The profile picture URL and ID, or None if no picture is available.
#### Response Example
`Option`
```
--------------------------------
### Get Identity Key Pair
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/storage-backend.md
Retrieves the long-lived identity key pair used for signing pre-keys.
```rust
let ikp = backend.get_identity_key_pair().await?;
```
--------------------------------
### Initialize SQLite Store with Custom Path
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/storage-backend.md
Initializes the SQLite storage backend using a custom file path for the database.
```rust
let store = SqliteStore::new("/path/to/custom/location.db").await?;
```
--------------------------------
### Initialize SQLite Persistence Store in Rust
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/INDEX.md
Demonstrates how to initialize the `SqliteStore` for persisting WhatsApp data, such as Signal sessions and group metadata. The database schema is automatically created on the first run.
```rust
let store = SqliteStore::new("whatsapp.db").await?;
```
--------------------------------
### Get Profile Pictures Batch
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/contacts-presence-api.md
Retrieves profile pictures for multiple users in a batch, with an option for highest quality.
```APIDOC
## get_profile_pictures_batch
### Description
Get profile pictures for multiple users.
### Method
`async fn get_profile_pictures_batch(&self, jids: Vec, highest_quality: bool) -> Result)>, ContactError>`
### Parameters
#### Path Parameters
- **jids** (`Vec`) - Required - User JIDs
- **highest_quality** (`bool`) - Required - Request highest resolution
### Response
#### Success Response (Vec<(Jid, Option)`)
- A vector of tuples, where each tuple contains a user JID and their profile picture information (or None).
#### Response Example
`Vec<(Jid, Option)>`
```
--------------------------------
### Get Signed Pre-Key
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/storage-backend.md
Retrieves the signed pre-key and its identifier. This special pre-key is renewed periodically for signature verification.
```rust
let (spk_id, spk_bytes) = backend.get_signed_pre_key().await?;
```
--------------------------------
### Bot with Custom Transport and HTTP Client
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/configuration-errors.md
Illustrates how to integrate custom implementations for transport, HTTP client, and the async runtime. Replace `MyCustomTransport`, `MyHttpClient`, and `MyCustomRuntime` with your specific types.
```rust
let bot = Bot::builder()
.with_backend(SqliteStore::new("bot.db").await?)
.with_transport_factory(MyCustomTransport)
.with_http_client(MyHttpClient)
.with_runtime(MyCustomRuntime)
.build()
.await?;
```
--------------------------------
### Bot::builder()
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/bot-api.md
Creates a new BotBuilder with default transport, HTTP client, and runtime. The storage backend is always required and must be provided explicitly.
```APIDOC
## Bot::builder()
### Description
Creates a new builder with default transport (Tokio WebSocket), HTTP client (ureq), and runtime (Tokio) if their features are enabled. The storage backend is always required and must be provided explicitly.
### Returns
`BotBuilder` - A new builder instance.
### Example
```rust
let bot = Bot::builder()
.with_backend(SqliteStore::new("whatsapp.db").await?)
.build()
.await?;
```
```
--------------------------------
### Get Participating Groups
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/groups-api.md
Retrieves a list of JIDs for all groups the client is currently a member of. This is useful for iterating through accessible groups.
```rust
let participating_groups = client.groups().participating_groups().await?;
```
--------------------------------
### Basic Bot Implementation with QR Code
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/README.md
This Rust code sets up a basic WhatsApp bot using the whatsapp-rust library. It configures a SQLite store, provides a callback for QR code generation, and handles incoming messages to reply 'pong' to 'ping'. The bot runs until explicitly logged out or shut down.
```rust
use whatsapp_rust::prelude::*;
#[tokio::main] async fn main() -> Result<(), Box> {
let bot = Bot::builder()
.with_backend(SqliteStore::new("whatsapp.db").await?)
.on_qr_code(|code, _timeout| async move {
println!("Scan to pair:\n{code}");
})
.on_message(|ctx| async move {
if ctx.message.text_content() == Some("ping") {
let _ = ctx.reply("pong").await;
}
})
.build()
.await?;
// Runs until logout or shutdown; a single await.
bot.run().await;
Ok(())
}
```
--------------------------------
### Get Group Profile Picture
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/groups-api.md
Retrieves the group's profile picture. You can specify whether to request the highest quality available.
```APIDOC
## get_profile_picture
### Description
Get the group's profile picture.
### Method
`async fn get_profile_picture(&self, jid: &Jid, highest_quality: bool) -> Result, GroupError>`
### Parameters
#### Path Parameters
- **jid** (`&Jid`) - Required - Group JID
- **highest_quality** (`bool`) - Required - Request highest resolution
### Returns
- **Result , GroupError>** — picture URL and ID
```
--------------------------------
### Build WhatsApp Messages
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/types-reference.md
Shows how to construct various types of WhatsApp messages, including text, images, and replies with context.
```rust
use wacore::proto_helpers::MessageBuilderExt;
let msg = wa::Message::text("Hello");
let msg = wa::Message::image(
"https://...".to_string(),
vec![/* 32-byte media key */],
vec![/* SHA256 hash */],
12345, // file size
);
let quoted_msg = wa::Message::text_with_context(
"Reply text",
wa::ContextInfo {
stanza_id: Some("original_msg_id".to_string()),
participant: Some(original_sender.to_string()),
..Default::default()
}
);
```
--------------------------------
### Get Group Metadata from Backend
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/storage-backend.md
Retrieves group metadata from the backend and deserializes it from JSON. Ensure the backend implementation supports this operation.
```rust
let metadata: GroupInfo = serde_json::from_slice(
&backend.get_group_metadata("group@g.us").await?
)?;
```
--------------------------------
### Build a Simple Bot with Message Reply
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/INDEX.md
Use this snippet to create a basic bot that responds to messages. It requires setting up a storage backend and defining a message handler. The bot will reply 'pong' if it receives the message 'ping'.
```rust
use whatsapp_rust::prelude::*;
#[tokio::main]
async fn main() -> Result<()> {
let bot = Bot::builder()
.with_backend(SqliteStore::new("bot.db").await?)
.on_message(|ctx| async move {
if ctx.message.text_content() == Some("ping") {
let _ = ctx.reply("pong").await;
}
})
.build()
.await?;
bot.run().await;
Ok(())
}
```
--------------------------------
### Handle SendMessage Errors with Match
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/types-reference.md
Provides a comprehensive example of using a match statement to handle various potential errors when sending a message.
```rust
match client.send_message(&chat, msg).await {
Ok(result) => {
println!("Sent: {}", result.message_id);
}
Err(SendError::NotLoggedIn) => {
eprintln!("Not logged in, pairing required");
}
Err(SendError::Client(ClientError::NotConnected)) => {
eprintln!("No connection, retrying...");
}
Err(SendError::Iq(IqError::Timeout)) => {
eprintln!("Server timeout, message lost");
}
Err(SendError::InvalidRequest(msg)) => {
eprintln!("Invalid: {}", msg);
}
Err(e) => {
eprintln!("Unknown error: {}", e);
}
}
```
--------------------------------
### Get Message Key for Reactions
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/bot-api.md
Retrieves the `MessageKey` for the incoming message, which is used for operations like reactions. It omits the participant for 1-on-1 chats.
```rust
fn message_key(&self) -> wa::MessageKey
```
--------------------------------
### Configuration Methods
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/bot-api.md
Methods to configure the bot's behavior, including cache, rate limits, and device properties.
```APIDOC
## with_cache_config(config: CacheConfig) -> Self
### Description
Configure in-memory cache behavior (TTLs, capacity bounds, secret retention).
### Parameters
#### Path Parameters
- None
#### Query Parameters
- None
#### Request Body
- None
### Parameters
- **config** (`CacheConfig`) - Required - Cache configuration object
### Returns
- `Self`
```
```APIDOC
## with_wanted_pre_key_count(count: usize) -> Self
### Description
Set the target Signal pre-key count to maintain (default 20).
### Parameters
#### Path Parameters
- None
#### Query Parameters
- None
#### Request Body
- None
### Parameters
- **count** (`usize`) - Required - Target Signal pre-key count
### Returns
- `Self`
```
```APIDOC
## with_resend_rate_limit(max_resends: u32, window_secs: u32) -> Self
### Description
Limit outbound resends per chat to prevent flooding on network recovery.
### Parameters
#### Path Parameters
- None
#### Query Parameters
- None
#### Request Body
- None
### Parameters
- **max_resends** (`u32`) - Required - Maximum number of resends allowed
- **window_secs** (`u32`) - Required - Time window in seconds for rate limiting
### Returns
- `Self`
```
```APIDOC
## with_pair_code(options: PairCodeOptions) -> Self
### Description
Enable pair-code linking instead of QR-only pairing.
### Parameters
#### Path Parameters
- None
#### Query Parameters
- None
#### Request Body
- None
### Parameters
- **options** (`PairCodeOptions`) - Required - Options for pair-code linking
### Returns
- `Self`
```
```APIDOC
## with_device_props_override(props: DevicePropsOverride) -> Self
### Description
Override device properties like model, manufacturer, and OS version reported to the server.
### Parameters
#### Path Parameters
- None
#### Query Parameters
- None
#### Request Body
- None
### Parameters
- **props** (`DevicePropsOverride`) - Required - Overridden device properties
### Returns
- `Self`
```
```APIDOC
## skip_history_sync() -> Self
### Description
Skip history sync on connection (useful for bots that don't need chat backlog).
### Parameters
#### Path Parameters
- None
#### Query Parameters
- None
#### Request Body
- None
### Returns
- `Self`
```
```APIDOC
## with_initial_push_name(name: String) -> Self
### Description
Set the initial push name (display name) sent to the server on first connection.
### Parameters
#### Path Parameters
- None
#### Query Parameters
- None
#### Request Body
- None
### Parameters
- **name** (`String`) - Required - Initial push name
### Returns
- `Self`
```
--------------------------------
### Spawn Bot in Background with Tokio in Rust
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/INDEX.md
Shows how to spawn the bot to run in the background, allowing the main thread to continue. Includes handling graceful shutdown using Tokio signals.
```rust
let handle = bot.spawn(); // Returns immediately, bot runs on runtime
tokio::signal::ctrl_c().await?;
handle.shutdown().await; // Graceful shutdown
```
--------------------------------
### HttpClient Trait
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/types-reference.md
Abstraction for HTTP clients, providing methods for making GET and POST requests, essential for media upload and download operations.
```APIDOC
## HttpClient Trait
### Description
Provides an abstraction for HTTP clients, used for operations like media upload and download.
### Methods
- **get(url: &str)**: Performs an HTTP GET request to the specified URL.
- **post(url: &str, body: Vec)**: Performs an HTTP POST request to the specified URL with the given request body.
### Implementations
- `UreqHttpClient`: An implementation using the `ureq` library, with blocking I/O handled via `tokio::spawn_blocking`.
```
--------------------------------
### IqNamespace Enum
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/types-reference.md
Defines the different types of IQ (Information Query) namespaces used for XMPP communication, such as get, set, result, and error.
```APIDOC
## IqNamespace Enum
### Description
Represents the different types of IQ (Information Query) requests in XMPP communication.
### Enum Variants
- **Get**: Represents an IQ request to retrieve information.
- **Set**: Represents an IQ request to set information.
- **Result**: Represents the result of an IQ request.
- **Error**: Represents an error response to an IQ request.
```
--------------------------------
### create
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/groups-api.md
Creates a new group with the specified options, including name, participants, and description.
```APIDOC
## create
### Description
Create a new group.
### Method
POST
### Endpoint
/groups
### Parameters
#### Request Body
- **subject** (string) - Required - The name of the group.
- **participants** (array of Jid) - Required - Initial participants for the group.
- **description** (string) - Optional - A description for the group.
### Response
#### Success Response (200)
- **metadata** (CreateGroupResult) - Metadata of the created group, including its ID.
### Errors
- `GroupError::InvalidRequest` — invalid options (empty name, duplicate participants)
- `GroupError::Iq` — server rejected creation
```
--------------------------------
### HTTP Client Trait
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/types-reference.md
Abstract trait for HTTP clients, defining methods for GET and POST requests. Used for media upload/download operations.
```rust
#[async_trait]
pub trait HttpClient: Send + Sync {
async fn get(&self, url: &str) -> Result;
async fn post(&self, url: &str, body: Vec) -> Result;
}
```
--------------------------------
### Get Device Snapshot
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/storage-backend.md
Retrieves a cached snapshot of the device state. Snapshots are refcount-efficient (Arc) and safe to clone across tasks.
```rust
let snapshot = client.get_device_snapshot().await;
let jid = &snapshot.jid;
```
--------------------------------
### UploadOptions Struct for Media Uploads
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/media-upload-download.md
Defines the configuration options for uploading media files. Specify file size, media type, and optionally filename or a custom thumbnail.
```rust
pub struct UploadOptions {
pub file_size: u64,
pub media_type: MediaType,
pub file_name: Option,
pub thumbnail: Option>,
pub generate_missing_thumbnail: bool,
}
```
--------------------------------
### Bot::builder() Constructor
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/bot-api.md
Creates a new BotBuilder instance with default configurations for transport, HTTP client, and runtime. The storage backend must always be explicitly provided.
```rust
pub fn builder() -> BotBuilder
```
--------------------------------
### Bot Methods
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/bot-api.md
Provides access to the underlying client and methods to run or spawn the bot.
```APIDOC
## Bot
The main client entry point after configuration.
```rust
pub struct Bot {
client: Arc,
// ... internal fields
}
```
### Methods
#### `fn client(&self) -> Arc`
Access the underlying `Client` for direct API calls (messaging, contacts, groups, etc.).
#### `async fn run(self)`
Run the bot on the current task until it shuts down (logout or `Client::disconnect()` from another task).
**Example:**
```rust
#[tokio::main]
async fn main() -> Result<()> {
let bot = Bot::builder()
.with_backend(SqliteStore::new("whatsapp.db").await?)
.on_message(|ctx| async move {
let _ = ctx.reply("Hello!").await;
})
.build()
.await?;
bot.run().await;
Ok(())
}
```
#### `fn spawn(self) -> BotHandle`
Start the bot on its runtime and return a `BotHandle` for background control.
**Returns:** `BotHandle` — handle for awaiting, graceful shutdown, or abort
**Example:**
```rust
let handle = bot.spawn();
tokio::signal::ctrl_c().await?;
handle.shutdown().await;
```
```
--------------------------------
### Check if User is on WhatsApp Example
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/contacts-presence-api.md
Shows how to check if a given phone number is registered on WhatsApp. This is useful for verifying user existence before sending messages.
```rust
if client.contacts().is_on_whatsapp(&phone_jid).await? {
println!("User is on WhatsApp!");
}
```
--------------------------------
### Project Structure Overview
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/INDEX.md
This is a visual representation of the whatsapp-rust project's directory structure, outlining the location of key modules and components.
```text
whatsapp-rust/
├── src/
│ ├── bot.rs # BotBuilder, Bot, MessageContext
│ ├── client.rs # Client core and lifecycle
│ ├── client/
│ │ ├── messaging.rs # send_message, reactions, edits
│ │ ├── sessions.rs # Signal protocol session management
│ │ ├── device_registry.rs # Device list caching
│ │ └── ...
│ ├── features/
│ │ ├── groups.rs # Groups API
│ │ ├── contacts.rs # Contacts API
│ │ ├── presence.rs # Presence API
│ │ ├── profile.rs # Profile API
│ │ ├── blocking.rs # Blocking API
│ │ └── ...
│ ├── upload.rs # Media upload
│ ├── download.rs # Media download
│ ├── store/ # Backend trait and persistence
│ ├── types/
│ │ └── events.rs # Event types
│ └── ...
├── wacore/ # Platform-agnostic core
│ ├── binary/ # WABinary protocol
│ ├── libsignal/ # Signal Protocol
│ ├── appstate/ # App state sync
│ └── ...
├── waproto/ # Protocol Buffers definitions
├── storages/sqlite-storage/ # SQLite Backend
├── transports/tokio-transport/ # WebSocket transport
├── http_clients/ureq-client/ # HTTP client
└── tests/
├── e2e/ # End-to-end tests
└── bench-integration/ # Benchmarks
```
--------------------------------
### Create and Parse JIDs in Rust
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/INDEX.md
Demonstrates how to create JIDs for users, groups, and newsletters, and how to parse them from strings. Ensure JID strings are correctly formatted.
```rust
let user_jid = Jid::user("1234567890"); // @s.whatsapp.net
let group_jid = Jid::group("120363xyz"); // @g.us
let newsletter_jid = Jid::newsletter("123456@newsletter");
// Parse from string
let jid: Jid = "1234567890@s.whatsapp.net".parse()?;
```
--------------------------------
### BotBuilder::with_runtime
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/bot-api.md
Overrides the default async runtime implementation.
```APIDOC
## BotBuilder::with_runtime
### Description
Overrides the async runtime implementation. Replaces the Tokio default.
### Parameters
#### Path Parameters
- **runtime** (impl Runtime + 'static) - Required - Async runtime for spawning tasks
### Returns
`BotBuilder` - Builder with Runtime marked as Provided.
```
--------------------------------
### Handling PresenceChange Events
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/events-lifecycle.md
Example of an event handler for PresenceChange events. It filters for the specific event kind and prints the user's JID and new status.
```rust
.on_event_for(&[EventKind::PresenceChange], |event, _| async move {
if let Event::PresenceChange(pce) = &*event {
println!("{} is now {:?}", pce.jid, pce.status);
}
})
```
--------------------------------
### Construct and Use MessageKey in Rust
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/INDEX.md
Illustrates how to create a `MessageKey` for identifying messages, used for actions like sending reactions or quoting. Ensure `remote_jid`, `id`, and `participant` (for groups) are correctly set.
```rust
let key = wa::MessageKey {
remote_jid: Some(chat.to_string()),
from_me: Some(false),
id: Some("message_id_123".to_string()),
participant: Some(sender.to_string()), // groups only
};
// React
client.send_reaction(&chat, key, "👍").await?;
// Quote
let quoted = wa::Message::text_with_context(
"Reply",
wa::ContextInfo {
stanza_id: Some(key.id.clone()),
..Default::default()
}
);
```
--------------------------------
### Get Client's Status Text
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/contacts-presence-api.md
Retrieves the client's current status text. Returns an Option which may be None if no status is set.
```rust
client.profile().get_status().await?;
```
--------------------------------
### Registering Custom Event Handlers
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/events-lifecycle.md
Demonstrates how to integrate custom event handlers by implementing the `EventHandler` trait and registering them with the bot.
```APIDOC
## Integrating with Custom Event Handlers
### Description
This section shows how to create and register custom event handlers to process specific events from the WhatsApp client.
### Handler Implementation
Implement the `EventHandler` trait, defining `handle_event` for processing events and `interest` to specify which events to subscribe to.
```rust
use whatsapp_rust::types::events::{Event, EventHandler, EventInterest, EventKind};
use std::sync::Arc;
struct MyHandler;
impl EventHandler for MyHandler {
fn handle_event(&self, event: Arc) {
match &*event {
Event::Message(msg, info) => {
println!("Got message: {:?}", info.id);
}
_ => {}
}
}
fn interest(&self) -> EventInterest {
EventInterest::of(&[EventKind::Message])
}
}
```
### Registration
Register the custom handler using `register_raw_handler` during bot configuration.
```rust
// Register
bot = Bot::builder()
// ... other config ...
.register_raw_handler(Arc::new(MyHandler))
.build()
.await?;
```
```
--------------------------------
### Thread-Safe Client Sharing
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/configuration-errors.md
Demonstrates how to safely clone and use the `Client` across multiple Tokio tasks. The `Client` is `Send + Sync`, allowing it to be shared.
```rust
let bot = bot.spawn();
let client = bot.client();
// Safe to clone and use across tasks:
let client2 = client.clone();
tokio::spawn(async move {
let _ = client2.send_text(&jid, "hello").await;
});
// Main task can also send:
let _ = client.send_text(&jid, "hi").await;
```
--------------------------------
### Handshake Log Messages
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/agent_docs/protocol_architecture.md
Examples of log output during the Noise handshake process, including full handshakes, resumption attempts, and fallback scenarios. Useful for debugging connection issues.
```text
[socket] doFullHandshake: openChatSocket send hello
[socket] resumeNoiseHandshake started
[socket] resumeNoiseHandshake send hello
[socket] resumeNoiseHandshake rcv hello
[socket] resumeNoiseHandshake deriving secrets
[socket] resumeNoiseHandshake failed: serverStaticCiphertext not null —
doFallbackHandshake continuing handshake with given server hello
[socket] continueFullHandshakeCore client finish and deriving secrets
```
--------------------------------
### BotBuilder: with_backend Method
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/bot-api.md
Sets the storage backend implementation for the BotBuilder. This is a required field when default features are enabled.
```rust
pub fn with_backend(backend: impl Backend + 'static) -> BotBuilder
```
--------------------------------
### CreateGroupOptions Structure
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/groups-api.md
Defines the configuration options available when creating a new group. Includes subject, participants, and optional description or ephemeral settings.
```rust
pub struct CreateGroupOptions {
pub subject: String,
pub participants: Vec,
pub description: Option,
pub ephemeral_expiration: Option,
// ... other options
}
```
--------------------------------
### ProtocolNode Trait Definition
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/agent_docs/protocol_architecture.md
Defines the interface for mapping Rust structs to WhatsApp protocol nodes, including methods for getting the tag, converting to a Node, and attempting conversion from a Node.
```rust
pub trait ProtocolNode: Sized {
fn tag(&self) -> &'static str;
fn into_node(self) -> Node;
fn try_from_node(node: &Node) -> Result;
}
```
--------------------------------
### Handle PairingQrCode Event
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/events-lifecycle.md
Use this handler to display the QR code and its timeout for pairing.
```rust
.on_qr_code(|code, timeout| async move {
println!("Scan within {:?}: {}", timeout, code);
})
```
--------------------------------
### Register Message Handler
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/bot-api.md
Register a handler specifically for message events, providing a convenient `MessageContext` for easier message processing and replies. Example shows replying 'pong' to a 'ping' message.
```rust
.on_message(|ctx| async move {
if ctx.message.text_content() == Some("ping") {
let _ = ctx.reply("pong").await;
}
})
```
--------------------------------
### Customizing Cache Configuration with Builder
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/configuration-errors.md
Demonstrates how to override default cache settings using the `Bot::builder()` pattern. This allows for fine-tuning cache behavior for specific needs, such as increasing group cache capacity or altering TTLs.
```Rust
let bot = Bot::builder()
.with_cache_config(CacheConfig {
group_cache_capacity: 5000, // Cache up to 5000 groups
lid_pn_cache_ttl: Duration::from_secs(3600 * 48), // 48 hour TTL
msg_secret_policy: MsgSecretPolicy::Discard,
..Default::default()
})
.build()
.await?;
```
--------------------------------
### Get User Presence
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/contacts-presence-api.md
Retrieves a user's current presence information. It takes a user's JID as input and returns an Option containing Presence information or None if the user's presence is unavailable.
```rust
client.presence().get_user_presence(&user_jid).await?;
```
--------------------------------
### BotBuilder::with_backend
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/bot-api.md
Sets the storage backend implementation, which is required for persisting data.
```APIDOC
## BotBuilder::with_backend
### Description
Sets the storage backend implementation. This is the only required field when default features are enabled.
### Parameters
#### Path Parameters
- **backend** (impl Backend + 'static) - Required - Storage backend for persisting device state, sessions, and app state
### Returns
`BotBuilder` - Builder with Backend marked as Provided.
```
--------------------------------
### download_media_with_progress
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/media-upload-download.md
Downloads media from a URL with progress tracking. It accepts the media URL, media key, encryption type, and a callback function to report download progress.
```APIDOC
## download_media_with_progress
### Description
Download with progress tracking.
### Method
`async fn`
### Parameters
#### Path Parameters
- **url** (`&str`) - Required - Media URL
- **media_key** (`&[u8]`) - Required - Media encryption key
- **enc_type** (`&str`) - Required - Encryption type
- **progress_callback** (`F: Fn(DownloadProgress)`) - Required - Called as download progresses
### Response
#### Success Response
- **Result, MediaError>**
```
--------------------------------
### Upload Sticker
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/media-upload-download.md
Uploads a sticker file and sends it as a WhatsApp message. Ensure the sticker file is in webp format and specify the correct MIME type.
```rust
let sticker_bytes = std::fs::read("sticker.webp").await?;
let uploaded = client.upload_media(
&sticker_bytes,
UploadOptions {
file_size: sticker_bytes.len() as u64,
media_type: MediaType::Sticker,
..Default::default()
}
).await?;
let sticker_msg = wa::Message {
sticker_message: Some(Box::new(wa::message::StickerMessage {
url: Some(uploaded.url),
file_length: Some(sticker_bytes.len() as u64),
media_key: Some(uploaded.media_key.into()),
mime_type: Some("image/webp".to_string()),
sha256: Some(uploaded.file_sha256.into()),
file_sha256: Some(uploaded.file_sha256.into()),
..Default::default()
})),
..Default::default()
};
client.send_message(&chat, sticker_msg).await?;
```
--------------------------------
### Create Audio Message
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/media-upload-download.md
Use this method to create an audio message. Requires URL, media key, file SHA256, file length, MIME type, audio length, and a boolean indicating if it's a voice message.
```rust
let audio_msg = wa::Message::audio(
url,
media_key,
file_sha256,
file_length,
Some(mime_type),
audio_length_secs,
false, // is_voicemessage
);
```
--------------------------------
### BotBuilder: with_backend_arc Method
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/bot-api.md
Provides an alternative way to set the storage backend using an already shared Arc.
```rust
pub fn with_backend_arc(backend: Arc) -> BotBuilder
```
--------------------------------
### SQLite Performance Tuning PRAGMAs
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/storage-backend.md
Configure SQLite cache size and memory-mapped I/O for high-throughput bots. Ensure writes are enabled by setting query_only to false.
```sql
PRAGMA cache_size = 10000; -- 40 MB page cache
PRAGMA mmap_size = 268435456; -- 256 MB memory-mapped I/O
PRAGMA query_only = false; -- Enable writes
```
--------------------------------
### Initializing Test Environment
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/agent_docs/e2e_testing.md
Initialize logging for tests using `env_logger` to enable debug output. Ensure it's configured for test environments using `is_test(true)`.
```rust
let _ = env_logger::builder().is_test(true).try_init();
```
--------------------------------
### BotBuilder::with_http_client
Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/bot-api.md
Overrides the default HTTP client used for media operations.
```APIDOC
## BotBuilder::with_http_client
### Description
Overrides the HTTP client used for media uploads/downloads and version fetching. Replaces the ureq-client default.
### Parameters
#### Path Parameters
- **client** (impl HttpClient + 'static) - Required - HTTP client for media operations
### Returns
`BotBuilder` - Builder with HttpClient marked as Provided.
```