{"id":517,"date":"2026-10-28T16:05:47","date_gmt":"2026-10-28T16:05:47","guid":{"rendered":"https:\/\/vectalk.com.br\/blog\/download-media-whatsapp-webhook\/"},"modified":"2026-10-28T16:05:59","modified_gmt":"2026-10-28T16:05:59","slug":"download-media-whatsapp-webhook","status":"publish","type":"post","link":"https:\/\/vectalk.com.br\/blog\/en\/download-media-whatsapp-webhook\/","title":{"rendered":"How to receive and download media customers send through the WhatsApp API"},"content":{"rendered":"\n<p><em>Updated on October 28, 2026<\/em><\/p>\n\n\n\n<p>When a customer sends a photo, PDF, audio or video, the WhatsApp Business API webhook does not include the file: it includes a <strong>media ID<\/strong>. To download it, call <code>GET \/{media-id}<\/code> to get a temporary URL, which <strong>expires after 5 minutes<\/strong>, then <code>GET<\/code> that URL with your access token in the <code>Authorization<\/code> header. Since a media ID received via webhook is only valid for <strong>7 days<\/strong>, download right away and keep the file in your own storage.<\/p>\n\n\n\n<p>This guide covers the full flow, the fields for each media type, size limits, how to check file integrity, and examples in cURL, Node.js and Python, including uploading to Amazon S3.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The flow in 4 steps<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Webhook<\/strong>: a message arrives with <code>type<\/code> set to <code>image<\/code>, <code>document<\/code>, <code>audio<\/code>, <code>video<\/code> or <code>sticker<\/code>, carrying the media <code>id<\/code>.<\/li>\n\n\n<li><strong>Temporary URL<\/strong>: <code>GET https:\/\/graph.facebook.com\/v26.0\/{media-id}<\/code> returns <code>url<\/code>, <code>mime_type<\/code>, <code>sha256<\/code> and <code>file_size<\/code>.<\/li>\n\n\n<li><strong>Download<\/strong>: <code>GET<\/code> the <code>url<\/code> with <code>Authorization: Bearer &lt;token&gt;<\/code>. Without the token, the request fails.<\/li>\n\n\n<li><strong>Storage<\/strong>: save it to your storage (S3, GCS, disk) and store the file path in your database, never Meta&#8217;s URL.<\/li>\n\n<\/ol>\n\n\n\n<p>The time limits come from <a href=\"https:\/\/developers.facebook.com\/documentation\/business-messaging\/whatsapp\/business-phone-numbers\/media\" target=\"_blank\" rel=\"noreferrer noopener\">Meta&#8217;s media documentation<\/a>: media URLs expire after 5 minutes (after that, query the media ID again for a new one), media IDs from webhooks expire after 7 days, and media IDs from uploads expire after 30 days.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What arrives in the webhook<\/h2>\n\n\n\n<p>This is the shape of an incoming image, per the <a href=\"https:\/\/developers.facebook.com\/documentation\/business-messaging\/whatsapp\/webhooks\/reference\/messages\/image\" target=\"_blank\" rel=\"noreferrer noopener\">image message webhook reference<\/a> (sample values):<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"language-json\">{\n  \"object\": \"whatsapp_business_account\",\n  \"entry\": [{\n    \"id\": \"WABA_ID\",\n    \"changes\": [{\n      \"field\": \"messages\",\n      \"value\": {\n        \"messaging_product\": \"whatsapp\",\n        \"metadata\": {\n          \"display_phone_number\": \"15550783881\",\n          \"phone_number_id\": \"PHONE_NUMBER_ID\"\n        },\n        \"contacts\": [{ \"profile\": { \"name\": \"Maria\" }, \"wa_id\": \"16505551234\" }],\n        \"messages\": [{\n          \"from\": \"16505551234\",\n          \"id\": \"wamid.HBgLMTY1...\",\n          \"timestamp\": \"1761650000\",\n          \"type\": \"image\",\n          \"image\": {\n            \"caption\": \"Receipt\",\n            \"mime_type\": \"image\/jpeg\",\n            \"sha256\": \"SfInY0gGKTsJlUWbwxC1k+FAD0FZHvzwfpvO0zX0GUI=\",\n            \"id\": \"1003383421387256\",\n            \"url\": \"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=...\"\n          }\n        }]\n      }\n    }]\n  }]\n}<\/code><\/pre>\n\n\n\n<p>The object name changes with the type (<code>image<\/code>, <code>document<\/code>, <code>audio<\/code>, <code>video<\/code>, <code>sticker<\/code>), but the structure is similar. Documents also include <code>filename<\/code>, handy for saving with the original name.<\/p>\n\n\n\n<p>Note the <code>url<\/code> field. Meta started rolling it out gradually in the webhook itself on November 12, 2025, which lets you skip step 2 and download directly with your token. Because the rollout is gradual, your code should work with and without it: use <code>url<\/code> when present and, if it is missing or the download fails, query the media ID.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Field<\/th><th>What it is for<\/th><\/tr><\/thead><tbody><tr><td><code>id<\/code><\/td><td>Media ID; use it to generate the download URL<\/td><\/tr><tr><td><code>mime_type<\/code><\/td><td>File type (<code>image\/jpeg<\/code>, <code>application\/pdf<\/code>, <code>audio\/ogg<\/code>&#8230;)<\/td><\/tr><tr><td><code>sha256<\/code><\/td><td>File hash, to check integrity<\/td><\/tr><tr><td><code>caption<\/code><\/td><td>Caption sent by the customer, if any<\/td><\/tr><tr><td><code>filename<\/code><\/td><td>Original name (documents)<\/td><\/tr><tr><td><code>url<\/code><\/td><td>Direct download URL, in gradual rollout<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Types and size limits<\/h2>\n\n\n\n<p>This table summarizes supported types and maximum sizes from Meta&#8217;s media page. Use it to size your storage and download timeouts:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Type<\/th><th>Formats<\/th><th>Max size<\/th><\/tr><\/thead><tbody><tr><td>Audio<\/td><td>AAC, AMR, MP3, M4A, OGG (OPUS codec only, mono)<\/td><td>16 MB<\/td><\/tr><tr><td>Document<\/td><td>TXT, XLS, XLSX, DOC, DOCX, PPT, PPTX, PDF<\/td><td>100 MB<\/td><\/tr><tr><td>Image<\/td><td>JPEG, PNG (8-bit, RGB or RGBA)<\/td><td>5 MB<\/td><\/tr><tr><td>Sticker<\/td><td>WebP<\/td><td>500 KB animated, 100 KB static<\/td><\/tr><tr><td>Video<\/td><td>3GP, MP4 (H.264 and AAC)<\/td><td>16 MB<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Voice notes arrive as <code>audio<\/code> messages. If you pass audio to a transcription service, check the <code>mime_type<\/code> you received and whether the service accepts that format; if not, convert it first.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">cURL example<\/h2>\n\n\n\n<p>Step 2, get the URL:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"language-bash\">curl \"https:\/\/graph.facebook.com\/v26.0\/1003383421387256\" \\\n  -H \"Authorization: Bearer $TOKEN\"<\/code><\/pre>\n\n\n\n<p>Response:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"language-json\">{\n  \"messaging_product\": \"whatsapp\",\n  \"url\": \"https:\/\/lookaside.fbsbx.com\/whatsapp_business\/attachments\/?mid=...\",\n  \"mime_type\": \"image\/jpeg\",\n  \"sha256\": \"SfInY0gGKTsJlUWbwxC1k+FAD0FZHvzwfpvO0zX0GUI=\",\n  \"file_size\": 303833,\n  \"id\": \"1003383421387256\"\n}<\/code><\/pre>\n\n\n\n<p>Step 3, download:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"language-bash\">curl -L \"RETURNED_URL\" \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -o receipt.jpg<\/code><\/pre>\n\n\n\n<p>Optionally, pass <code>phone_number_id<\/code> as a query parameter in step 2: Meta then processes the request only if the media belongs to that number, a useful safeguard when one application serves several numbers.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Node.js example<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"language-js\">import crypto from 'node:crypto';\nimport { S3Client, PutObjectCommand } from '@aws-sdk\/client-s3';\n\nconst GRAPH = 'https:\/\/graph.facebook.com\/v26.0';\nconst TOKEN = process.env.WHATSAPP_TOKEN;\nconst s3 = new S3Client({ region: process.env.AWS_REGION });\n\nasync function getMediaUrl(mediaId) {\n  const res = await fetch(`${GRAPH}\/${mediaId}`, {\n    headers: { Authorization: `Bearer ${TOKEN}` },\n  });\n  if (!res.ok) throw new Error(`media ${mediaId}: HTTP ${res.status}`);\n  return res.json(); \/\/ { url, mime_type, sha256, file_size, id }\n}\n\nasync function download(url) {\n  const res = await fetch(url, { headers: { Authorization: `Bearer ${TOKEN}` } });\n  if (!res.ok) throw Object.assign(new Error('download failed'), { status: res.status });\n  return Buffer.from(await res.arrayBuffer());\n}\n\nexport async function saveMedia(media, key) {\n  let info = { url: media.url, sha256: media.sha256, mime_type: media.mime_type };\n  let file;\n  try {\n    if (!info.url) throw new Error('no url in webhook');\n    file = await download(info.url);\n  } catch {\n    info = await getMediaUrl(media.id); \/\/ fresh URL\n    file = await download(info.url);\n  }\n\n  const hash = crypto.createHash('sha256').update(file).digest('base64');\n  if (info.sha256 &amp;&amp; hash !== info.sha256) throw new Error('hash mismatch');\n\n  await s3.send(new PutObjectCommand({\n    Bucket: process.env.BUCKET,\n    Key: key,\n    Body: file,\n    ContentType: info.mime_type,\n  }));\n  return key;\n}<\/code><\/pre>\n\n\n\n<p>In Meta&#8217;s examples the <code>sha256<\/code> value is base64-encoded, which is why the comparison uses <code>digest('base64')<\/code>. If you see a different format in your traffic, log both values before turning the check on.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Python example<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"language-python\">import base64\nimport hashlib\nimport os\n\nimport boto3\nimport httpx\n\nGRAPH = \"https:\/\/graph.facebook.com\/v26.0\"\nTOKEN = os.environ[\"WHATSAPP_TOKEN\"]\nHEADERS = {\"Authorization\": f\"Bearer {TOKEN}\"}\ns3 = boto3.client(\"s3\")\n\n\ndef get_media_url(client: httpx.Client, media_id: str) -&gt; dict:\n    r = client.get(f\"{GRAPH}\/{media_id}\", headers=HEADERS)\n    r.raise_for_status()\n    return r.json()\n\n\ndef save_media(media: dict, key: str) -&gt; str:\n    with httpx.Client(timeout=60, follow_redirects=True) as client:\n        info = get_media_url(client, media[\"id\"])\n        r = client.get(info[\"url\"], headers=HEADERS)\n        if r.status_code == 404:  # expired URL: get a new one and retry\n            info = get_media_url(client, media[\"id\"])\n            r = client.get(info[\"url\"], headers=HEADERS)\n        r.raise_for_status()\n\n    computed = base64.b64encode(hashlib.sha256(r.content).digest()).decode()\n    if info.get(\"sha256\") and computed != info[\"sha256\"]:\n        raise ValueError(\"hash mismatch\")\n\n    s3.put_object(\n        Bucket=os.environ[\"BUCKET\"],\n        Key=key,\n        Body=r.content,\n        ContentType=info[\"mime_type\"],\n    )\n    return key<\/code><\/pre>\n\n\n\n<p>For documents up to 100 MB, holding everything in memory can get heavy. In that case, stream the download to a temporary file and use boto3&#8217;s <code>upload_fileobj<\/code>, or <code>Upload<\/code> from <code>@aws-sdk\/lib-storage<\/code> in Node, both of which upload in parts.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Where this fits in your architecture<\/h2>\n\n\n\n<p>Do not download media inside the webhook request. The endpoint should validate the signature, enqueue the event and return <code>200<\/code> quickly; a separate worker handles download and upload. That way a large video does not stall the webhook or trigger retries from Meta. For the validation part, see <a href=\"https:\/\/vectalk.com.br\/blog\/en\/whatsapp-webhook-signature-validation\/\">how to validate the webhook signature<\/a>.<\/p>\n\n\n\n<p>Some good practices:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Predictable storage keys<\/strong>, such as <code>whatsapp\/{phone_number_id}\/{wa_id}\/{wamid}.{ext}<\/code>, so you can find the file from the message.<\/li>\n\n\n<li><strong>Idempotency<\/strong>: before downloading, check whether that message was already processed; webhooks can be delivered more than once.<\/li>\n\n\n<li><strong>Private buckets<\/strong> and signed links for whoever needs to view the file, since receipts and documents contain personal data. If you serve Brazilian customers, the LGPD (Brazil&#8217;s data protection law, Law 13,709\/2018) requires care with security and retention of that data; define how long you keep each type. This is not legal advice.<\/li>\n\n\n<li><strong>Retry within the window<\/strong>: if the download fails, you have the media ID&#8217;s 7-day validity to try again.<\/li>\n\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Common errors<\/h2>\n\n\n\n<p><strong>404 on download.<\/strong> Meta&#8217;s media page says to request a new media URL and try again; if that does not fix it, renew your access token. In practice, the most common cause is using a URL saved more than 5 minutes earlier.<\/p>\n\n\n\n<p><strong>401 or 403 on download.<\/strong> The <code>GET<\/code> on the URL was sent without the <code>Authorization<\/code> header, or with a token that has no access to the account. Use a permanent system user token; see <a href=\"https:\/\/vectalk.com.br\/blog\/en\/whatsapp-api-permanent-access-token\/\">WhatsApp API permanent access token<\/a>.<\/p>\n\n\n\n<p><strong>Error 131052 in the webhook.<\/strong> <a href=\"https:\/\/developers.facebook.com\/documentation\/business-messaging\/whatsapp\/support\/error-codes\" target=\"_blank\" rel=\"noreferrer noopener\">Meta&#8217;s error table<\/a> defines it as &#8220;unable to download the media sent by the user&#8221;. Read the webhook&#8217;s <code>error_data.details<\/code> field and ask the customer to resend the file another way.<\/p>\n\n\n\n<p><strong>Expired media ID.<\/strong> After 7 days there is no way to retrieve the media through the API. That is why the download should happen right after the webhook.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">How to do this with Vectalk<\/h2>\n\n\n\n<p>With Vectalk, webhooks are Meta&#8217;s own, so the media ID arrives in the same field. For media, the <a href=\"https:\/\/docs.vectalk.com.br\/api-reference\/media\/get-url\">Vectalk API<\/a> offers <code>GET https:\/\/apis.vectalk.com.br\/api\/media\/{mediaId}<\/code>, which returns the temporary URL (valid for about 5 minutes), and <code>GET https:\/\/apis.vectalk.com.br\/api\/media\/{mediaId}\/download<\/code>, which returns the binary file with the right <code>Content-Type<\/code>, removing the second step. Both routes use the instance token. Sign up at <a href=\"https:\/\/apps.vectalk.com.br\/register\">apps.vectalk.com.br\/register<\/a>.<\/p>\n\n\n\n<p>For the opposite direction, sending files to customers, see <a href=\"https:\/\/vectalk.com.br\/blog\/en\/send-media-whatsapp-api\/\">how to send media with the WhatsApp API<\/a>. If your bot receives lots of files, complete examples are in the <a href=\"https:\/\/vectalk.com.br\/blog\/en\/whatsapp-bot-python-fastapi\/\">Python bot<\/a> and <a href=\"https:\/\/vectalk.com.br\/blog\/en\/whatsapp-bot-nodejs-express\/\">Node.js bot<\/a> tutorials. The big picture is in our <a href=\"https:\/\/vectalk.com.br\/blog\/en\/whatsapp-cloud-api-en\/\">WhatsApp Cloud API guide<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Frequently asked questions<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">How long is the media URL valid?<\/h3>\n\n\n\n<p>5 minutes. After that, query the media ID again for a new URL. A media ID received via webhook is valid for 7 days.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Can I store Meta&#8217;s URL in my database and open it later?<\/h3>\n\n\n\n<p>No. The URL expires in 5 minutes and requires the token to download. Store the file in your own storage and save its path in the database.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Do I need the token to download from the URL?<\/h3>\n\n\n\n<p>Yes. Meta&#8217;s documentation says the request fails if you omit the token. Send <code>Authorization: Bearer &lt;token&gt;<\/code> both when querying the media ID and when downloading.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">What is the maximum size of a received file?<\/h3>\n\n\n\n<p>Per Meta&#8217;s supported media table, images go up to 5 MB, audio and video up to 16 MB, and documents up to 100 MB. Stickers have smaller limits.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How do I know the downloaded file is intact?<\/h3>\n\n\n\n<p>Compute the SHA-256 of the content and compare it with the <code>sha256<\/code> from the webhook or the media ID response. In Meta&#8217;s examples, the value is base64-encoded.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p><strong>Official sources consulted on October 28, 2026:<\/strong> <a href=\"https:\/\/developers.facebook.com\/documentation\/business-messaging\/whatsapp\/business-phone-numbers\/media\" target=\"_blank\" rel=\"noreferrer noopener\">Media (Meta)<\/a>, <a href=\"https:\/\/developers.facebook.com\/documentation\/business-messaging\/whatsapp\/webhooks\/reference\/messages\/image\" target=\"_blank\" rel=\"noreferrer noopener\">Image message webhook (Meta)<\/a>, <a href=\"https:\/\/developers.facebook.com\/documentation\/business-messaging\/whatsapp\/webhooks\/reference\/messages\/document\" target=\"_blank\" rel=\"noreferrer noopener\">Document message webhook (Meta)<\/a>, <a href=\"https:\/\/developers.facebook.com\/documentation\/business-messaging\/whatsapp\/support\/error-codes\" target=\"_blank\" rel=\"noreferrer noopener\">Error codes (Meta)<\/a>, <a href=\"https:\/\/docs.vectalk.com.br\/api-reference\/media\/get-url\">Media in the Vectalk API<\/a>, <a href=\"https:\/\/docs.aws.amazon.com\/AWSJavaScriptSDK\/v3\/latest\/client\/s3\/command\/PutObjectCommand\/\" target=\"_blank\" rel=\"noreferrer noopener\">PutObjectCommand (AWS SDK for JavaScript v3)<\/a>, <a href=\"https:\/\/boto3.amazonaws.com\/v1\/documentation\/api\/latest\/reference\/services\/s3\/client\/upload_fileobj.html\" target=\"_blank\" rel=\"noreferrer noopener\">upload_fileobj (boto3)<\/a>, <a href=\"https:\/\/www.planalto.gov.br\/ccivil_03\/_ato2015-2018\/2018\/lei\/l13709.htm\" target=\"_blank\" rel=\"noreferrer noopener\">LGPD, Law 13,709\/2018 (Portuguese)<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>From webhook to your own storage: turn the media ID the WhatsApp Cloud API sends into a saved file, with temporary URLs, tokens, size limits and cURL, Node and Python code.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[1],"tags":[],"class_list":["post-517","post","type-post","status-publish","format-standard","hentry","category-blog"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.7 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Download Media from WhatsApp Webhooks: Guide with Code<\/title>\n<meta name=\"description\" content=\"Download media from WhatsApp webhooks: get the media ID, fetch the 5-minute URL, download with your token and save to S3. cURL, Node and Python examples.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/vectalk.com.br\/blog\/en\/download-media-whatsapp-webhook\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Download Media from WhatsApp Webhooks: Guide with Code\" \/>\n<meta property=\"og:description\" content=\"Download media from WhatsApp webhooks: get the media ID, fetch the 5-minute URL, download with your token and save to S3. cURL, Node and Python examples.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/vectalk.com.br\/blog\/en\/download-media-whatsapp-webhook\/\" \/>\n<meta property=\"og:site_name\" content=\"Blog Vectalk\" \/>\n<meta property=\"article:published_time\" content=\"2026-10-28T16:05:47+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-10-28T16:05:59+00:00\" \/>\n<meta name=\"author\" content=\"wanderleyfcunha\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"wanderleyfcunha\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"9 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/en\\\/download-media-whatsapp-webhook\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/en\\\/download-media-whatsapp-webhook\\\/\"},\"author\":{\"name\":\"wanderleyfcunha\",\"@id\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/#\\\/schema\\\/person\\\/ff36ecd9d8257856f227f8e5d639db2b\"},\"headline\":\"How to receive and download media customers send through the WhatsApp API\",\"datePublished\":\"2026-10-28T16:05:47+00:00\",\"dateModified\":\"2026-10-28T16:05:59+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/en\\\/download-media-whatsapp-webhook\\\/\"},\"wordCount\":1182,\"articleSection\":[\"Blog\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/en\\\/download-media-whatsapp-webhook\\\/\",\"url\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/en\\\/download-media-whatsapp-webhook\\\/\",\"name\":\"Download Media from WhatsApp Webhooks: Guide with Code\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/#website\"},\"datePublished\":\"2026-10-28T16:05:47+00:00\",\"dateModified\":\"2026-10-28T16:05:59+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/#\\\/schema\\\/person\\\/ff36ecd9d8257856f227f8e5d639db2b\"},\"description\":\"Download media from WhatsApp webhooks: get the media ID, fetch the 5-minute URL, download with your token and save to S3. cURL, Node and Python examples.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/en\\\/download-media-whatsapp-webhook\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/en\\\/download-media-whatsapp-webhook\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/en\\\/download-media-whatsapp-webhook\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"How to receive and download media customers send through the WhatsApp API\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/\",\"name\":\"Blog Vectalk\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/#\\\/schema\\\/person\\\/ff36ecd9d8257856f227f8e5d639db2b\",\"name\":\"wanderleyfcunha\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/21c37077f1731eb558973f27a7b647d55f72fde5200a843ac5f5345b247ea725?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/21c37077f1731eb558973f27a7b647d55f72fde5200a843ac5f5345b247ea725?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/21c37077f1731eb558973f27a7b647d55f72fde5200a843ac5f5345b247ea725?s=96&d=mm&r=g\",\"caption\":\"wanderleyfcunha\"},\"sameAs\":[\"https:\\\/\\\/vectalk.com.br\\\/blog\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Download Media from WhatsApp Webhooks: Guide with Code","description":"Download media from WhatsApp webhooks: get the media ID, fetch the 5-minute URL, download with your token and save to S3. cURL, Node and Python examples.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/vectalk.com.br\/blog\/en\/download-media-whatsapp-webhook\/","og_locale":"en_US","og_type":"article","og_title":"Download Media from WhatsApp Webhooks: Guide with Code","og_description":"Download media from WhatsApp webhooks: get the media ID, fetch the 5-minute URL, download with your token and save to S3. cURL, Node and Python examples.","og_url":"https:\/\/vectalk.com.br\/blog\/en\/download-media-whatsapp-webhook\/","og_site_name":"Blog Vectalk","article_published_time":"2026-10-28T16:05:47+00:00","article_modified_time":"2026-10-28T16:05:59+00:00","author":"wanderleyfcunha","twitter_card":"summary_large_image","twitter_misc":{"Written by":"wanderleyfcunha","Est. reading time":"9 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/vectalk.com.br\/blog\/en\/download-media-whatsapp-webhook\/#article","isPartOf":{"@id":"https:\/\/vectalk.com.br\/blog\/en\/download-media-whatsapp-webhook\/"},"author":{"name":"wanderleyfcunha","@id":"https:\/\/vectalk.com.br\/blog\/#\/schema\/person\/ff36ecd9d8257856f227f8e5d639db2b"},"headline":"How to receive and download media customers send through the WhatsApp API","datePublished":"2026-10-28T16:05:47+00:00","dateModified":"2026-10-28T16:05:59+00:00","mainEntityOfPage":{"@id":"https:\/\/vectalk.com.br\/blog\/en\/download-media-whatsapp-webhook\/"},"wordCount":1182,"articleSection":["Blog"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/vectalk.com.br\/blog\/en\/download-media-whatsapp-webhook\/","url":"https:\/\/vectalk.com.br\/blog\/en\/download-media-whatsapp-webhook\/","name":"Download Media from WhatsApp Webhooks: Guide with Code","isPartOf":{"@id":"https:\/\/vectalk.com.br\/blog\/#website"},"datePublished":"2026-10-28T16:05:47+00:00","dateModified":"2026-10-28T16:05:59+00:00","author":{"@id":"https:\/\/vectalk.com.br\/blog\/#\/schema\/person\/ff36ecd9d8257856f227f8e5d639db2b"},"description":"Download media from WhatsApp webhooks: get the media ID, fetch the 5-minute URL, download with your token and save to S3. cURL, Node and Python examples.","breadcrumb":{"@id":"https:\/\/vectalk.com.br\/blog\/en\/download-media-whatsapp-webhook\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/vectalk.com.br\/blog\/en\/download-media-whatsapp-webhook\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/vectalk.com.br\/blog\/en\/download-media-whatsapp-webhook\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/vectalk.com.br\/blog\/"},{"@type":"ListItem","position":2,"name":"How to receive and download media customers send through the WhatsApp API"}]},{"@type":"WebSite","@id":"https:\/\/vectalk.com.br\/blog\/#website","url":"https:\/\/vectalk.com.br\/blog\/","name":"Blog Vectalk","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/vectalk.com.br\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/vectalk.com.br\/blog\/#\/schema\/person\/ff36ecd9d8257856f227f8e5d639db2b","name":"wanderleyfcunha","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/21c37077f1731eb558973f27a7b647d55f72fde5200a843ac5f5345b247ea725?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/21c37077f1731eb558973f27a7b647d55f72fde5200a843ac5f5345b247ea725?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/21c37077f1731eb558973f27a7b647d55f72fde5200a843ac5f5345b247ea725?s=96&d=mm&r=g","caption":"wanderleyfcunha"},"sameAs":["https:\/\/vectalk.com.br\/blog"]}]}},"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/vectalk.com.br\/blog\/wp-json\/wp\/v2\/posts\/517","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vectalk.com.br\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/vectalk.com.br\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/vectalk.com.br\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/vectalk.com.br\/blog\/wp-json\/wp\/v2\/comments?post=517"}],"version-history":[{"count":1,"href":"https:\/\/vectalk.com.br\/blog\/wp-json\/wp\/v2\/posts\/517\/revisions"}],"predecessor-version":[{"id":520,"href":"https:\/\/vectalk.com.br\/blog\/wp-json\/wp\/v2\/posts\/517\/revisions\/520"}],"wp:attachment":[{"href":"https:\/\/vectalk.com.br\/blog\/wp-json\/wp\/v2\/media?parent=517"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vectalk.com.br\/blog\/wp-json\/wp\/v2\/categories?post=517"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vectalk.com.br\/blog\/wp-json\/wp\/v2\/tags?post=517"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}