WhatsApp API guide

How to send images, audio, video and documents with the WhatsApp API

In the WhatsApp API, each media type has its own endpoint, and they all follow the same logic: you pass the connection, the number and the file, as a public URL or base64. On the receiving side, media customers send arrives through the webhook and can be downloaded through the API.

By D-API engineering team5 min read

Why media changes the outcome of a conversation

An invoice as a PDF gets more done than a link to it. A product photo sells better than a description. A short voice note from a sales rep feels closer than three paragraphs. In business systems, the receipt a customer photographs and sends back needs to reach the finance team without anyone downloading and uploading files by hand.

A WhatsApp API handles both directions: your system attaches files to the messages it sends and receives the files customers send, ready to store or process.

Sending endpoints by media type

TypeEndpointFile fieldUseful options
Image/messages/send/imageimagecaption
Audio/messages/send/audioaudioptt (voice note)
Video/messages/send/videovideocaption, ptv, gifPlayback
Document/messages/send/documentdocumentfileName, mimetype
Album/messages/send/albummedia (list)caption per item
Sticker/messages/send/stickersticker-

Every route lives under https://api.d-api.cloud/api/v1 and requires sessionId and to, with the number in international format without the plus sign, like 14155550123.

Sending examples

A document with a friendly name

curl -X POST https://api.d-api.cloud/api/v1/messages/send/document \
  -H "Authorization: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "sessionId": "billing",
    "to": "14155550123",
    "document": "https://files.yourcompany.com/invoices/8812.pdf",
    "fileName": "invoice-september.pdf",
    "mimetype": "application/pdf"
  }'

Without fileName, the customer sees a generic name and gets suspicious. It is a small detail that cuts down on "is this a scam?" questions in support.

Image, voice note and album with the Node SDK

import { DApi } from 'd-api-sdk'

const dapi = new DApi({ apiKey: process.env.DAPI_KEY })

await dapi.messages.sendImage({
  sessionId: 'store',
  to: '14155550123',
  image: 'https://cdn.yourcompany.com/products/blue-sneakers.jpg',
  caption: 'Back in stock in your size. Want me to hold a pair?',
})

await dapi.messages.sendAudio({
  sessionId: 'store',
  to: '14155550123',
  audio: 'https://cdn.yourcompany.com/audio/welcome.ogg',
  ptt: true,
})

await dapi.messages.sendAlbum({
  sessionId: 'store',
  to: '14155550123',
  media: [
    { type: 'image', url: 'https://cdn.yourcompany.com/products/front.jpg', caption: 'Front' },
    { type: 'image', url: 'https://cdn.yourcompany.com/products/side.jpg', caption: 'Side' },
  ],
})

The SDK is a thin client over the same REST API, so everything above also works with any HTTP client. More details on the Node.js SDK page.

Public URL or base64: how to decide

For single-file sends, the file field accepts two formats, and each has its place. In albums, items always go by URL.

  • Public URL: the file lives in storage or on a CDN and you pass the link. The request stays light, the same file serves many recipients and you are not pushing megabytes on every call. The link must respond without a login and without redirecting to an authentication page.
  • Base64: the content goes inside the JSON. It makes sense for files generated on the fly, like a receipt built by your system, or when the document holds sensitive data and you do not want it behind an accessible link. The cost is a larger payload.

If you go with a URL for sensitive data, use signed links with a short expiry. The API only needs to fetch the file at the moment of sending.

Receiving and downloading media customers send

When a customer sends a photo, audio or document, the messages.received event reaches your webhook with type set to image, audio, video, document or sticker. The media_url field usually already carries a link to the stored file, and media_data carries type, size, caption, duration and, for audio, whether it is a voice note.

If you need the content as base64 (to send to OCR or a transcription model, for example) or the link came back empty, use the download endpoint. WhatsApp delivers media encrypted, and the endpoint decrypts it using the metadata that came with the event:

curl -X POST https://api.d-api.cloud/api/v1/media/download \
  -H "Authorization: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "sessionId": "billing",
    "direct_path": "<from the webhook>",
    "media_key": "<from the webhook>",
    "mimetype": "image/jpeg",
    "base64": true
  }'

Without base64: true, the file is saved to storage and the response returns media_url. For large files, the async parameter runs the download in the background. If you want to keep everything in your own bucket, you can use the native S3 or MinIO integration.

Common mistakes when sending media

  • A link that requires login or expires too fast: the send fails or arrives empty. Test the URL in a private browser window.
  • Audio without ptt when it should feel like a voice note: the customer gets a file, not a message.
  • Sending the same heavy media in bulk to lots of people: besides the bandwidth cost, unusual sending volume is one of the signals that lead to bans. Read how to avoid bans before automating campaigns.
  • Processing media before answering the webhook: download and handle the file in a worker, after returning 200.

If you want to send media from triggers in your system without writing code, see the WhatsApp API for automation. To combine media with clickable options, continue to buttons and lists.

Frequently asked questions

Can I send a PDF through the WhatsApp API?
Yes. Use the document endpoint and pass the file as a public URL or base64. Set fileName so the customer sees a readable name, like invoice-march.pdf, and mimetype when the type is not obvious from the extension.
How do I make audio arrive as a recorded voice note?
Send it with ptt set to true. Without that field, the file shows up as an attached audio file with a file player. With ptt, it shows up as a voice bubble, just like audio recorded on the spot.
Is it better to send media by URL or as base64?
A public URL is usually the best path: the request body stays small and the same file can serve many sends. Base64 makes sense when the file is generated on the fly and should not be exposed through a link.
How do I receive the photos and audio customers send me?
They arrive on the incoming message webhook with the media type and, usually, a ready-to-use link in media_url. When you need the file as base64 or the link is empty, use the media download endpoint with the metadata from the event.
Can I send several photos in a single message?
Yes, with the album endpoint. You pass a list of images and videos by URL, each with an optional caption, and WhatsApp shows them grouped, just like when someone picks several photos from their gallery.

Try D-API's WhatsApp API

3-day trial with full access. No credit card, no lock-in.