Send media
هذا المحتوى غير متوفر بلغتك بعد.
Two ways to attach a file, and which one you want depends on how often you send the same thing.
By link
Section titled “By link”Give us a public URL. We fetch it and upload it to WhatsApp.
{ "to": "+966500000000", "type": "document", "document": { "link": "https://example.com/invoices/1001.pdf", "filename": "Invoice-1001.pdf", "caption": "Your invoice for order 1001" }}Simplest for anything generated per customer, like an invoice: you already have a URL and it is used once.
The URL must be publicly reachable over http or https. Private and internal
addresses are refused before the fetch, and refused again at connection time if
DNS resolves to one. Maximum 15 MB.
By media id
Section titled “By media id”If you already uploaded the file to Meta, pass its id and skip the transfer.
{ "to": "+966500000000", "type": "image", "image": { "id": "1234567890123456", "caption": "This week's offers" }}Worth doing for anything sent to many people, such as a campaign image: upload once, reference it thousands of times, and no bytes move per send.
type | Field | Notes |
|---|---|---|
image | image | JPEG or PNG. caption supported. |
video | video | MP4 or 3GPP. caption supported. |
document | document | Any type. filename is shown to the recipient. |
audio | audio | AAC, MP4, MPEG, AMR or OGG. No caption. |
WhatsApp’s own size limits apply and differ per type. A file it refuses comes
back as upstream_failure with Meta’s explanation.
Voice notes
Section titled “Voice notes”Audio can be sent as a push-to-talk note rather than an attached file:
{ "to": "+966500000000", "type": "audio", "audio": { "link": "https://example.com/reply.ogg", "voice": true }}It appears in the chat as a recorded message with a waveform. WhatsApp expects OGG with the Opus codec for this; other formats send as a plain audio file.
Filenames
Section titled “Filenames”Without one we fall back to the last segment of the URL, and then to
document, so a link ending in a generated identifier produces exactly the
filename you would not want.
Reading media in
Section titled “Reading media in”Incoming media messages report has_media: true. Fetch the bytes with the
message id:
curl https://k-message.kerneltics.com/v1/media/6f1c2d3e-... \ -H "Authorization: Bearer km_live_YOUR_KEY" \ -o received.jpgThe response is the file with its original content type, not JSON. It needs the
messages:read scope.