Saltar al contenido

API Cloud (MEDIA v2)

Estas rutas son la forma corregida: el canal primero y el identificador de la media al final, como en el resto de la API del canal. Las anteriores siguen funcionando sin cambios, documentadas en la página Media.

Además del orden, esta forma corrige dos cosas:

  • Descarga: la respuesta siempre informa el tipo de contenido, el tamaño real del archivo y un nombre de archivo, y no reenvía los headers que solo valen entre Meta y el proxy. La ruta anterior reenvía los headers de Meta tal como vienen, incluido el tamaño que declare Meta.
  • Subida: el tipo de archivo que se envía a Meta es el que declara el part file cuando Meta lo acepta, y se infiere del contenido cuando no. La ruta anterior siempre lo infiere del contenido, y eso etiqueta mal varios de los formatos que Meta acepta.

Todas las rutas comparten la base https://channels.chattigo.com/bsp-cloud-chattigo-isv y el header de autenticación Authorization: <JWT> (el JWT en crudo, sin prefijo Bearer ni Basic), obtenido en POST /login.

{version} lo elige el cliente y se reenvía a Meta tal cual: la versión de Graph API la gestiona Meta, por lo que no debe fijarse.

Cómo se conecta con el resto de la API

Descargar la media de un mensaje entrante

  1. Pedí el token con POST /login y mandalo en el header Authorization de todas las llamadas.
  2. Tu webhook recibe el payload del mensaje entrante. De ahí salen los dos datos que necesita la ruta: el canal, en metadata.display_phone_number, y el identificador de la media, en messages[].audio.id.
  3. Descargá el archivo con GET /{version}/{did}/media/{media_id} y guardalo con la extensión que corresponde al Content-Type de la respuesta.
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}/5492646715777/media/980301304349102' \
  --header 'Authorization: <JWT>' \
  --output audio.ogg

Si querés liberar esa media en Meta, la eliminás con DELETE /{version}/{did}/media/{media_id}.

Subir un archivo y usarlo en una plantilla

  1. Pedí el token con POST /login.
  2. Subí el archivo con POST /{version}/{did}/media, multipart con el part file.
  3. La respuesta es {"h": "4::..."}. Ese valor es el header_handle del header de media cuando creás o editás una plantilla, como se explica en Templates.
curl --request POST \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/{version}/{did}/media' \
  --header 'Authorization: <JWT>' \
  -F 'file=@/ruta/archivo.jpg'

Para enviar una media dentro de un mensaje se usa una URL pública en link, no el handle: consultá Messages.

Descargar media

GET /{version}/{did}/media/{media_id}

Descarga el cuerpo binario de una media de WhatsApp con el canal primero y el identificador de la media al final. Devuelve el Content-Type de la media, el tamaño real del cuerpo y un nombre de archivo sugerido.

Parámetros

Path

ParámetroTipoRequeridoDescripción
versionStringSíVersión de Graph API de Meta. Se reenvía tal cual.
didStringSíIdentificador del canal.
media_idStringSíIdentificador de la media.

Identificadores en el webhook

ValorOrigen en el payload inbound
media_identry[].changes[].value.messages[].audio.id (igual para image.id, document.id, video.id y sticker.id).
didentry[].changes[].value.metadata.display_phone_number, el mismo valor que la documentación llama waId en PATCH /webhooks/inbound.

El identificador de canal que usa esta API es el número de teléfono, no el phone_number_id de Meta.

En esta forma el canal va primero y el identificador de la media al final: /{version}/{did}/media/{media_id}. Es el mismo orden que la ruta de eliminación y que el resto de la API del canal.

Request

GET /{version}/{did}/media/{media_id}

curl --fail --request GET \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/{version}/{did}/media/{media_id}' \
  --header 'Authorization: <JWT>' \
  --output audio.ogg

