API Cloud (MEDIA)
The media API lets you download, upload and delete WhatsApp multimedia files. All routes share the base https://channels.chattigo.com/bsp-cloud-chattigo-isv and the Authorization: <JWT> authentication header (the raw JWT, with no Bearer or Basic prefix), obtained from POST /login.
{version} is client-chosen and forwarded to Meta as-is: Meta manages the Graph API version lifecycle, so it must never be pinned.
This page documents the current media routes, GET /{version}/{id}/{did}/media for download and POST /{version}/{did}/uploads for upload. The corrected shape has its own page: Media v2.
How it connects to the rest of the API
Downloading the media of an inbound message
- Request the token with
POST /loginand send it in theAuthorizationheader on every call. - Your webhook receives the inbound message payload. Two pieces of data the route needs come from it: the channel, in
metadata.display_phone_number, and the media identifier, inmessages[].audio.id. - Download the file with
GET /{version}/{id}/{did}/mediaand save it with the extension that matches the responseContent-Type.
curl --request POST \
--url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/login' \
--header 'Content-Type: application/json' \
--data '{"username": "<user>", "password": "<password>"}'curl --fail --request GET \
--url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/{version}/980301304349102/5492646715777/media' \
--header 'Authorization: <JWT>' \
--output audio.oggIf you want to release that media at Meta, you delete it with DELETE /{version}/{did}/media/{media_id}.
Uploading a file and using it in a template
- Request the token with
POST /login. - Upload the file with
POST /{version}/{did}/uploads, multipart with thefilepart. - The response is
{"h": "4::..."}. That value is theheader_handleof the media header when you create or edit a template, as explained in Templates.
curl --request POST \
--url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/{version}/{did}/uploads' \
--header 'Authorization: <JWT>' \
-F 'file=@/path/file.jpg'To send media inside a message you use a public URL in link, not the handle: see Messages.
Download media
GET /{version}/{id}/{did}/media
Downloads the binary body of a WhatsApp media file. It forwards Meta’s headers as they come, so the Content-Type, the Content-Length and, when Meta sends one, the Content-Disposition, are whatever Meta returns.
Parameters
Path
| Parameter | Type | Required | Description |
|---|---|---|---|
version | String | Yes | Meta’s Graph API version. Forwarded as-is. |
id | String | Yes | Media ID. |
did | String | Yes | Channel identifier. |
{id} first and {did} second. Reversing them is the most common integration mistake: the download fails even when both identifiers exist.Identifiers in the webhook
| Value | Origin in the inbound payload |
|---|---|
id | entry[].changes[].value.messages[].audio.id (same for image.id, document.id, video.id and sticker.id). |
did | entry[].changes[].value.metadata.display_phone_number, the same value the documentation calls waId in PATCH /webhooks/inbound. |
The channel identifier this API uses is the phone number, not Meta’s phone_number_id.
Request
GET /{version}/{id}/{did}/media
curl --fail --request GET \
--url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/{version}/{id}/{did}/media' \
--header 'Authorization: <JWT>' \
--output audio.oggThe --output audio.ogg in the example is the name you save it with, not something you need to know in advance; the extension can be derived from the response Content-Type. --fail prevents an error body from being saved as if it were the media. If you prefer curl to use the name the response suggests, replace --output audio.ogg with --remote-header-name --remote-name.
For example, this inbound webhook shows the fields this route uses for the audio message:
{
"object": "whatsapp_business_account",
"entry": [
{
"id": "102290129340398",
"changes": [
{
"field": "messages",
"value": {
"messaging_product": "whatsapp",
"metadata": {
"display_phone_number": "5492646715777",
"phone_number_id": "106540352242922"
},
"messages": [
{
"from": "5491122334455",
"id": "wamid.HBgNNTQ5MjY0NjcxNTc3NxUCABIYFj",
"timestamp": "1758552655",
"type": "audio",
"audio": {
"id": "980301304349102",
"mime_type": "audio/ogg; codecs=opus"
}
}
]
}
}
]
}
]
}the download uses id = 980301304349102 and did = 5492646715777:
curl --fail --request GET \
--url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/{version}/980301304349102/5492646715777/media' \
--header 'Authorization: <JWT>' \
--output audio.oggResponse
Success (200)
Returns the binary media body with the headers Meta sends, forwarded as they come: Content-Type, Content-Length and, when Meta sends one, Content-Disposition.
Errors
| Code | Case |
|---|---|
401 | Invalid token or insufficient permissions. |
| Meta | Meta’s errors are forwarded as-is, with its status code and body. For a media that does not exist, expired or is not accessible, Meta answers 404 with Unsupported get request. Object with ID '<id>' does not exist, cannot be loaded due to missing permissions, or does not support this operation.... |
404 with the plain-text body 404 page not found does not come from Meta: it means the URL does not match any registered route and no handler processed the request. Check that the route is /{version}/{id}/{did}/media, with {id} first and {did} second.Upload media
POST /{version}/{did}/uploads
Uploads a file to Meta using the resumable upload flow. The result is the file handle used as the header_handle of a media header in a template, as explained in Templates.
Parameters
Path
| Parameter | Type | Required | Description |
|---|---|---|---|
version | String | Yes | Meta’s Graph API version. Forwarded as-is. |
did | String | Yes | Channel identifier. |
Body (multipart/form-data)
| Field | Type | Required | Description |
|---|---|---|---|
file | File | Yes | File to upload. |
Request
POST /{version}/{did}/uploads
curl --request POST \
--url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/{version}/{did}/uploads' \
--header 'Authorization: <JWT>' \
-F 'file=@/path/file.jpg'Response
Success (200)
{
"h": "4::aW1hZ2............."
}Errors
| Code | Case |
|---|---|
400 | The file part is missing from the multipart form: {"message":"file require"}. |
401 | Invalid token or insufficient permissions. |
| Meta | Meta’s errors are forwarded as-is, with its status code and body. |
Delete media
DELETE /{version}/{did}/media/{media_id}
Deletes a media asset at Meta.
Parameters
Path
| Parameter | Type | Required | Description |
|---|---|---|---|
version | String | Yes | Meta’s Graph API version. Forwarded as-is. |
did | String | Yes | Channel identifier. |
media_id | String | Yes | ID of the media to delete. |
Request
DELETE /{version}/{did}/media/{media_id}
curl --request DELETE \
--url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/{version}/{did}/media/{media_id}' \
--header 'Authorization: <JWT>'Response
Success (200)
{
"success": true
}Errors
| Code | Case |
|---|---|
401 | Invalid token or insufficient permissions. |
| Meta | Meta’s errors are forwarded as-is, with its status code and body. |