Volver al blog
Desarrolladores

Cómo enviar fotos, PDF y audios por la API de WhatsApp

Para mandar una foto, un PDF o un audio por la API de Waspy: el POST real, los topes de Meta y cómo bajar el archivo que te mandó el cliente. Sin un endpoint de subida inventado.

· 12 min
Cómo enviar fotos, PDF y audios por la API de WhatsApp

Respuesta corta: para mandar una foto, un PDF o un audio por la API de Waspy hacés POST https://api.waspytech.com/api/v2/messages con type en image, document, audio o video, y un link https público o un id de media de Meta. No existe POST /api/v2/media para subir el archivo: GET /api/v2/media/:id solo baja algo que ya está guardado. Si la ventana de 24 horas está cerrada, ese pedido responde 403 SERVICE_WINDOW_EXPIRED y hay que usar una plantilla.

Sirve para el caso de todos los días en una tienda argentina: el cliente te manda la foto de la transferencia, o vos le tenés que pasar el PDF del remito mientras el chat sigue abierto. La referencia está en docs.waspytech.com. Los límites de tamaño son los de la Cloud API de Meta.

Qué tipo manda qué

La autenticación es Authorization: Bearer wspy_... y el scope del envío es messages:write. El phoneNumberId es el UUID de GET /api/v2/channels, no el id de teléfono de Meta. El detalle de la clave, los errores 401 y la idempotencia está en API de WhatsApp para desarrolladores.

typeCamposTope al bajar el linkNotas
imagelink o id, caption opcional5 MBJPEG o PNG. Waspy normaliza fotos que Meta rechaza (PNG de 16 bits, WebP) antes de subirlas
documentlink o id, caption y filename opcionales100 MBPDF, texto, Word, Excel, PowerPoint
audiolink o id16 MBNo lleva caption. AAC, MP3, M4A, AMR, OGG
videolink o id, caption opcional16 MBMP4 o 3GPP
El id de esos objetos es un media id de Meta (el que devuelve Graph al subir un archivo), no el UUID de Waspy. Si mandás el UUID de GET /media/:id en image.id, Meta no lo reconoce.

Mandar la foto de un producto

Dentro de la ventana (el cliente escribió hace menos de 24 horas) el cuerpo es este. El header Idempotency-Key evita un segundo envío si el script se corta: la respuesta queda guardada 24 horas.

curl -sS https://api.waspytech.com/api/v2/messages \
  -H "Authorization: Bearer $WASPY_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: pedido-1847-foto" \
  -d '{
    "phoneNumberId": "UUID-DEL-CANAL",
    "to": "+5491155554444",
    "type": "image",
    "image": {
      "link": "https://cdn.mitienda.com.ar/vestido-azul.jpg",
      "caption": "Vestido azul, talle M. Te queda este."
    },
    "clientRef": "pedido-1847"
  }'

Un 201 devuelve el mensaje en data (id, status, conversationId). El teléfono va en E.164: para un celular argentino, +549 más el código de área sin 0 y el número sin el 15.

El PDF del remito es el mismo pedido con type: "document" y document.filename (por ejemplo remito-1847.pdf). Sin id ni link, Meta responde 132018 (Either one of media ID or link must be present).

La ventana sigue mandando

Una foto o un PDF no son una plantilla. Si serviceWindowExpiresAt ya pasó, o la conversación es nueva y ese campo está vacío, la API responde 403 SERVICE_WINDOW_EXPIRED y no encola nada. Lo consultás con GET /api/v2/conversations/:id (scope conversations:read): el campo viene en la conversación.

No hace falta crear el contacto antes. El envío lo crea si no existe, pero no abre la ventana. Para escribirle a alguien que no te escribió, la vía es una plantilla aprobada, explicada en la regla de las 24 horas. Una plantilla con imagen en el encabezado se arma en el panel: la API REST no tiene POST /templates.

