Working with Media
Send images, video, audio, documents and stickers, and fetch inbound media bytes on demand from the WUTS gateway.
WUTS handles rich media in both directions. You send media through the
dedicated POST /send/* endpoints, and you receive media as descriptors in
webhook payloads — fetching the actual bytes on demand through the gateway, which
re-downloads and retransmits when the original WhatsApp CDN copy has expired.
All requests use the base URL https://api.wuts.com.br and the
Authorization: Bearer <token> header. See Authentication and
Conventions for the shared request/response model.
Sending media
Each media type has its own endpoint:
| Type | Endpoint | Source fields |
|---|---|---|
| Image | POST /send/image | image or image_url |
| Video | POST /send/video | video or video_url |
| Audio | POST /send/audio | audio or audio_url |
| Document | POST /send/document | document or document_url |
| Sticker | POST /send/sticker | sticker or sticker_url |
Source: URL or base64
Every media endpoint accepts the content either as a public URL or as base64 — provide exactly one, never both. When you pass a URL, the gateway downloads it before sending (default download timeout is 30 seconds; videos allow up to 60 seconds).
Base64 may be supplied with or without a data-URI prefix:
- With prefix (recommended):
data:image/png;base64,iVBORw0KGgo...— the MIME type is taken from the prefix. - Without prefix: raw base64; the gateway detects the format automatically.
For large files, prefer a URL over base64. Base64 inflates the request body by roughly a third and is slower to transfer.
Captions, file names and MIME types
caption— optional text shown below the media on image, video, audio and document messages. Maximum 1024 characters, with native WhatsApp formatting (*bold*,_italic_,~strikethrough~,```monospace```). Stickers do not take a caption.file_name— for documents, the name shown in WhatsApp. It is required when sending viadocument_url.mime_type— for documents, an optional override; when omitted the gateway detects it (e.g. from adata:application/pdf;base64,...data URI).thumbnail/thumbnail_base64— optional JPEG preview for documents and videos.
Size and format limits
Limits come straight from the gateway code:
| Type | Max size | Accepted formats |
|---|---|---|
| Image | 16 MB | JPEG, PNG, GIF, WebP |
| Audio | 16 MB | MP3, OGG, WAV, M4A, AAC, FLAC (max 5 min) |
| Video | 100 MB | MP4 (native); AVI, MOV, MKV, WebM require conversion |
| Document | 64 MB | Any file type |
| Sticker | 500 KB | WebP only (static or animated) |
Audio is automatically transcoded to WhatsApp's native Opus/OGG format and a
64-sample waveform is generated. Set ptt: true to send it as a voice message.
Stickers must already be WebP — convert PNG/JPEG to WebP (512×512 recommended)
before sending.
Optional behaviour
These fields are shared across the media endpoints:
delay— seconds to wait before sending (0–3600).viewOnce— image/video/audio that disappears after a single view.mentioned/mentionsEveryOne— mention specific JIDs or everyone in a group, applied to the caption. See Group Management.quoted— reply to an existing message. In groups, theparticipantJID is required insidequoted.key.
Example: send an image by URL
curl -X POST "https://api.wuts.com.br/send/image" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"number": "5511999999999",
"image_url": "https://example.com/product.jpg",
"caption": "Check out our new product! *Limited offer*"
}'A successful send returns 200 OK with the message id and rich metadata:
{
"success": true,
"message_id": "3EB0F8A1B2C3D4E5F6",
"timestamp": "2026-06-15T18:30:15Z",
"status": "sent",
"chat_jid": "5511999999999@s.whatsapp.net",
"metadata": {
"image_size_bytes": 245760,
"image_format": "image/jpeg",
"upload_time_ms": 567
}
}Example: send a document by base64
curl -X POST "https://api.wuts.com.br/send/document" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"number": "5511999999999",
"document": "data:application/pdf;base64,JVBERi0xLjcKJ...",
"file_name": "contract.pdf",
"caption": "Signed contract attached"
}'{
"success": true,
"message_id": "3EB0F8A1B2C3D4E5F6",
"status": "sent",
"chat_jid": "5511999999999@s.whatsapp.net",
"metadata": {
"file_name": "contract.pdf",
"mime_type": "application/pdf",
"document_size_bytes": 302481
}
}Large videos may return 202 Accepted with a status: "processing" and a
job_id instead of 200 OK. The video is encoded in the background and sent when
ready — use webhooks to learn when it actually goes out.
Every successful media send also fires a message.sent webhook.
Receiving media
When a contact sends you media, WUTS delivers a webhook
whose message payload carries a media descriptor rather than the raw bytes. Image,
video, audio and sticker messages populate a media object; documents populate a
document object.
{
"message_id": "3EB0F8A1B2C3D4E5F6",
"from": "5511999999999@s.whatsapp.net",
"message_type": "image",
"media": {
"mime_type": "image/jpeg",
"file_length": 245760,
"width": 1280,
"height": 720,
"caption": "Look at this",
"media_path": "/messages/3EB0F8A1B2C3D4E5F6/media",
"jpeg_thumbnail": "/9j/4AAQSkZJRgABAQ..."
}
}The media_path (also present on documents) is a stable, authenticated
gateway path. Prefer it over the ephemeral WhatsApp CDN url, which expires
quickly. The jpeg_thumbnail lets you show a preview immediately without
downloading the full file.
Fetching the bytes
To get the actual file, call GET /messages/:id/media with the message id from the
webhook. The gateway serves its decrypted, warm-cached copy when available, and
otherwise re-downloads the media on demand using a connected device of your tenant:
curl -X GET "https://api.wuts.com.br/messages/3EB0F8A1B2C3D4E5F6/media" \
-H "Authorization: Bearer <token>" \
-o downloaded-media.jpgOn success the response body is the raw file bytes with the correct
Content-Type (e.g. image/jpeg) and a private 24-hour cache header — not JSON.
Expired CDN copies and retransmission
WhatsApp removes media from its CDN after a while. When the original copy is gone,
the gateway cannot simply re-download it — instead it asks the sender's device to
re-upload (retransmit) the media. In that case GET /messages/:id/media responds
with 202 Accepted and a status field:
{ "success": false, "status": "retry_requested" }The retransmission is requested over the live WhatsApp connection and arrives
asynchronously. Wait a few seconds, then call GET /messages/:id/media again to
get the bytes. Repeated calls while a retransmission is already in flight return
status: "retry_pending" (the request is throttled to once every 90 seconds per
message).
Fetch on demand and persist the bytes on your side if you need them long term. Retransmission depends on the sending device being online, and is not guaranteed indefinitely after the CDN copy expires.
Status codes for the fetch endpoint
| Status | Meaning |
|---|---|
200 | Raw media bytes in the body (Content-Type set per the file). |
202 | Retransmission requested or pending — retry shortly. |
404 | No media descriptor for that message id. |
502 | Download failed (transient CDN or decode error) — safe to retry. |
503 | No connected device available to download the media. |
A 404 or 502 here is retryable; see Errors and
Rate Limits for the broader retry guidance.