El --output audio.ogg del ejemplo es el nombre con el que guardás vos, no un dato que debas conocer de antemano; la extensión puede derivarse del Content-Type de la respuesta. --fail evita que un cuerpo de error se guarde como si fuera la media. Si preferís que curl use el nombre que sugiere la respuesta, reemplazá --output audio.ogg por --remote-header-name --remote-name.

Por ejemplo, este webhook inbound muestra los campos que usa esta ruta para el mensaje de audio:

{
  "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"
                }
              }
            ]
          }
        }
      ]
    }
  ]
}

la descarga se realiza con did = 5492646715777 y media_id = 980301304349102:

curl --fail --request GET \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/{version}/5492646715777/media/980301304349102' \
  --header 'Authorization: <JWT>' \
  --output audio.ogg

Response

Éxito (200)

Devuelve el cuerpo binario de la media con los headers:

HeaderDescripción
Content-TypeTipo de la media que reporta Meta para el archivo.
Content-LengthTamaño real del cuerpo de la respuesta.
Content-Dispositioninline; filename="<media_id>.<ext>", donde la extensión se deriva del tipo servido.

Ejemplos de extensión según el tipo servido:

Tipo servidoExtensión
audio/ogg.ogg
audio/amr.amr
audio/mpeg.mp3
audio/mp4.m4a
video/mp4.mp4
image/jpeg.jpg
application/pdf.pdf

Content-Disposition es un header de respuesta: no se envía y no hace falta conocerlo de antemano, porque la URL solo necesita el identificador de la media. Está para que un cliente que quiera guardar el archivo con el nombre sugerido lo use; si preferís elegir el nombre vos mismo, ignoralo y quedate con el Content-Type, que es el dato esencial.

Errores

CódigoCaso
401Token inválido o con permisos insuficientes.
MetaLos errores de Meta se reenvían tal cual, con su código de estado y su cuerpo. Para una media que no existe, expiró o no es accesible, Meta responde 404 con Unsupported get request. Object with ID '<media_id>' does not exist, cannot be loaded due to missing permissions, or does not support this operation....
Un 404 con el cuerpo en texto plano 404 page not found no proviene de Meta: significa que la URL no coincide con ninguna ruta registrada y ningún handler procesó la petición. Verifica que la forma de la ruta sea /{version}/{did}/media/{media_id}.

Subir media

POST /{version}/{did}/media

Sube un archivo a Meta con el canal primero. El tipo de archivo que se envía a Meta es el que declara el part file del multipart cuando Meta lo acepta, y se infiere del contenido en caso contrario. El resultado es el file handle que se usa como header_handle en el header de media de una plantilla, como se explica en Templates.

Parámetros

Path

ParámetroTipoRequeridoDescripción
versionStringSíVersión de Graph API de Meta. Se reenvía tal cual.
didStringSíIdentificador del canal.

Body (multipart/form-data)

CampoTipoRequeridoDescripción
fileFileSíArchivo a subir.

Request

POST /{version}/{did}/media

curl --request POST \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/{version}/{did}/media' \
  --header 'Authorization: <JWT>' \
  -F 'file=@/ruta/archivo.jpg'

Response

Éxito (200)

{
  "h": "4::aW1hZ2............."
}

Tipos aceptados por Meta

GrupoTipos
Audioaudio/aac, audio/amr, audio/mpeg, audio/mp4, audio/ogg
Imágenesimage/jpeg, image/png
Stickersimage/webp
Videosvideo/mp4, video/3gpp
Documentostext/plain, application/pdf, application/msword, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/vnd.openxmlformats-officedocument.wordprocessingml.document, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.openxmlformats-officedocument.presentationml.presentation

Errores

CódigoCaso
400Falta el part file en el formulario multipart: {"message":"file require"}.
401Token inválido o con permisos insuficientes.
MetaLos errores de Meta se reenvían tal cual, con su código de estado y su cuerpo.

Eliminar media

La eliminación ya usa el canal primero: DELETE /{version}/{did}/media/{media_id}, documentada en la página Media.