El pedido se acepta enseguida y el envío corre en un worker. Con un link:

  1. Tiene que ser https. http, localhost, un host interno o una IP privada no se bajan.
  2. Waspy sigue hasta 5 redirects, con un tope de 60 segundos, y corta si el archivo pasa el tamaño de la tabla.
  3. Si la bajada sale bien, sube el archivo a Meta y manda el mensaje por id. La foto pasa por un normalizador para no morir con el error 131053 de Meta (el mismo que aparece cuando Meta no puede usar el archivo).
  4. Si la bajada o la subida fallan, el plan B es pasarle a Meta el link original. Si Meta tampoco puede bajarlo, el mensaje queda failed.

Un id de Meta se reenvía tal cual, sin bajar nada. El link de la API pública no es el mediaKey del panel: ese campo lo usa la bandeja cuando el archivo ya está en el almacenamiento de Waspy, y no hace falta mandarlo vos.

Bajar la foto o el audio que mandó el cliente

Cuando entra un mensaje, el webhook message.received trae el mensaje. Si es una foto, un audio o un documento, mediaId es el UUID para bajarlo. La descarga desde Meta es asíncrona: en el primer aviso mediaId puede venir vacío. En ese caso releé GET /api/v2/messages/:id (scope messages:read) y, cuando aparezca, pedí la URL:

curl -sS "https://api.waspytech.com/api/v2/media/UUID-DEL-MEDIA" \
  -H "Authorization: Bearer $WASPY_API_KEY"

Hace falta el scope media:read. La respuesta trae url (firmada), expiresIn, mimeType y fileName. El vencimiento por defecto es 900 segundos (15 minutos): cuando vence, pedís otra. Un id de otro tenant responde 404 MEDIA_NOT_FOUND.

GET /api/v2/media/by-key?key= es el camino viejo, cuando el mensaje solo trae mediaKey. La clave tiene que empezar con el id de tu cuenta; si no, también es 404.

En un audio, transcriptionStatus suele llegar pending en el webhook. Unos segundos después, GET /messages/:id trae transcription cuando el estado pasa a completed. Eso es el texto del audio para tu sistema. No es una respuesta automática al cliente: Waspy no le contesta solo.

El alta del webhook, la firma y los reintentos están en webhooks de WhatsApp API.

Cuánto cobra Meta por ese archivo

La foto dentro de la ventana es un mensaje de servicio, igual que un texto. Desde el 1 de octubre de 2026 cada número tiene 1.000 gratis por mes; desde el 1.001, en Argentina, alrededor de ARS 37,68 (~US$0,026) por mensaje entregado. Un PDF fuera de la ventana no se puede mandar como archivo suelto: va en una plantilla, y si es un aviso de pedido (sin promo) es utilidad, al mismo precio. El desglose está en cuánto cuesta la API y en la rate card de Meta.

Waspy no suma un cargo encima del archivo. Meta le factura los mensajes al negocio. La API está en los planes Scale (US$150/mes) y Enterprise; la suscripción va aparte, en Planes.

Waspy, la Cloud API directa y un BSP de acceso

CaminoCómo mandás el archivoQué más tenés que armar
Cloud API de Meta, directaSubís el binario a /{phone-number-id}/media y después mandás el idToken, webhooks de Meta, ventana, reintentos
Twilio o 360dialogLa API de ese proveedorEl inbox, si lo querés
Z-APIUna sesión tipo WhatsApp WebNo es la API oficial
API de Waspylink https o id de Meta en POST /api/v2/messagesNada más para que el equipo lo vea en la bandeja
El alta del número sigue siendo el registro embebido de Meta. Si todavía no lo tenés, los requisitos están en cómo obtener la API de WhatsApp.

En resumen

  • Enviá con POST /api/v2/messages y un link https o un id de Meta. No hay upload en /api/v2.
  • Foto 5 MB, audio y video 16 MB, documento 100 MB.
  • Fuera de las 24 horas, 403 SERVICE_WINDOW_EXPIRED.
  • Lo que manda el cliente se baja con GET /api/v2/media/:id (URL firmada, 15 minutos).

Si el número de la tienda ya está en la API, la clave se crea en Configuración → Claves de API con el plan Scale. Si todavía no, abrí la cuenta: 10 días gratis, sin tarjeta.

Tu equipo atendiendo por WhatsApp en minutos

CRM facil pero potente. En 10 minutos tenes a tu equipo trabajando — no necesitas hablar con nadie.