22 KiB
WhatsApp Business Platform (Cloud API) — Tipos de mensajes, payloads y límites
Investigación sobre la documentación oficial de Meta (developers.facebook.com), 2026-09-26. Nota: Meta migró la doc de
/docs/whatsapp/cloud-api/...a/documentation/business-messaging/whatsapp/.... Los tipos text/media/location/contacts siguen accesibles en las URLs legacy; interactive/templates ya solo viven en la nueva ruta. Los datos citados provienen de las páginas listadas en "Fuentes".
1. Convención común de todos los mensajes
Endpoint: POST https://graph.facebook.com/<API_VERSION>/<PHONE_NUMBER_ID>/messages
con header Authorization: Bearer <TOKEN> y Content-Type: application/json
(Fuente: Message API reference — §Fuentes [17]).
Sobre (envelope) común a todo mensaje (BaseMessageProperties, [17]):
{
"messaging_product": "whatsapp", // requerido, siempre "whatsapp"
"recipient_type": "individual", // "individual" (o "group" para grupos)
"to": "<número del usuario>", // requerido
"type": "<text|image|video|audio|document|sticker|location|contacts|interactive|template|reaction>",
"context": { "message_id": "wamid..." } // opcional: responde a un mensaje previo
}
Respuesta de éxito: contacts[].input, contacts[].wa_id y messages[].id (wamid.HBgL...);
el message_status inicial puede ser accepted (también existen held_for_quality_assessment y paused) [17].
2. Text
Payload [1]:
{
"messaging_product": "whatsapp",
"recipient_type": "individual",
"to": "16505551234",
"type": "text",
"text": {
"preview_url": false,
"body": "Hola mundo"
}
}
| Campo | Descripción | Límite |
|---|---|---|
text.body |
Texto del mensaje (requerido). El cliente hipervincula URLs automáticamente | 4096 caracteres |
text.preview_url |
true = el cliente intenta renderizar preview del enlace |
opcional |
Vista en el teléfono: burbuja de solo texto; con preview_url: true solo el primer URL del body
recibe preview (requiere http:// o https://); si no se puede obtener, queda como enlace clicable [1].
El preview usa el Open Graph de la página: og:title (negrita, máx 2 líneas), og:description
(~80 caracteres), og:url y og:image (thumbnail <600 KB, ≥300 px de ancho) renderizados encima
del texto de la burbuja [22].
Formato de texto (*negrita*, _cursiva_, ~tachado~, ```mono```):
la página oficial actual de text-messages ya no documenta la sintaxis de formateo (verificado [1]);
lo único oficial vigente leído es que el body/footer interactivos "soportan emojis y markdown" [17]
y que el header de plantillas tipo TEXT prohíbe caracteres markdown [20]. La sintaxis con
*asteriscos*, _guiones bajos_, ~tildes~ y triple acento grave es la estándar del cliente
WhatsApp, pero su referencia oficial en el site de developers está retirada: dato NO verificable
contra fuentes oficiales en esta investigación.
3. Media (image, video, audio, document, sticker)
Patrón común: el objeto de media admite id (asset subido vía Media API — recomendado por
performance) o link (URL pública — "no recomendado"); se provee solo uno [2]–[6].
Image [2] — type: "image", objeto image: { id | link, caption }.
Caption máx 1024 caracteres. Formatos: JPEG (image/jpeg) y PNG (image/png),
8-bit RGB/RGBA, máx 5 MB.
Video [3] — type: "video", objeto video: { id | link, caption }.
Caption máx 1024. Solo códecs H.264 (video) + AAC (audio), un solo stream de audio o ninguno;
MP4 (video/mp4) y 3GP (video/3gpp), máx 16 MB. H.264 "High" con B-frames no funciona en
Android; usar Main/Baseline y moov antes de mdat (ffmpeg -movflags faststart).
Audio [4] — type: "audio", objeto audio: { id | link, voice }.
voice: true = mensaje de voz (requiere OGG con codec OPUS, mono; el OGG base no es soportado).
Formatos: AAC, AMR, MP3 (audio/mpeg), M4A (audio/mp4), OGG (audio/ogg); máx 16 MB.
Vista: archivos ≤512 KB muestran icono de play como mensaje de voz; los mayores muestran icono de descarga [4].
Document [5] — type: "document", objeto document: { id | link, caption, filename }.
Caption máx 1024; filename (con extensión) define el icono del tipo de archivo en el cliente.
Tipos soportados (máx 100 MB): TXT, XLS/XLSX, DOC/DOCX, PPT/PPTX, PDF. Otros tipos pueden
enviarse pero no están soportados oficialmente.
Sticker [6] — type: "sticker", objeto sticker: { id | link } (sin caption).
Formato WebP únicamente: animado máx 500 KB, estático máx 100 KB.
Vista: se muestra como sticker (sin texto); error si el WebP no es soportado o excede el tamaño.
Vista general media: la burbuja muestra el recurso y, si aplica, el caption debajo; en document aparece icono por extensión + filename; en image/video el caption va bajo el recurso [2][3][5].
4. Location
Payload [7] — type: "location", objeto location:
| Campo | Requerido | Ejemplo |
|---|---|---|
latitude |
sí | "37.44216251868683" (grados decimales) |
longitude |
sí | "-122.16153582049394" |
name |
no | "Philz Coffee" |
address |
no | "101 Forest Ave, Palo Alto, CA 94301" |
Vista: tarjeta de mapa con las coordenadas; nombre y dirección se muestran como título/detalle. La página no especifica límites de caracteres ni renderizado adicional [7].
5. Contacts
Payload [8] — type: "contacts", array contacts[] de objetos contacto.
Cada mensaje puede incluir hasta 257 contactos (se recomienda menos por usabilidad).
Único campo requerido por contacto: name.formatted_name (es lo que aparece en la burbuja
junto al botón de flecha de perfil). Resto opcionales [8]:
name:formatted_name,first_name,last_name,middle_name,suffix,prefixphones[]:phone,type(CELL/MAIN/IPHONE/HOME/WORK),wa_id— si faltawa_id, el botón Message/Save se sustituye por "Invite to WhatsApp"emails[]:email,type(PERSONAL/WORK)urls[]:url,type(COMPANY/WORK/PERSONAL/FACEBOOK_PAGE/INSTAGRAM)org:company,department,titleaddresses[]:street,city,state,zip,country,country_code(ISO-2),typebirthday: formatoYYYY-MM-DD
Vista: tarjeta de contacto con avatar, nombre formateado y filas por cada dato presente; algunos metadatos (direcciones, cumpleaños) pueden no mostrarse según el dispositivo del usuario [8].
6. Interactive
type: "interactive" + objeto interactive con type de: button, list, cta_url,
product, product_list, catalog_message, carousel, flow (y call_permission_request) [17].
Objetos internos: header (HeaderObject: text/image/video/document; requerido para product_list,
no permitido en product), body (text, requerido — "emojis y markdown soportados"),
footer (text, opcional — "emojis, markdown y links soportados"), action (estructura varía por tipo) [17].
6.1 Botones reply (quick replies) — interactive.type: "button" [10]
{ "type": "interactive",
"interactive": {
"type": "button",
"header": { "type": "text", "text": "Detalles" },
"body": { "text": "¿Confirmas tu cita?" },
"footer": { "text": "Elige una opción" },
"action": { "buttons": [
{ "type": "reply", "reply": { "id": "id_si", "title": "Sí" } },
{ "type": "reply", "reply": { "id": "id_no", "title": "No" } } ] } } }
| Campo | Límite |
|---|---|
| Botones | máx 3 |
reply.title |
20 caracteres, único entre botones |
reply.id |
256 caracteres, único por botón |
body.text |
1024 caracteres (URLs se hipervinculan) |
footer.text |
60 caracteres |
header |
tipos text/image/video/document (límite de header text no declarado en esta página) [10] |
Vista: header arriba (media o texto), body, footer y los botones como filas-blanco fijas bajo la
burbuja. Al tocar, webhook messages con button_reply.id/title + context.id del mensaje original [10].
6.2 Lista — interactive.type: "list" [9]
{ "type": "interactive",
"interactive": {
"type": "list",
"header": { "type": "text", "text": "Menú" },
"body": { "text": "Selecciona un producto" },
"footer": { "text": "Catálogo 2026" },
"action": { "button": "Ver opciones",
"sections": [
{ "title": "Bebidas",
"rows": [ { "id": "r1", "title": "Café", "description": "Chico" } ] } ] } } }
| Campo | Límite |
|---|---|
| Secciones | mín 1, máx 10 |
| Filas (total, sumando secciones) | máx 10 |
action.button (etiqueta que despliega) |
20 caracteres |
header.text |
60 caracteres (solo type text) |
body.text |
4096 caracteres |
footer.text |
60 caracteres |
| Título de sección | 24 caracteres (requerido solo si hay >1 sección, [17]) |
row.title |
24 caracteres |
row.description |
opcional, 72 caracteres |
row.id |
200 caracteres |
Vista: burbuja con header/body/footer y un único botón (action.button) que abre la lista
de opciones seleccionables a pantalla (las filas muestran title y description); el webhook devuelve
list_reply con id, title, description + context [9].
6.3 CTA URL — interactive.type: "cta_url" [11]
"interactive": {
"type": "cta_url",
"header": { "type": "image", "image": { "link": "https://…/promo.jpg" } },
"body": { "text": "Aprovecha la promo" },
"footer": { "text": "Vence hoy" },
"action": { "name": "cta_url",
"parameters": { "display_text": "Abrir tienda", "url": "https://mitienda.com" } } }
Límites: display_text 20 caracteres; body.text 1024; footer.text 60;
header.text 60. Header opcional de tipo image/video/document/text. Un solo botón URL por
acción; la doc menciona etiquetas únicas "si se usan múltiples botones" sin declarar máximo [11].
Vista: media/texto del header, body, footer y un botón azul que abre el navegador con la URL [11].
6.4 Producto único — interactive.type: "product" [15]
"interactive": {
"type": "product",
"body": { "text": "Texto opcional" },
"footer": { "text": "Texto opcional" },
"action": { "catalog_id": "123456789", "product_retailer_id": "SKU-001" } }
action requiere catalog_id + product_retailer_id (SKU del producto); header no permitido
en este tipo [15][17]; body/footer opcionales. Sin límites de caracteres declarados en la página [15].
Vista: tarjeta con imagen/nombre/precio actuales del producto; al tocar se abre una
Product Detail Page (PDP) con los datos en tiempo real (solo imágenes; videos/GIF no se muestran);
hay botón para escribir al negocio; reenviable, no puede enviarse como notificación [15].
6.5 Multi-producto — interactive.type: "product_list" [16]
"interactive": {
"type": "product_list",
"header": { "type": "text", "text": "Nuestra tienda" },
"body": { "text": "Elige productos" },
"footer": { "text": "Envío gratis" },
"action": { "catalog_id": "123456789",
"sections": [ { "title": "Cafés",
"product_items": [ { "product_retailer_id": "SKU-001" } ] } ] } }
Requeridos: header type text, body, action.catalog_id + sections[] (title +
product_items[].product_retailer_id). Límite documentado: hasta 30 productos en secciones;
máximo de secciones y límites de texto NO declarados en la página (el título de sección es el
SectionObject.title de máx 24 chars según [17]). Si el SKU no existe se descarta y llega
error pidiendo actualización de catálogo [16]. Vista: carrusel horizontal de productos que abre
PDP y permite armar carrito por dispositivo (el carrito no sincroniza entre dispositivos) [16].
6.6 Catálogo — interactive.type: "catalog_message" [14]
"interactive": {
"type": "catalog_message",
"body": { "text": "Explora nuestro catálogo" },
"action": { "name": "catalog_message",
"parameters": { "thumbnail_product_retailer_id": "SKU-001" } },
"footer": { "text": "Tienda oficial" } }
body.text máx 1024; footer.text máx 60; thumbnail_product_retailer_id opcional
(define la miniatura; si falta se usa la imagen del primer artículo del catálogo) [14].
Vista: miniatura de producto, texto fijo de encabezado, body, footer y botón "View catalog"
que abre el catálogo completo dentro de WhatsApp [14].
6.7 Carrusel de productos — interactive.type: "carousel" (cards tipo product) [13]
"interactive": {
"type": "carousel",
"body": { "text": "Lo más vendido" },
"action": { "cards": [
{ "card_index": 0, "type": "product",
"action": { "product_retailer_id": "SKU-001", "catalog_id": "123456789" } } ] } }
Límites: 2 a 10 cards; card_index entero 0–9, sin repetir; todas las cards deben
referenciar el mismo catalog_id; body.text máx 1024. Sin header, footer ni botones
a nivel de mensaje [13]. Vista: tarjetas desplazables horizontalmente, cada una abre su PDP [13][15].
6.8 Carrusel de media — cards con header image/video [12]
"interactive": {
"type": "carousel",
"body": { "text": "Nuevos cursos" },
"action": { "cards": [
{ "card_index": 0,
"header": { "type": "image", "image": { "link": "https://…/a.jpg" } },
"body": { "text": "Curso A" },
"action": { "name": "cta_url",
"parameters": { "display_text": "Inscribirme", "url": "https://…" } } } ] } }
Límites exactos [12]: 2–10 cards; header por card solo image o video (link o id);
body por card máx 160 caracteres y 2 saltos de línea; body del mensaje máx 1024;
quick-reply id máx 256, etiquetas (quick reply y URL) máx 20; cada card lleva un botón
URL o uno o más quick replies; tipos y cantidades de botones deben ser idénticos en todas las cards.
Sin header/footer a nivel de mensaje. Vista: cards con media arriba, texto y botón, desplazables
izquierda→derecha desde índice 0 [12].
7. Template messages
Único tipo enviable fuera de la ventana de servicio al cliente; se crean vía Template API o
WhatsApp Manager y deben quedar APPROVED antes de enviarse [19]. Creación: name (máx 512,
minúsculas/guiones bajos), category (AUTHENTICATION/MARKETING/UTILITY), language,
parameter_format (named p.ej. {{first_name}}, o positional p.ej. {{1}}) y components
[19]. Límites de cuenta: 250 plantillas/WABA (6000 con portafolio verificado + display name
aprobado), 100 plantillas creadas por hora por WABA [19].
7.1 Envío por Cloud API [21]
{ "messaging_product": "whatsapp",
"recipient_type": "individual",
"to": "16505551234",
"type": "template",
"template": {
"name": "reservation_confirmation",
"language": { "code": "en_US" },
"components": [
{ "type": "header",
"parameters": [ { "type": "image", "image": { "id": "2871834006348767" } } ] },
{ "type": "body",
"parameters": [ { "type": "text", "parameter_name": "day", "text": "Saturday" } ] },
{ "type": "buttons",
"sub_type": "URL", "index": 0,
"parameters": [ { "type": "text", "text": "abc123" } ] } ] } }
El header solo se envía si la plantilla usa header de media (image/video/document; los header
text/location no llevan parámetros en el envío) [21]. En plantillas posicionales los parámetros
van por orden, sin parameter_name [21]. En webhook los botones responden con
button_reply/list_reply; COPY_CODE entrega el código y CATALOG/MPM abren catálogo (los
sub_types de botón definidos por la API son: CATALOG, COPY_CODE, FLOW, MPM, OTP,
PHONE_NUMBER, QUICK_REPLY, URL [18]).
7.2 Componentes y límites de caracteres (creación) [20]
| Componente | Formatos / tipos | Límites |
|---|---|---|
| HEADER (1 máx) | format: TEXT, IMAGE, VIDEO, DOCUMENT, LOCATION |
TEXT: 60 caracteres, sin markdown, admite 1 parámetro. Media: handle de Resumable Upload API (GIF mp4 ≤3.5 MB, solo Marketing). LOCATION: sin parámetros al crear; al enviar latitude, longitude, name, address; solo UTILITY/MARKETING |
| BODY (requerido, 1) | texto | 1024 caracteres; parámetros múltiples named/posicionales con ejemplos obligatorios |
| FOOTER (opcional, 1) | texto | 60 caracteres |
BUTTONS (array buttons) |
ver abajo | máx 10 botones en total por plantilla |
Botones por tipo [20]:
- QUICK_REPLY: hasta 10; etiqueta máx 25 caracteres; deben agruparse (no intercalar
QR, URL, QR); el orden en el teléfono lo defineindexal enviar. - URL: hasta 2; etiqueta 25;
urlmáx 2000 caracteres, admite 1 variable al final (requiereexample; valores con caracteres especiales deben ir percent-encoded:%20,%3A,%7C… o el envío falla). El título corto del botón puede sobreescribirse (tap-target-url-title-override). - PHONE_NUMBER: solo 1;
phone_numbermáx 20 caracteres (se recortan ceros a la izquierda tras el código de país); etiqueta 25. - COPY_CODE: solo 1; código copiable en
example, máx 20 caracteres. - CATALOG: abre el catálogo; MPM (multi-producto) muestra hasta 30 productos en hasta 10 secciones; ambos no personalizables.
- VOICE_CALL: inicia llamada de WhatsApp al negocio; OTP (URL/ONE_TAP/ZERO_TAP) para
plantillas de autenticación, con
autofill_text,package_name,signature_hash.
Rendimiento en pantalla [20]: con >3 botones WhatsApp muestra 2 y un botón "See all options" que expande el resto; plantillas con 4+ botones, o quick replies mezcladas con otros tipos, no se ven en clientes de escritorio. Vista general: header arriba del body; body con variables resaltadas; footer en gris pequeño; botones como filas fijas al pie de la burbuja [20].
7.3 Plantillas de carrusel (marketing)
Existen media-card-carousel-templates (cards de media) y product-card-carousel-template-messages
[19]; su estructura de componentes en la Template API incluye type: CAROUSEL y
LIMITED_TIME_OFFER [18]. Detalle no extraído en esta investigación (fuera del alcance directo).
8. Tabla resumen de límites clave
| Elemento | Límite | Fuente |
|---|---|---|
text.body / body de lista |
4096 | [1][9] |
| Caption de image/video/document | 1024 | [2][3][5] |
| Tamaño image / video / audio / document | 5 MB / 16 MB / 16 MB / 100 MB | [2][3][4][5] |
| Sticker WebP animado / estático | 500 KB / 100 KB | [6] |
| Contactos por mensaje | 257 | [8] |
| Botones reply / list rows / secciones | 3 / 10 / 10 | [10][9] |
| Título botón (interactive) / display_text | 20 / 20 | [10][11][12] |
reply.id / row.id |
256 / 200 | [10][9] |
| Header / footer interactivos | 60 / 60 | [9][11] |
| Section title / row title / row description | 24 / 24 / 72 | [9][17] |
| Body de card de carrusel de media | 160 (2 saltos) | [12] |
| Cards de carrusel | 2–10 (índices 0–9) | [12][13] |
| Productos por product_list / MPM | 30 (en ≤10 secciones) | [16][20] |
| Plantilla: header TEXT / body / footer | 60 / 1024 / 60 | [20] |
| Plantilla: botones totales / QR / URL / PHONE / COPY_CODE | 10 / 10 / 2 / 1 / 1 | [20] |
| Plantilla: etiqueta botón / URL / phone / código | 25 / 2000 / 20 / 20 | [20] |
| Plantillas por WABA / creación por hora | 250 (6000 verificada) / 100 | [19] |
9. Fuentes consultadas (oficiales, developers.facebook.com)
[1] https://developers.facebook.com/docs/whatsapp/cloud-api/messages/text-messages [2] https://developers.facebook.com/docs/whatsapp/cloud-api/messages/image-messages [3] https://developers.facebook.com/docs/whatsapp/cloud-api/messages/video-messages [4] https://developers.facebook.com/docs/whatsapp/cloud-api/messages/audio-messages [5] https://developers.facebook.com/docs/whatsapp/cloud-api/messages/document-messages [6] https://developers.facebook.com/docs/whatsapp/cloud-api/messages/sticker-messages [7] https://developers.facebook.com/docs/whatsapp/cloud-api/messages/location-messages [8] https://developers.facebook.com/docs/whatsapp/cloud-api/messages/contacts-messages [9] https://developers.facebook.com/documentation/business-messaging/whatsapp/messages/interactive-list-messages [10] https://developers.facebook.com/documentation/business-messaging/whatsapp/messages/interactive-reply-buttons-messages [11] https://developers.facebook.com/documentation/business-messaging/whatsapp/messages/interactive-cta-url-messages [12] https://developers.facebook.com/documentation/business-messaging/whatsapp/messages/interactive-media-carousel-messages.md [13] https://developers.facebook.com/documentation/business-messaging/whatsapp/catalogs/interactive-product-carousel-messages.md [14] https://developers.facebook.com/documentation/business-messaging/whatsapp/catalogs/catalog-messages.md [15] https://developers.facebook.com/documentation/business-messaging/whatsapp/catalogs/single-product-messages.md [16] https://developers.facebook.com/documentation/business-messaging/whatsapp/catalogs/multi-product-messages.md [17] https://developers.facebook.com/documentation/business-messaging/whatsapp/reference/whatsapp-business-phone-number/message-api.md [18] https://developers.facebook.com/documentation/business-messaging/whatsapp/reference/whatsapp-business-account/message-template-api.md [19] https://developers.facebook.com/documentation/business-messaging/whatsapp/templates/overview.md [20] https://developers.facebook.com/documentation/business-messaging/whatsapp/templates/components.md [21] https://developers.facebook.com/documentation/business-messaging/whatsapp/templates/utility-templates/utility-templates.md [22] https://developers.facebook.com/documentation/business-messaging/whatsapp/link-previews.md
Declaraciones de cobertura: (a) la sintaxis de formateo de texto (bold, italic, tachado,
mono) ya no está documentada en las páginas oficiales consultadas — solo consta la nota de que
body/footer interactivos soportan markdown [17] y la prohibición de markdown en header TEXT de
plantillas [20]; (b) límites no declarados: máximo de secciones en product_list, límites de texto
en product, límite de header text en interactive.type: button, y máximo de botones en
cta_url — se reportan como no documentados, no como valores asumidos; (c) varias páginas nuevas
(carousel-messages, product-messages en su slug HTML) solo renderizan con JavaScript y se accedió
a su contenido vía las versiones .md publicadas por Meta en el índice llms.txt.