Inbound media
The easy path — it’s on the webhook
Section titled “The easy path — it’s on the webhook”Every inbound media message arrives on your message.received webhook
with a media_url already signed and ready to download (valid ~1 hour), plus
its mime type and original filename:
{ "event": "message.received", "data": { "conversation_id": "c9e6f0f7-...", "phone": "919876543210", "message": { "id": "wamid...", "type": "image", "text": "here's my materials list", "media_url": "https://blr1.digitaloceanspaces.com/…?X-Amz-Signature=…", "media_mime_type": "image/jpeg", "media_filename": "list.jpg", "timestamp": "2026-07-16T09:10:00Z" } }}GET the media_url as-is — no auth header, no extra call. type is
image · document · audio · video · sticker for media messages (text
messages carry no media_url).
On demand — the media endpoint
Section titled “On demand — the media endpoint”Fetch a fresh signed URL any time, authenticated with your X-API-Key. Pass
either a message_id (from the list API or the webhook) or the stored
path:
curl "https://api.whatbot.in/public/v1/media?message_id=8f1c..." \ -H "X-API-Key: wa_live_xxx"curl "https://api.whatbot.in/public/v1/media?path=whatsapp-media/inbound/<org>/<file>.jpg" \ -H "X-API-Key: wa_live_xxx"{ "media_url": "https://blr1.digitaloceanspaces.com/…?X-Amz-Signature=…", "media_mime_type": "image/jpeg", "media_filename": "list.jpg"}Then GET media_url to download the bytes. A path is only accepted for your
own workspace’s media; anything else returns 403. Unknown message → 404.
Listing messages already signs media
Section titled “Listing messages already signs media”GET /conversations/{id}/messages also returns media with media_url already
signed — so a message you read back is immediately downloadable, no separate
call needed:
curl https://api.whatbot.in/public/v1/conversations/{id}/messages \ -H "X-API-Key: wa_live_xxx"Each media row’s media_url is a signed link (valid ~1 hour), alongside
media_mime_type and media_filename.