Skip to content

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

  1. Request the token with POST /login and send it in the Authorization header on every call.
  2. 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, in messages[].audio.id.
  3. Download the file with GET /{version}/{id}/{did}/media and save it with the extension that matches the response Content-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.ogg

If 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

  1. Request the token with POST /login.
  2. Upload the file with POST /{version}/{did}/uploads, multipart with the file part.
  3. The response is {"h": "4::..."}. That value is the header_handle of 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

ParameterTypeRequiredDescription
versionStringYesMeta’s Graph API version. Forwarded as-is.
idStringYesMedia ID.
didStringYesChannel identifier.
The argument order is {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

ValueOrigin in the inbound payload
identry[].changes[].value.messages[].audio.id (same for image.id, document.id, video.id and sticker.id).
didentry[].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.ogg

The --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.ogg

Response

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

CodeCase
401Invalid token or insufficient permissions.
MetaMeta’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....
A 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

ParameterTypeRequiredDescription
versionStringYesMeta’s Graph API version. Forwarded as-is.
didStringYesChannel identifier.

Body (multipart/form-data)

FieldTypeRequiredDescription
fileFileYesFile 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

CodeCase
400The file part is missing from the multipart form: {"message":"file require"}.
401Invalid token or insufficient permissions.
MetaMeta’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

ParameterTypeRequiredDescription
versionStringYesMeta’s Graph API version. Forwarded as-is.
didStringYesChannel identifier.
media_idStringYesID 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

CodeCase
401Invalid token or insufficient permissions.
MetaMeta’s errors are forwarded as-is, with its status code and body.