Upload and download WhatsApp media
Upload bytes to Meta with POST /v2/media/upload (max 100 MB) to get a mediaId, then send it in messages or templates. Download with GET /v2/media/:mediaId/download.
Base: /v2/media
Auth + Premium/Enterprise + active plan required. See HTTP API v2 Overview.
The upload path is POST /v2/media/upload, not POST /v2/media.
Prerequisites
- An API token and Premium/Enterprise plan (Authentication)
- A
phoneNumberIdfrom GET /v2/me (required on upload) - A file within WhatsApp’s 100 MB ceiling
Step-by-step
Authenticate
SendAuthorization: Bearer YOUR_TOKENorX-API-Token: YOUR_TOKEN.Upload with POST /v2/media/upload
Multipart: form fieldsfileandphoneNumberId. Raw body: file bytes plusX-Phone-Number-Id(orphoneNumberIdheader). Max 100 MB. Success returns{ "success": true, "data": { "mediaId": "..." } }.Use mediaId on send
Pass the id in message media or a template header (image/video/document).Download when you have a Meta media ID
GET /v2/media/:mediaId/downloadreturns a binary stream on success. OptionalphoneNumberIdoraccountIdselects the WABA token. Missing URL returns JSON404 NOT_FOUND. Graph/upload failures returnVALIDATION_ERRORwith Meta’s payload indetailswhen available.
POST /v2/media/upload
Uploads bytes to Meta POST /{phone-number-id}/media and returns a mediaId for use with send media and templates.
Limits: maximum 100 MB per request (WhatsApp ceiling).
Phone number: phoneNumberId must belong to your account (same rules as message sends).
Mode A — multipart/form-data
| Field | Required | Description |
|---|---|---|
file | yes | File part |
phoneNumberId | yes | Meta phone number ID |
type | no | MIME hint if the part has a generic type |
Example (curl):
bash
curl -sS -X POST "https://api.avenping.com/v2/media/upload" \
-H "Authorization: Bearer YOUR_TOKEN" \
-F "phoneNumberId=YOUR_META_PHONE_NUMBER_ID" \
-F "file=@/path/to/photo.jpg;type=image/jpeg"Response 200:
json
{
"success": true,
"data": {
"mediaId": "1234567890"
}
}Mode B — raw body (buffer / stream)
Same pattern as the main AvenPing app upload route: the body is the raw file bytes.
| Header | Required | Description |
|---|---|---|
Content-Type | recommended | File MIME type (e.g. image/jpeg) |
X-Phone-Number-Id | yes | Meta phone number ID (also accepts phoneNumberId header) |
X-Filename | no | Original filename (default file) |
X-Upload-Type | no | Optional MIME override |
Example (curl):
bash
curl -sS -X POST "https://api.avenping.com/v2/media/upload" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Phone-Number-Id: YOUR_META_PHONE_NUMBER_ID" \
-H "X-Filename: photo.jpg" \
-H "Content-Type: image/jpeg" \
--data-binary "@/path/to/photo.jpg"Response 200: same as multipart.
Meta / validation errors
Failures from Meta are returned as JSON with success: false, HTTP status aligned when possible (e.g. 400), message from Meta, and the raw Graph payload in details when available (same style as other proxied Graph calls).
GET /v2/media/:mediaId/download
Path: mediaId — Meta media ID.
Query (optional):
| Name | Description |
|---|---|
disposition | inline (default) or attachment |
phoneNumberId | Meta phone number ID — use that line’s WABA token |
accountId | AvenPing WABA id from GET /v2/me |
Without a WABA selector, the API tries the default account token, then other linked accounts, until Meta returns the media URL.
Success: binary stream, not JSON.
Example request (save to file):
bash
curl -sS -L "https://api.avenping.com/v2/media/MEDIA_ID_FROM_META/download?disposition=attachment" \
-H "Authorization: Bearer YOUR_TOKEN" \
-o "download.bin"Response 200 (headers — body is raw bytes):
| Header | Example value |
|---|---|
Content-Type | image/jpeg (from Meta) |
Content-Length | 48291 |
Content-Disposition | attachment or inline |
Response 404 (JSON):
json
{
"success": false,
"error": "NOT_FOUND",
"message": "Media URL not found"
}FAQ
How do I get a mediaId for sending?
POST /v2/media/upload (multipart file + phoneNumberId, or raw body with X-Phone-Number-Id). The JSON response includes data.mediaId. There is no POST /v2/media route.
Is download JSON or binary?
Success is a binary stream (not JSON). Failures such as missing media URL return JSON (404 NOT_FOUND). A download proxy failure can return 502 INTERNAL_ERROR (Failed to download media).
How do I choose which WABA downloads the file?
Pass optional query phoneNumberId or accountId. Without a selector, the API tries the default account token, then other linked accounts, until Meta returns the media URL.