Skip to main content

download

Download and decrypt media from a message.
Only use download when you need the plaintext bytes (processing, transcoding, re-upload). To forward existing media unchanged, reuse the original message’s CDN fields directly — no download required. See media forwarding via CDN reuse.
&dyn Downloadable
required
Any message type that implements the Downloadable trait. Includes:
  • ImageMessage
  • VideoMessage
  • AudioMessage
  • DocumentMessage
  • StickerMessage
  • ExternalBlobReference (app state)
  • HistorySyncNotification
Vec<u8>
Decrypted media bytes. For encrypted media (E2EE), automatically decrypts using AES-256-CBC and verifies HMAC-SHA256. For plaintext media (newsletters/channels), validates SHA-256 hash.

Example: download image

Example: download with error handling

Automatic retry and URL re-derivation

All download methods handle three categories of CDN errors automatically:
  • Auth errors (401/403): The client invalidates the cached media connection, fetches fresh credentials, and retries the download once.
  • Media not found (404/410): When a media URL has expired or the file has been relocated, the CDN returns 404 or 410. The client treats this the same as an auth error — it invalidates the cached connection, re-derives download URLs with fresh credentials and hosts, and retries once. This matches WhatsApp Web’s MediaNotFoundError handling.
  • Other errors (e.g., 500): The client tries the next available CDN host without refreshing credentials. Hosts are tried in priority order (primary first, then fallback).
For streaming downloads, the writer is seeked back to position 0 before retrying so partial writes are overwritten.

download_to_writer

Download media to a writer using streaming when available, with automatic buffered fallback. This is the method to use for downloading straight to a file — pass a File or BufWriter<File>. When the HTTP client supports streaming (supports_streaming() returns true), the entire HTTP download, decryption, and file write happen in a single blocking thread with ~40KB memory usage regardless of file size. When streaming is not available, the method automatically falls back to a buffered download — fetching the full response into memory, then decrypting and writing to the writer. This ensures download_to_writer works with any HttpClient implementation.
&dyn Downloadable
required
Message containing downloadable media
W: Write + Seek + Send + 'static
required
Writer for streaming output. Must be Send + ‘static for use in blocking task.
W
Returns the writer after successful download, seeked back to position 0.

Example: streaming download

When using an HTTP client that supports streaming (like the default UreqHttpClient), memory usage is constant ~40KB (8KB read buffer + decryption state). HTTP clients that don’t support streaming fall back to buffered downloads, which load the full file into memory before writing.

download_from_params

Download and decrypt media from raw CDN parameters without the original message. The parameters are bundled into a DownloadParams struct.
&DownloadParams
required
The CDN/crypto fields needed to fetch and decrypt the media. Build one with DownloadParams::encrypted.
Vec<u8>
Decrypted media bytes

Example: download from stored metadata

DownloadParams implements Downloadable, so you can also pass it straight to download: client.download(&params).await?.

download_from_params_to_writer

Streaming variant of download_from_params that writes to a writer.
&DownloadParams
required
The CDN/crypto fields needed to fetch and decrypt the media. See DownloadParams.
W
required
Writer for streaming output
W
Returns the writer after successful download

DownloadParams

A Downloadable built from raw CDN fields, for re-downloading media without the original message.

DownloadParams::encrypted

Convenience constructor for encrypted (E2EE) media — fills media_key and file_enc_sha256 as Some(...).
DownloadParams implements Downloadable, so it works with download, download_to_writer, download_from_params, and download_from_params_to_writer.

fetch_sticker_pack

Fetch first-party sticker pack metadata (and the per-sticker download handles) from the WhatsApp CDN.
&str
required
The first-party sticker pack ID (typically extracted from a received sticker_pack_message).
&str
required
BCP-47 locale tag for localized name / publisher strings. Pass "en" to match whatsmeow’s default.
StickerPack
Pack metadata plus a Vec<StickerPackItem> of individual stickers. Each StickerPackItem implements Downloadable, so you can pass it straight to client.download(...).
Under the hood the client GETs https://static.whatsapp.net/sticker?lottie=1&cat=sticker_pack_data&id={pack_id}&lg={locale}, parses the JSON envelope, and constructs the StickerPack. The endpoint is unauthenticated — the call works whether or not you are paired.

StickerPack

StickerPackItem

The CDN response is a JSON envelope, not a protobuf message — StickerPack / StickerPackItem live in wacore::sticker_pack and are independent of waproto::whatsapp::StickerPackMessage (which represents the inline pack-bubble in a chat). The struct mirrors whatsmeow’s FirstPartyStickerPack.

Downloadable Trait

The Downloadable trait provides a generic interface for downloading media from any message type.
fn() -> Option<&str>
WhatsApp CDN path for the media file
fn() -> Option<&[u8]>
32-byte encryption key. Present for E2EE media, None for plaintext (newsletter/channel) media.
fn() -> Option<&[u8]>
SHA-256 hash of the encrypted file. Used for encrypted media validation.
fn() -> Option<&[u8]>
SHA-256 hash of the decrypted file. Used for plaintext media validation.
fn() -> Option<u64>
Original file size in bytes
fn() -> MediaType
Media type for HKDF key derivation (Image, Video, Audio, Document, etc.)
fn() -> Option<&str>
default:"None"
Static CDN URL for direct download. Present on newsletter/channel media, bypasses host construction.
fn() -> bool
default:"media_key().is_some()"
Returns true if media is encrypted (has media_key), false for plaintext media

Built-in Implementations

The Downloadable trait is automatically implemented for:
  • wa::message::ImageMessage
  • wa::message::VideoMessage
  • wa::message::AudioMessage
  • wa::message::DocumentMessage
  • wa::message::StickerMessage
  • wa::ExternalBlobReference (app state)
  • wa::message::HistorySyncNotification

MediaType

Media type enum for encryption/decryption.
Each media type has specific HKDF info strings used for key derivation:
  • Image / Sticker"WhatsApp Image Keys"
  • Video"WhatsApp Video Keys"
  • Audio"WhatsApp Audio Keys"
  • Document"WhatsApp Document Keys"
  • History"WhatsApp History Keys"
  • AppState"WhatsApp App State Keys"
  • StickerPack"WhatsApp Sticker Pack Keys"
  • StickerPackThumbnail"WhatsApp Sticker Pack Thumbnail Keys"
  • LinkThumbnail"WhatsApp Link Thumbnail Keys"

MediaType methods

Upload paths

ProductCatalogImage is unencryptedis_encrypted() returns false. This matches WhatsApp Web’s behavior where CreateMediaKeys.js skips encryption for product catalog images. Its upload path is /product/image (not under the /mms/ prefix like other media types).

Media Decryption

WhatsApp uses different handling for encrypted (E2EE) and plaintext media:

Encrypted Media (E2EE)

  1. Download encrypted bytes from CDN
  2. Verify HMAC-SHA256 (last 10 bytes)
  3. Decrypt using AES-256-CBC with keys derived from media_key via HKDF
  4. Return decrypted plaintext
The media_key is expanded using HKDF-SHA256 to derive:
  • 16-byte IV
  • 32-byte cipher key
  • 32-byte MAC key

Plaintext media (newsletter/channel)

  1. Download plaintext bytes from CDN (often via static_url)
  2. Verify SHA-256 hash matches file_sha256
  3. Return plaintext (no decryption needed)
Newsletter and channel media is not encrypted. The library automatically detects this when media_key is absent and switches to plaintext validation.

Example: detect media type


DownloadUtils

Low-level static methods for media decryption and validation. These are re-exported from wacore::download and useful when you need fine-grained control over the download pipeline.

Key methods