waiaconnect

Documentación / Esencial

Enviar media (imagen · documento · audio · video)

POST /v1/messages

Markdown

Connect no almacena archivos. Para mandar un archivo tuyo, hospedalo y mandá su enlace (link) — lo descarga Meta, no nosotros. Ese es el camino principal, no la alternativa.

Los identificadores (id) son los de archivos que RECIBISTE: llegan dentro del evento de un mensaje entrante (data.message.image.id, .document.id, …). No hay endpoint de subida — GET /v1/media/:mediaId es sólo de descarga —, así que no existe forma de obtener un id para un archivo tuyo.

⚠ Y la parte incómoda, dicha como es: Meta suele permitir reusar un identificador entrante para responder desde el mismo número, pero no lo garantiza y nosotros todavía no lo verificamos contra Meta real. No lo afirmamos ni lo negamos. Si te importa que salga siempre, usá el enlace.

¿Querés mandar SIEMPRE el mismo archivo — una lista de precios, un instructivo, un catálogo? Hospedalo y mandá el enlace. Es la respuesta completa: no hay un id propio que guardar y reusar. Y no es una limitación disimulada — no guardamos archivos porque no guardamos contenido (tampoco el texto de tus mensajes). Es exactamente lo que promete nuestra política de privacidad, aplicado acá.

Cómo se manda. POST /v1/messages con type image/document/audio/video y, dentro del objeto de ese tipo, link o id — exactamente uno de los dos. caption para image/document/video; audio no acepta caption; document puede llevar filename (el nombre que ve quien lo recibe).

Qué necesita el enlace para que Meta lo acepte: ser https y apuntar directo al archivo (que la respuesta sean los bytes, sin login ni página intermedia); traer el Content-Type correcto — si no coincide con el archivo, Meta lo rechaza; y respetar los límites de Meta: imagen JPEG/PNG 5 MB, audio (aac · amr · mp3 · m4a · ogg sólo OPUS) 16 MB, video mp4/3gpp 16 MB, documento (pdf · doc/docx · xls/xlsx · ppt/pptx · txt) 100 MB.

⚠ La trampa más común: Google Drive, Dropbox y similares NO sirven. Un enlace de "compartir" devuelve una página HTML intermedia, no los bytes del archivo: Meta descarga esa página y rechaza el envío. Servilo desde una URL que responda el archivo directo.

curl -X POST https://api.waiaconnect.com/v1/messages \
  -H "Authorization: Bearer wc_live_YOUR_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"connectionId":"conn_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX","to":"5493511234567","type":"image","image":{"link":"https://example.com/product.jpg","caption":"New product 📦"}}'
# document: {"type":"document","document":{"link":"https://…/invoice.pdf","filename":"invoice.pdf","caption":"Your invoice"}}
# audio (no caption): {"type":"audio","audio":{"link":"https://…/note.ogg"}}
# video: {"type":"video","video":{"link":"https://…/demo.mp4","caption":"Demo"}}
# by media id instead of a link: {"image":{"id":"1234567890"}}
# ...but the only ids that exist are the ones you RECEIVED (from a message.received
# event); there is no upload endpoint. To send a file of your own, host it and link it.
// Media is sent by { link } (Meta fetches the URL) or { id }. The only media ids that
// exist are the ones you RECEIVED: there is no upload endpoint. Host your own files.
const res = await fetch("https://api.waiaconnect.com/v1/messages", {
  method: "POST",
  headers: {
    "Authorization": "Bearer wc_live_YOUR_API_KEY",
    "Idempotency-Key": crypto.randomUUID(),
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
  "connectionId": "conn_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "to": "5493511234567",
  "type": "image",
  "image": {
    "link": "https://example.com/product.jpg",
    "caption": "New product 📦"
  }
})
});
console.log(await res.json()); // { id: "msg_…", status: "queued" }
<?php
// Media is sent by ["link" => …] (Meta fetches it) or ["id" => …]. The only media ids
// that exist are the ones you RECEIVED: there is no upload endpoint. Host your own files.
$ch = curl_init("https://api.waiaconnect.com/v1/messages");
curl_setopt_array($ch, [
  CURLOPT_POST => true,
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    "Authorization: Bearer wc_live_YOUR_API_KEY",
    "Idempotency-Key: " . bin2hex(random_bytes(16)),
    "Content-Type: application/json",
  ],
  CURLOPT_POSTFIELDS => json_encode(["connectionId" => "conn_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX","to" => "5493511234567","type" => "image","image" => ["link" => "https://example.com/product.jpg","caption" => "New product 📦"]]),
]);
echo curl_exec($ch);
import requests, uuid
# Media is sent by {"link": …} (Meta fetches it) or {"id": …}. The only media ids that
# exist are the ones you RECEIVED: there is no upload endpoint. Host your own files.
res = requests.post("https://api.waiaconnect.com/v1/messages",
  headers={
    "Authorization": "Bearer wc_live_YOUR_API_KEY",
    "Idempotency-Key": str(uuid.uuid4()),
  },
  json={"connectionId":"conn_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX","to":"5493511234567","type":"image","image":{"link":"https://example.com/product.jpg","caption":"New product 📦"}})
print(res.json())  # {"id": "msg_…", "status": "queued"}

⚠ Un identificador que llega en un webhook vence a los 7 días (los que devuelve la API de subida de Meta duran 30). Vencido no sirve ni para descargarlo ni para reenviarlo.

Meta cachea tu enlace 10 minutos. Si cambiás el archivo detrás de la MISMA URL, agregale un query string al azar (?v=…) o vas a mandar el viejo.

Si el enlace no sirve, te enterás en dos momentos. (1) Al aceptar, con un 400 y su code: MEDIA_LINK_OR_ID_REQUIRED (no mandaste ninguno), MEDIA_LINK_AND_ID (mandaste los dos), MEDIA_LINK_INVALID (no es una URL https bien formada), AUDIO_CAPTION_NOT_ALLOWED.

(2) Si pasó la validación pero Meta no pudo bajarlo, el rechazo aterriza DESPUÉS del 202: consultá GET /v1/messages/:id → lastErrorCode = MEDIA_DOWNLOAD_FAILED (enlace inaccesible o página intermedia), MEDIA_FILE_REJECTED (formato o tamaño) o MEDIA_TYPE_UNSUPPORTED. Qué hacer: servir el archivo directo, con su Content-Type, dentro de los límites de arriba.

Para descargar un archivo que te mandaron a vos, ver «Descargar media entrante».