[{"data":1,"prerenderedAt":1582},["ShallowReactive",2],{"guide:media":3},{"id":4,"title":5,"body":6,"date":1571,"description":1572,"extension":1573,"meta":1574,"navigation":489,"path":1575,"seo":1576,"stem":1577,"tags":1578,"updated":1580,"__hash__":1581},"guides\u002Fdocs\u002Fmedia.md","Sending and Receiving Media",{"type":7,"value":8,"toc":1561},"minimark",[9,27,32,35,139,157,663,670,696,705,714,721,778,782,796,843,949,957,961,964,1017,1024,1028,1038,1203,1214,1227,1231,1258,1288,1299,1317,1549,1557],[10,11,12,13,17,18,22,23,26],"p",{},"Media in Wapito is one field and one store. The ",[14,15,16],"strong",{},"field"," is ",[19,20,21],"code",{},"media"," on every send endpoint that\ncarries a file, and it accepts three forms: a public URL, a data URI, or the id of a file you\nuploaded earlier. The ",[14,24,25],{},"store"," is where those uploads live, and where every inbound file is\ncopied to the moment it arrives, so a photo a customer sent this morning is still there long after\nWhatsApp itself has discarded it. This page covers both directions, the size and type limits, and\nthe signed links that let a browser fetch a file without ever seeing your channel token.",[28,29,31],"h2",{"id":30},"sending-a-file","Sending a file",[10,33,34],{},"Seven endpoints send media, one per bubble type WhatsApp renders:",[36,37,38,51],"table",{},[39,40,41],"thead",{},[42,43,44,48],"tr",{},[45,46,47],"th",{},"Endpoint",[45,49,50],{},"What the recipient sees",[52,53,54,68,79,90,101,112,128],"tbody",{},[42,55,56,65],{},[57,58,59],"td",{},[60,61],"endpoint-ref",{"label":62,"op":63,"tag":64},"POST \u002Fmessages\u002Fimage","send-image","messages",[57,66,67],{},"A photo with an optional caption. JPEG, PNG or WebP.",[42,69,70,76],{},[57,71,72],{},[60,73],{"label":74,"op":75,"tag":64},"POST \u002Fmessages\u002Fvideo","send-video",[57,77,78],{},"A video with an optional caption.",[42,80,81,87],{},[57,82,83],{},[60,84],{"label":85,"op":86,"tag":64},"POST \u002Fmessages\u002Fdocument","send-document",[57,88,89],{},"A file bubble with the name you give it. Bytes are never re-encoded.",[42,91,92,98],{},[57,93,94],{},[60,95],{"label":96,"op":97,"tag":64},"POST \u002Fmessages\u002Fsticker","send-sticker",[57,99,100],{},"A sticker. WebP only; no caption.",[42,102,103,109],{},[57,104,105],{},[60,106],{"label":107,"op":108,"tag":64},"POST \u002Fmessages\u002Faudio","send-audio",[57,110,111],{},"An audio file with a play bar.",[42,113,114,120],{},[57,115,116],{},[60,117],{"label":118,"op":119,"tag":64},"POST \u002Fmessages\u002Fvoice","send-voice",[57,121,122,123,127],{},"A voice note: the waveform bubble, with a ",[124,125,126],"em",{},"played"," receipt. Wapito converts MP3, WAV and M4A to the Opus-in-OGG format WhatsApp needs.",[42,129,130,136],{},[57,131,132],{},[60,133],{"label":134,"op":135,"tag":64},"POST \u002Fmessages\u002Fshort","send-short",[57,137,138],{},"A round video note.",[10,140,141,142,145,146,148,149,152,153,156],{},"They share one request body: ",[19,143,144],{},"to",", ",[19,147,21],{},", and depending on the type ",[19,150,151],{},"caption"," and ",[19,154,155],{},"filename",".",[158,159,160,260,462],"code-group",{},[161,162,168],"pre",{"className":163,"code":164,"filename":165,"language":166,"meta":167,"style":167},"language-bash shiki shiki-themes github-light-default github-dark-default","curl -X POST https:\u002F\u002Fapi.wapito.com\u002Fv1\u002Fmessages\u002Fdocument \\\n  -H \"Authorization: Bearer $WAPITO_TOKEN\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"to\": \"+15551234567\",\n    \"media\": \"https:\u002F\u002Facme.example\u002Finvoices\u002F4182.pdf\",\n    \"filename\": \"Invoice-4182.pdf\",\n    \"caption\": \"Invoice for order #4182\"\n  }'\n","curl","bash","",[19,169,170,193,211,221,230,236,242,248,254],{"__ignoreMap":167},[171,172,175,178,182,186,189],"span",{"class":173,"line":174},"line",1,[171,176,165],{"class":177},"sTDnQ",[171,179,181],{"class":180},"sHrmB"," -X",[171,183,185],{"class":184},"sSVrQ"," POST",[171,187,188],{"class":184}," https:\u002F\u002Fapi.wapito.com\u002Fv1\u002Fmessages\u002Fdocument",[171,190,192],{"class":191},"sjeE4"," \\\n",[171,194,196,199,202,206,209],{"class":173,"line":195},2,[171,197,198],{"class":180},"  -H",[171,200,201],{"class":184}," \"Authorization: Bearer ",[171,203,205],{"class":204},"s4rv2","$WAPITO_TOKEN",[171,207,208],{"class":184},"\"",[171,210,192],{"class":191},[171,212,214,216,219],{"class":173,"line":213},3,[171,215,198],{"class":180},[171,217,218],{"class":184}," \"Content-Type: application\u002Fjson\"",[171,220,192],{"class":191},[171,222,224,227],{"class":173,"line":223},4,[171,225,226],{"class":180},"  -d",[171,228,229],{"class":184}," '{\n",[171,231,233],{"class":173,"line":232},5,[171,234,235],{"class":184},"    \"to\": \"+15551234567\",\n",[171,237,239],{"class":173,"line":238},6,[171,240,241],{"class":184},"    \"media\": \"https:\u002F\u002Facme.example\u002Finvoices\u002F4182.pdf\",\n",[171,243,245],{"class":173,"line":244},7,[171,246,247],{"class":184},"    \"filename\": \"Invoice-4182.pdf\",\n",[171,249,251],{"class":173,"line":250},8,[171,252,253],{"class":184},"    \"caption\": \"Invoice for order #4182\"\n",[171,255,257],{"class":173,"line":256},9,[171,258,259],{"class":184},"  }'\n",[161,261,266],{"className":262,"code":263,"filename":264,"language":265,"meta":167,"style":167},"language-javascript shiki shiki-themes github-light-default github-dark-default","const res = await fetch('https:\u002F\u002Fapi.wapito.com\u002Fv1\u002Fmessages\u002Fdocument', {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.WAPITO_TOKEN}`,\n    'Content-Type': 'application\u002Fjson',\n  },\n  body: JSON.stringify({\n    to: '+15551234567',\n    media: 'https:\u002F\u002Facme.example\u002Finvoices\u002F4182.pdf',\n    filename: 'Invoice-4182.pdf',\n    caption: 'Invoice for order #4182',\n  }),\n});\nconst message = await res.json();\nconsole.log(message.document.link); \u002F\u002F a signed link to the stored copy\n","Node","javascript",[19,267,268,295,306,311,337,350,355,371,381,391,402,413,419,425,446],{"__ignoreMap":167},[171,269,270,273,276,279,282,286,289,292],{"class":173,"line":174},[171,271,272],{"class":191},"const",[171,274,275],{"class":180}," res",[171,277,278],{"class":191}," =",[171,280,281],{"class":191}," await",[171,283,285],{"class":284},"sbjLL"," fetch",[171,287,288],{"class":204},"(",[171,290,291],{"class":184},"'https:\u002F\u002Fapi.wapito.com\u002Fv1\u002Fmessages\u002Fdocument'",[171,293,294],{"class":204},", {\n",[171,296,297,300,303],{"class":173,"line":195},[171,298,299],{"class":204},"  method: ",[171,301,302],{"class":184},"'POST'",[171,304,305],{"class":204},",\n",[171,307,308],{"class":173,"line":213},[171,309,310],{"class":204},"  headers: {\n",[171,312,313,316,319,322,324,327,329,332,335],{"class":173,"line":223},[171,314,315],{"class":204},"    Authorization: ",[171,317,318],{"class":184},"`Bearer ${",[171,320,321],{"class":204},"process",[171,323,156],{"class":184},[171,325,326],{"class":204},"env",[171,328,156],{"class":184},[171,330,331],{"class":180},"WAPITO_TOKEN",[171,333,334],{"class":184},"}`",[171,336,305],{"class":204},[171,338,339,342,345,348],{"class":173,"line":232},[171,340,341],{"class":184},"    'Content-Type'",[171,343,344],{"class":204},": ",[171,346,347],{"class":184},"'application\u002Fjson'",[171,349,305],{"class":204},[171,351,352],{"class":173,"line":238},[171,353,354],{"class":204},"  },\n",[171,356,357,360,363,365,368],{"class":173,"line":244},[171,358,359],{"class":204},"  body: ",[171,361,362],{"class":180},"JSON",[171,364,156],{"class":204},[171,366,367],{"class":284},"stringify",[171,369,370],{"class":204},"({\n",[171,372,373,376,379],{"class":173,"line":250},[171,374,375],{"class":204},"    to: ",[171,377,378],{"class":184},"'+15551234567'",[171,380,305],{"class":204},[171,382,383,386,389],{"class":173,"line":256},[171,384,385],{"class":204},"    media: ",[171,387,388],{"class":184},"'https:\u002F\u002Facme.example\u002Finvoices\u002F4182.pdf'",[171,390,305],{"class":204},[171,392,394,397,400],{"class":173,"line":393},10,[171,395,396],{"class":204},"    filename: ",[171,398,399],{"class":184},"'Invoice-4182.pdf'",[171,401,305],{"class":204},[171,403,405,408,411],{"class":173,"line":404},11,[171,406,407],{"class":204},"    caption: ",[171,409,410],{"class":184},"'Invoice for order #4182'",[171,412,305],{"class":204},[171,414,416],{"class":173,"line":415},12,[171,417,418],{"class":204},"  }),\n",[171,420,422],{"class":173,"line":421},13,[171,423,424],{"class":204},"});\n",[171,426,428,430,433,435,437,440,443],{"class":173,"line":427},14,[171,429,272],{"class":191},[171,431,432],{"class":180}," message",[171,434,278],{"class":191},[171,436,281],{"class":191},[171,438,439],{"class":204}," res.",[171,441,442],{"class":284},"json",[171,444,445],{"class":204},"();\n",[171,447,449,452,455,458],{"class":173,"line":448},15,[171,450,451],{"class":204},"console.",[171,453,454],{"class":284},"log",[171,456,457],{"class":204},"(message.document.link); ",[171,459,461],{"class":460},"sU953","\u002F\u002F a signed link to the stored copy\n",[161,463,468],{"className":464,"code":465,"filename":466,"language":467,"meta":167,"style":167},"language-python shiki shiki-themes github-light-default github-dark-default","import os\nimport requests\n\nres = requests.post(\n    \"https:\u002F\u002Fapi.wapito.com\u002Fv1\u002Fmessages\u002Fdocument\",\n    headers={\"Authorization\": f\"Bearer {os.environ['WAPITO_TOKEN']}\"},\n    json={\n        \"to\": \"+15551234567\",\n        \"media\": \"https:\u002F\u002Facme.example\u002Finvoices\u002F4182.pdf\",\n        \"filename\": \"Invoice-4182.pdf\",\n        \"caption\": \"Invoice for order #4182\",\n    },\n    timeout=(5, 60),\n)\nres.raise_for_status()\nprint(res.json()[\"document\"][\"link\"])\n","Python","python",[19,469,470,478,485,491,502,509,549,559,571,583,595,607,612,632,637,642],{"__ignoreMap":167},[171,471,472,475],{"class":173,"line":174},[171,473,474],{"class":191},"import",[171,476,477],{"class":204}," os\n",[171,479,480,482],{"class":173,"line":195},[171,481,474],{"class":191},[171,483,484],{"class":204}," requests\n",[171,486,487],{"class":173,"line":213},[171,488,490],{"emptyLinePlaceholder":489},true,"\n",[171,492,493,496,499],{"class":173,"line":223},[171,494,495],{"class":204},"res ",[171,497,498],{"class":191},"=",[171,500,501],{"class":204}," requests.post(\n",[171,503,504,507],{"class":173,"line":232},[171,505,506],{"class":184},"    \"https:\u002F\u002Fapi.wapito.com\u002Fv1\u002Fmessages\u002Fdocument\"",[171,508,305],{"class":204},[171,510,511,514,516,519,522,524,527,530,532,535,538,541,544,546],{"class":173,"line":238},[171,512,513],{"class":177},"    headers",[171,515,498],{"class":191},[171,517,518],{"class":204},"{",[171,520,521],{"class":184},"\"Authorization\"",[171,523,344],{"class":204},[171,525,526],{"class":191},"f",[171,528,529],{"class":184},"\"Bearer ",[171,531,518],{"class":191},[171,533,534],{"class":204},"os.environ[",[171,536,537],{"class":184},"'WAPITO_TOKEN'",[171,539,540],{"class":204},"]",[171,542,543],{"class":191},"}",[171,545,208],{"class":184},[171,547,548],{"class":204},"},\n",[171,550,551,554,556],{"class":173,"line":244},[171,552,553],{"class":177},"    json",[171,555,498],{"class":191},[171,557,558],{"class":204},"{\n",[171,560,561,564,566,569],{"class":173,"line":250},[171,562,563],{"class":184},"        \"to\"",[171,565,344],{"class":204},[171,567,568],{"class":184},"\"+15551234567\"",[171,570,305],{"class":204},[171,572,573,576,578,581],{"class":173,"line":256},[171,574,575],{"class":184},"        \"media\"",[171,577,344],{"class":204},[171,579,580],{"class":184},"\"https:\u002F\u002Facme.example\u002Finvoices\u002F4182.pdf\"",[171,582,305],{"class":204},[171,584,585,588,590,593],{"class":173,"line":393},[171,586,587],{"class":184},"        \"filename\"",[171,589,344],{"class":204},[171,591,592],{"class":184},"\"Invoice-4182.pdf\"",[171,594,305],{"class":204},[171,596,597,600,602,605],{"class":173,"line":404},[171,598,599],{"class":184},"        \"caption\"",[171,601,344],{"class":204},[171,603,604],{"class":184},"\"Invoice for order #4182\"",[171,606,305],{"class":204},[171,608,609],{"class":173,"line":415},[171,610,611],{"class":204},"    },\n",[171,613,614,617,619,621,624,626,629],{"class":173,"line":421},[171,615,616],{"class":177},"    timeout",[171,618,498],{"class":191},[171,620,288],{"class":204},[171,622,623],{"class":180},"5",[171,625,145],{"class":204},[171,627,628],{"class":180},"60",[171,630,631],{"class":204},"),\n",[171,633,634],{"class":173,"line":427},[171,635,636],{"class":204},")\n",[171,638,639],{"class":173,"line":448},[171,640,641],{"class":204},"res.raise_for_status()\n",[171,643,645,648,651,654,657,660],{"class":173,"line":644},16,[171,646,647],{"class":180},"print",[171,649,650],{"class":204},"(res.json()[",[171,652,653],{"class":184},"\"document\"",[171,655,656],{"class":204},"][",[171,658,659],{"class":184},"\"link\"",[171,661,662],{"class":204},"])\n",[664,665,667,668],"h3",{"id":666},"the-three-forms-of-media","The three forms of ",[19,669,21],{},[10,671,672,675,676,679,680,683,684,687,688,691,692,695],{},[14,673,674],{},"A URL."," ",[19,677,678],{},"https:\u002F\u002F"," only, and the host must resolve to a public address. Wapito probes it\nwith a ",[19,681,682],{},"HEAD"," request — that is where the size and the type are read from — and the protocol\nengine then downloads it, so the URL is never shown to the recipient and never has to be\nreachable from WhatsApp itself. Up to two redirects are followed, each one checked again. A URL\nthat points at a private range, a plain ",[19,685,686],{},"http"," URL, or one that does not answer within ten\nseconds is refused with ",[19,689,690],{},"400 invalid_request"," and a ",[19,693,694],{},"details.reason"," saying why.",[10,697,698,675,701,704],{},[14,699,700],{},"A data URI.",[19,702,703],{},"data:application\u002Fpdf;base64,JVBERi0…"," — the bytes inline. Convenient for small\nfiles generated on the fly; for anything large, upload first.",[10,706,707,675,710,713],{},[14,708,709],{},"A media id.",[19,711,712],{},"med_01JRQ8F4X9N2K7YB3C5V6W8H0T",", returned by an upload or found on any media\nmessage. The file is already in the store, so a send is immediate and the same id can go to a\nhundred recipients without a hundred fetches. This is the right form for anything you send more\nthan once.",[10,715,716,717,720],{},"When the type or the name cannot be inferred — an upload endpoint that serves every file as\n",[19,718,719],{},"application\u002Foctet-stream",", say — pass an object instead of a string:",[161,722,725],{"className":723,"code":724,"language":442,"meta":167,"style":167},"language-json shiki shiki-themes github-light-default github-dark-default","{ \"to\": \"+15551234567\", \"media\": { \"url\": \"https:\u002F\u002Facme.example\u002Fdl?id=4182\", \"mimetype\": \"application\u002Fpdf\", \"filename\": \"Invoice-4182.pdf\" } }\n",[19,726,727],{"__ignoreMap":167},[171,728,729,732,736,738,740,742,745,748,751,753,756,758,761,763,766,768,771,773,775],{"class":173,"line":174},[171,730,731],{"class":204},"{ ",[171,733,735],{"class":734},"sjgCt","\"to\"",[171,737,344],{"class":204},[171,739,568],{"class":184},[171,741,145],{"class":204},[171,743,744],{"class":734},"\"media\"",[171,746,747],{"class":204},": { ",[171,749,750],{"class":734},"\"url\"",[171,752,344],{"class":204},[171,754,755],{"class":184},"\"https:\u002F\u002Facme.example\u002Fdl?id=4182\"",[171,757,145],{"class":204},[171,759,760],{"class":734},"\"mimetype\"",[171,762,344],{"class":204},[171,764,765],{"class":184},"\"application\u002Fpdf\"",[171,767,145],{"class":204},[171,769,770],{"class":734},"\"filename\"",[171,772,344],{"class":204},[171,774,592],{"class":184},[171,776,777],{"class":204}," } }\n",[28,779,781],{"id":780},"uploading-first","Uploading first",[10,783,784,788,789,792,793,795],{},[60,785],{"label":786,"op":787,"tag":21},"POST \u002Fmedia","upload-media"," takes a multipart form with a\n",[19,790,791],{},"file"," part and an optional ",[19,794,155],{},", and returns the stored file:",[161,797,799],{"className":163,"code":798,"language":166,"meta":167,"style":167},"curl -X POST https:\u002F\u002Fapi.wapito.com\u002Fv1\u002Fmedia \\\n  -H \"Authorization: Bearer $WAPITO_TOKEN\" \\\n  -F \"file=@.\u002FInvoice-4182.pdf\" \\\n  -F \"filename=Invoice-4182.pdf\"\n",[19,800,801,814,826,836],{"__ignoreMap":167},[171,802,803,805,807,809,812],{"class":173,"line":174},[171,804,165],{"class":177},[171,806,181],{"class":180},[171,808,185],{"class":184},[171,810,811],{"class":184}," https:\u002F\u002Fapi.wapito.com\u002Fv1\u002Fmedia",[171,813,192],{"class":191},[171,815,816,818,820,822,824],{"class":173,"line":195},[171,817,198],{"class":180},[171,819,201],{"class":184},[171,821,205],{"class":204},[171,823,208],{"class":184},[171,825,192],{"class":191},[171,827,828,831,834],{"class":173,"line":213},[171,829,830],{"class":180},"  -F",[171,832,833],{"class":184}," \"file=@.\u002FInvoice-4182.pdf\"",[171,835,192],{"class":191},[171,837,838,840],{"class":173,"line":223},[171,839,830],{"class":180},[171,841,842],{"class":184}," \"filename=Invoice-4182.pdf\"\n",[161,844,846],{"className":723,"code":845,"language":442,"meta":167,"style":167},"{\n  \"id\": \"med_01JRQ8F4X9N2K7YB3C5V6W8H0T\",\n  \"channel_id\": \"ch_01JRQ8F4X9N2K7YB3C5V6W8H0T\",\n  \"filename\": \"Invoice-4182.pdf\",\n  \"mimetype\": \"application\u002Fpdf\",\n  \"size_bytes\": 48210,\n  \"link\": \"https:\u002F\u002Fapi.wapito.com\u002Fv1\u002Fmedia\u002Fmed_01JRQ8F4X9N2K7YB3C5V6W8H0T?exp=1790064121&sig=8f2c1d94b6a70e35\",\n  \"created_at\": \"2026-09-15T07:22:01.000Z\",\n  \"expires_at\": \"2026-09-22T07:22:01.000Z\"\n}\n",[19,847,848,852,864,876,887,898,910,922,934,944],{"__ignoreMap":167},[171,849,850],{"class":173,"line":174},[171,851,558],{"class":204},[171,853,854,857,859,862],{"class":173,"line":195},[171,855,856],{"class":734},"  \"id\"",[171,858,344],{"class":204},[171,860,861],{"class":184},"\"med_01JRQ8F4X9N2K7YB3C5V6W8H0T\"",[171,863,305],{"class":204},[171,865,866,869,871,874],{"class":173,"line":213},[171,867,868],{"class":734},"  \"channel_id\"",[171,870,344],{"class":204},[171,872,873],{"class":184},"\"ch_01JRQ8F4X9N2K7YB3C5V6W8H0T\"",[171,875,305],{"class":204},[171,877,878,881,883,885],{"class":173,"line":223},[171,879,880],{"class":734},"  \"filename\"",[171,882,344],{"class":204},[171,884,592],{"class":184},[171,886,305],{"class":204},[171,888,889,892,894,896],{"class":173,"line":232},[171,890,891],{"class":734},"  \"mimetype\"",[171,893,344],{"class":204},[171,895,765],{"class":184},[171,897,305],{"class":204},[171,899,900,903,905,908],{"class":173,"line":238},[171,901,902],{"class":734},"  \"size_bytes\"",[171,904,344],{"class":204},[171,906,907],{"class":180},"48210",[171,909,305],{"class":204},[171,911,912,915,917,920],{"class":173,"line":244},[171,913,914],{"class":734},"  \"link\"",[171,916,344],{"class":204},[171,918,919],{"class":184},"\"https:\u002F\u002Fapi.wapito.com\u002Fv1\u002Fmedia\u002Fmed_01JRQ8F4X9N2K7YB3C5V6W8H0T?exp=1790064121&sig=8f2c1d94b6a70e35\"",[171,921,305],{"class":204},[171,923,924,927,929,932],{"class":173,"line":250},[171,925,926],{"class":734},"  \"created_at\"",[171,928,344],{"class":204},[171,930,931],{"class":184},"\"2026-09-15T07:22:01.000Z\"",[171,933,305],{"class":204},[171,935,936,939,941],{"class":173,"line":256},[171,937,938],{"class":734},"  \"expires_at\"",[171,940,344],{"class":204},[171,942,943],{"class":184},"\"2026-09-22T07:22:01.000Z\"\n",[171,945,946],{"class":173,"line":393},[171,947,948],{"class":204},"}\n",[10,950,951,952,956],{},"Uploads expire like inbound files do (below), so an upload is a staging area for the sends that\nfollow, not an archive. ",[60,953],{"label":954,"op":955,"tag":21},"DELETE \u002Fmedia\u002F{id}","delete-media","\nremoves one early.",[28,958,960],{"id":959},"limits","Limits",[10,962,963],{},"Two checks run before any WhatsApp traffic happens, so a file that is too big or the wrong type\ncosts the number nothing:",[965,966,967,989],"ul",{},[968,969,970,973,974,977,978,981,982,985,986,156],"li",{},[14,971,972],{},"Size."," 16 MB on Sandbox and 64 MB on Premium — the decoded bytes of a data URI, the\nmultipart body of an upload, or the ",[19,975,976],{},"Content-Length"," a URL reports. Over the cap answers\n",[19,979,980],{},"413 payload_too_large",". The cap is also in ",[19,983,984],{},"GET \u002Fchannel\u002Flimits"," as ",[19,987,988],{},"media_max_bytes",[968,990,991,994,995,998,999,1002,1003,1006,1007,1009,1010,1012,1013,1016],{},[14,992,993],{},"Type."," The store keeps an allow-list, not a deny-list, of media types: the common image\nformats (JPEG, PNG, GIF, BMP, TIFF, HEIC), WebP for stickers, MP4, 3GPP, QuickTime, WebM and\nMatroska video, MP3, AAC, OGG, Opus, WAV, AMR and WebM audio, and PDF, Office, OpenDocument,\nRTF and ZIP documents. Anything else — SVG above all, which can carry script — answers\n",[19,996,997],{},"415 unsupported_media_type",". The type comes from the URL's ",[19,1000,1001],{},"Content-Type"," header, the data\nURI's declared type or the ",[19,1004,1005],{},"mimetype"," you pass explicitly — never from the file extension. A\nserver that answers without a usable ",[19,1008,1001],{}," gets ",[19,1011,690],{}," with\n",[19,1014,1015],{},"details.reason: \"media_mimetype_required\""," until you pass one.",[10,1018,1019,1020,1023],{},"Media sends count toward the daily ",[19,1021,1022],{},"sent"," quota exactly like text, one per message.",[28,1025,1027],{"id":1026},"receiving-a-file","Receiving a file",[10,1029,1030,1031,1033,1034,1037],{},"An inbound photo, document or voice note arrives as a ",[19,1032,64],{}," event whose message object has\n",[19,1035,1036],{},"type"," set and one typed field beside it:",[161,1039,1041],{"className":723,"code":1040,"language":442,"meta":167,"style":167},"{\n  \"id\": \"false_15551234567@s.whatsapp.net_9F31A0C4D7E2B6081A55\",\n  \"chat_id\": \"15551234567@s.whatsapp.net\",\n  \"from\": \"15551234567\",\n  \"from_me\": false,\n  \"type\": \"image\",\n  \"timestamp\": 1789459200000,\n  \"image\": {\n    \"id\": \"med_01JRQ8F4X9N2K7YB3C5V6W8H0T\",\n    \"link\": \"https:\u002F\u002Fapi.wapito.com\u002Fv1\u002Fmedia\u002Fmed_01JRQ8F4X9N2K7YB3C5V6W8H0T?exp=1790064121&sig=8f2c1d94b6a70e35\",\n    \"mime_type\": \"image\u002Fjpeg\",\n    \"file_size\": 184213,\n    \"file_name\": null,\n    \"caption\": \"Here is the receipt\"\n  }\n}\n",[19,1042,1043,1047,1058,1070,1082,1094,1106,1118,1126,1137,1148,1160,1172,1184,1194,1199],{"__ignoreMap":167},[171,1044,1045],{"class":173,"line":174},[171,1046,558],{"class":204},[171,1048,1049,1051,1053,1056],{"class":173,"line":195},[171,1050,856],{"class":734},[171,1052,344],{"class":204},[171,1054,1055],{"class":184},"\"false_15551234567@s.whatsapp.net_9F31A0C4D7E2B6081A55\"",[171,1057,305],{"class":204},[171,1059,1060,1063,1065,1068],{"class":173,"line":213},[171,1061,1062],{"class":734},"  \"chat_id\"",[171,1064,344],{"class":204},[171,1066,1067],{"class":184},"\"15551234567@s.whatsapp.net\"",[171,1069,305],{"class":204},[171,1071,1072,1075,1077,1080],{"class":173,"line":223},[171,1073,1074],{"class":734},"  \"from\"",[171,1076,344],{"class":204},[171,1078,1079],{"class":184},"\"15551234567\"",[171,1081,305],{"class":204},[171,1083,1084,1087,1089,1092],{"class":173,"line":232},[171,1085,1086],{"class":734},"  \"from_me\"",[171,1088,344],{"class":204},[171,1090,1091],{"class":180},"false",[171,1093,305],{"class":204},[171,1095,1096,1099,1101,1104],{"class":173,"line":238},[171,1097,1098],{"class":734},"  \"type\"",[171,1100,344],{"class":204},[171,1102,1103],{"class":184},"\"image\"",[171,1105,305],{"class":204},[171,1107,1108,1111,1113,1116],{"class":173,"line":244},[171,1109,1110],{"class":734},"  \"timestamp\"",[171,1112,344],{"class":204},[171,1114,1115],{"class":180},"1789459200000",[171,1117,305],{"class":204},[171,1119,1120,1123],{"class":173,"line":250},[171,1121,1122],{"class":734},"  \"image\"",[171,1124,1125],{"class":204},": {\n",[171,1127,1128,1131,1133,1135],{"class":173,"line":256},[171,1129,1130],{"class":734},"    \"id\"",[171,1132,344],{"class":204},[171,1134,861],{"class":184},[171,1136,305],{"class":204},[171,1138,1139,1142,1144,1146],{"class":173,"line":393},[171,1140,1141],{"class":734},"    \"link\"",[171,1143,344],{"class":204},[171,1145,919],{"class":184},[171,1147,305],{"class":204},[171,1149,1150,1153,1155,1158],{"class":173,"line":404},[171,1151,1152],{"class":734},"    \"mime_type\"",[171,1154,344],{"class":204},[171,1156,1157],{"class":184},"\"image\u002Fjpeg\"",[171,1159,305],{"class":204},[171,1161,1162,1165,1167,1170],{"class":173,"line":415},[171,1163,1164],{"class":734},"    \"file_size\"",[171,1166,344],{"class":204},[171,1168,1169],{"class":180},"184213",[171,1171,305],{"class":204},[171,1173,1174,1177,1179,1182],{"class":173,"line":421},[171,1175,1176],{"class":734},"    \"file_name\"",[171,1178,344],{"class":204},[171,1180,1181],{"class":180},"null",[171,1183,305],{"class":204},[171,1185,1186,1189,1191],{"class":173,"line":427},[171,1187,1188],{"class":734},"    \"caption\"",[171,1190,344],{"class":204},[171,1192,1193],{"class":184},"\"Here is the receipt\"\n",[171,1195,1196],{"class":173,"line":448},[171,1197,1198],{"class":204},"  }\n",[171,1200,1201],{"class":173,"line":644},[171,1202,948],{"class":204},[10,1204,1205,1206,1209,1210,1213],{},"By the time the event reaches you the file has been copied out of the protocol engine into the\nWapito store, and ",[19,1207,1208],{},"link"," points at that copy. The engine itself keeps a file for about an hour;\nthe copy is what makes the link usable for days. If the copy failed — a file WhatsApp had already\ndropped, or one that could not be decrypted — the event still ships, with\n",[19,1211,1212],{},"{ \"id\": null, \"error\": \"unavailable\" }"," in place of the media block, so a missing file never\ndelays the message that carried it.",[10,1215,1216,1217,1220,1221,1226],{},"Your webhook handler should return ",[19,1218,1219],{},"200"," first and fetch the file from a worker: media downloads\nare the slowest thing a handler can do inline, and the ",[1222,1223,1225],"a",{"href":1224},"\u002Fdocs\u002Fwebhooks\u002F","ten-second delivery timeout","\nis for the acknowledgement, not for the download.",[28,1228,1230],{"id":1229},"signed-links-and-expiry","Signed links and expiry",[10,1232,1233,1234,1236,1237,1241,1242,152,1245,1248,1249,1252,1253,152,1255,1257],{},"A ",[19,1235,1208],{}," is a URL to ",[60,1238],{"label":1239,"op":1240,"tag":21},"GET \u002Fmedia\u002F{id}","get-media"," with two\nquery parameters, ",[19,1243,1244],{},"exp",[19,1246,1247],{},"sig",". The signature covers the media id and the expiry, so neither\ncan be edited to reach another file or extend the window, and the link needs ",[14,1250,1251],{},"no Bearer\nheader"," — that is what makes it safe to hand to a browser, an e-mail, or a downstream service\nthat must never hold the channel token. The same endpoint also accepts the channel token, without\n",[19,1254,1244],{},[19,1256,1247],{},", for your own back end.",[36,1259,1260,1270],{},[39,1261,1262],{},[42,1263,1264,1267],{},[45,1265,1266],{},"Plan",[45,1268,1269],{},"Inbound and uploaded files are kept for",[52,1271,1272,1280],{},[42,1273,1274,1277],{},[57,1275,1276],{},"Sandbox",[57,1278,1279],{},"24 hours",[42,1281,1282,1285],{},[57,1283,1284],{},"Premium",[57,1286,1287],{},"7 days",[10,1289,1290,1291,1294,1295,1298],{},"That window is the file's ",[19,1292,1293],{},"expires_at",", and it is also how long its signed links work. After it\nthe file is deleted and the link answers ",[19,1296,1297],{},"404 not_found",". Two consequences:",[965,1300,1301,1309],{},[968,1302,1303,1304,1308],{},"If you need the file for longer, fetch it and store your own copy. The store is a hand-off,\nnot an archive, and the ",[1222,1305,1307],{"href":1306},"\u002Fsecurity\u002F","security page"," lists this retention alongside everything\nelse Wapito keeps.",[968,1310,1311,1312,1316],{},"A link you saved yesterday may have expired even though the file has not, if you are close to\nthe window. ",[60,1313],{"label":1314,"op":1315,"tag":21},"GET \u002Fmessages\u002F{id}\u002Fmedia","get-message-media","\nreturns the file's current record with a freshly signed link.",[158,1318,1319,1346,1460],{},[161,1320,1322],{"className":163,"code":1321,"filename":165,"language":166,"meta":167,"style":167},"# Any HTTP client can follow a signed link — no Authorization header.\ncurl -o receipt.jpg \\\n  \"https:\u002F\u002Fapi.wapito.com\u002Fv1\u002Fmedia\u002Fmed_01JRQ8F4X9N2K7YB3C5V6W8H0T?exp=1790064121&sig=8f2c1d94b6a70e35\"\n",[19,1323,1324,1329,1341],{"__ignoreMap":167},[171,1325,1326],{"class":173,"line":174},[171,1327,1328],{"class":460},"# Any HTTP client can follow a signed link — no Authorization header.\n",[171,1330,1331,1333,1336,1339],{"class":173,"line":195},[171,1332,165],{"class":177},[171,1334,1335],{"class":180}," -o",[171,1337,1338],{"class":184}," receipt.jpg",[171,1340,192],{"class":191},[171,1342,1343],{"class":173,"line":213},[171,1344,1345],{"class":184},"  \"https:\u002F\u002Fapi.wapito.com\u002Fv1\u002Fmedia\u002Fmed_01JRQ8F4X9N2K7YB3C5V6W8H0T?exp=1790064121&sig=8f2c1d94b6a70e35\"\n",[161,1347,1349],{"className":262,"code":1348,"filename":264,"language":265,"meta":167,"style":167},"import { writeFile } from 'node:fs\u002Fpromises';\n\nconst res = await fetch(message.image.link);\nif (!res.ok) throw new Error(`media ${res.status}`); \u002F\u002F 404 once the window has closed\nawait writeFile('receipt.jpg', Buffer.from(await res.arrayBuffer()));\n",[19,1350,1351,1367,1371,1386,1430],{"__ignoreMap":167},[171,1352,1353,1355,1358,1361,1364],{"class":173,"line":174},[171,1354,474],{"class":191},[171,1356,1357],{"class":204}," { writeFile } ",[171,1359,1360],{"class":191},"from",[171,1362,1363],{"class":184}," 'node:fs\u002Fpromises'",[171,1365,1366],{"class":204},";\n",[171,1368,1369],{"class":173,"line":195},[171,1370,490],{"emptyLinePlaceholder":489},[171,1372,1373,1375,1377,1379,1381,1383],{"class":173,"line":213},[171,1374,272],{"class":191},[171,1376,275],{"class":180},[171,1378,278],{"class":191},[171,1380,281],{"class":191},[171,1382,285],{"class":284},[171,1384,1385],{"class":204},"(message.image.link);\n",[171,1387,1388,1391,1394,1397,1400,1403,1406,1409,1411,1414,1417,1419,1422,1424,1427],{"class":173,"line":223},[171,1389,1390],{"class":191},"if",[171,1392,1393],{"class":204}," (",[171,1395,1396],{"class":191},"!",[171,1398,1399],{"class":204},"res.ok) ",[171,1401,1402],{"class":191},"throw",[171,1404,1405],{"class":191}," new",[171,1407,1408],{"class":284}," Error",[171,1410,288],{"class":204},[171,1412,1413],{"class":184},"`media ${",[171,1415,1416],{"class":204},"res",[171,1418,156],{"class":184},[171,1420,1421],{"class":204},"status",[171,1423,334],{"class":184},[171,1425,1426],{"class":204},"); ",[171,1428,1429],{"class":460},"\u002F\u002F 404 once the window has closed\n",[171,1431,1432,1435,1438,1440,1443,1446,1448,1450,1452,1454,1457],{"class":173,"line":232},[171,1433,1434],{"class":191},"await",[171,1436,1437],{"class":284}," writeFile",[171,1439,288],{"class":204},[171,1441,1442],{"class":184},"'receipt.jpg'",[171,1444,1445],{"class":204},", Buffer.",[171,1447,1360],{"class":284},[171,1449,288],{"class":204},[171,1451,1434],{"class":191},[171,1453,439],{"class":204},[171,1455,1456],{"class":284},"arrayBuffer",[171,1458,1459],{"class":204},"()));\n",[161,1461,1463],{"className":464,"code":1462,"filename":466,"language":467,"meta":167,"style":167},"import requests\n\nres = requests.get(message[\"image\"][\"link\"], timeout=(5, 60))\nres.raise_for_status()  # 404 once the window has closed\nwith open(\"receipt.jpg\", \"wb\") as f:\n    f.write(res.content)\n",[19,1464,1465,1471,1475,1509,1517,1544],{"__ignoreMap":167},[171,1466,1467,1469],{"class":173,"line":174},[171,1468,474],{"class":191},[171,1470,484],{"class":204},[171,1472,1473],{"class":173,"line":195},[171,1474,490],{"emptyLinePlaceholder":489},[171,1476,1477,1479,1481,1484,1486,1488,1490,1493,1496,1498,1500,1502,1504,1506],{"class":173,"line":213},[171,1478,495],{"class":204},[171,1480,498],{"class":191},[171,1482,1483],{"class":204}," requests.get(message[",[171,1485,1103],{"class":184},[171,1487,656],{"class":204},[171,1489,659],{"class":184},[171,1491,1492],{"class":204},"], ",[171,1494,1495],{"class":177},"timeout",[171,1497,498],{"class":191},[171,1499,288],{"class":204},[171,1501,623],{"class":180},[171,1503,145],{"class":204},[171,1505,628],{"class":180},[171,1507,1508],{"class":204},"))\n",[171,1510,1511,1514],{"class":173,"line":223},[171,1512,1513],{"class":204},"res.raise_for_status()  ",[171,1515,1516],{"class":460},"# 404 once the window has closed\n",[171,1518,1519,1522,1525,1527,1530,1532,1535,1538,1541],{"class":173,"line":232},[171,1520,1521],{"class":191},"with",[171,1523,1524],{"class":180}," open",[171,1526,288],{"class":204},[171,1528,1529],{"class":184},"\"receipt.jpg\"",[171,1531,145],{"class":204},[171,1533,1534],{"class":184},"\"wb\"",[171,1536,1537],{"class":204},") ",[171,1539,1540],{"class":191},"as",[171,1542,1543],{"class":204}," f:\n",[171,1545,1546],{"class":173,"line":238},[171,1547,1548],{"class":204},"    f.write(res.content)\n",[1550,1551,1554],"callout",{"ban-risk":1552,"type":1553},"medium","warn",[10,1555,1556],{},"Media is the heaviest thing a number sends and the most visible when it is unwanted. A stream of\nimages or documents to people who never wrote to you is reported faster than text, and the\nsend queue paces media exactly as it paces text — no send endpoint bypasses it.",[1558,1559,1560],"style",{},"html pre.shiki code .sTDnQ, html code.shiki .sTDnQ{--shiki-default:#953800;--shiki-dark:#FFA657}html pre.shiki code .sHrmB, html code.shiki .sHrmB{--shiki-default:#0550AE;--shiki-dark:#79C0FF}html pre.shiki code .sSVrQ, html code.shiki .sSVrQ{--shiki-default:#0A3069;--shiki-dark:#A5D6FF}html pre.shiki code .sjeE4, html code.shiki .sjeE4{--shiki-default:#CF222E;--shiki-dark:#FF7B72}html pre.shiki code .s4rv2, html code.shiki .s4rv2{--shiki-default:#1F2328;--shiki-dark:#E6EDF3}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sbjLL, html code.shiki .sbjLL{--shiki-default:#8250DF;--shiki-dark:#D2A8FF}html pre.shiki code .sU953, html code.shiki .sU953{--shiki-default:#6E7781;--shiki-dark:#8B949E}html pre.shiki code .sjgCt, html code.shiki .sjgCt{--shiki-default:#116329;--shiki-dark:#7EE787}",{"title":167,"searchDepth":195,"depth":195,"links":1562},[1563,1567,1568,1569,1570],{"id":30,"depth":195,"text":31,"children":1564},[1565],{"id":666,"depth":213,"text":1566},"The three forms of media",{"id":780,"depth":195,"text":781},{"id":959,"depth":195,"text":960},{"id":1026,"depth":195,"text":1027},{"id":1229,"depth":195,"text":1230},"2026-09-15","Upload images, audio, video and documents, send them to chats and groups, and download inbound media before the retention window closes.","md",{},"\u002Fdocs\u002Fmedia",{"title":5,"description":1572},"docs\u002Fmedia",[21,64,1579],"storage",null,"gFNFrRxWhONpnZJKKNBf8UmM39YJn8v-k2ewnBTlj7k",1790464894220]