Files
2026-09-27 19:17:33 -06:00

22 KiB
Raw Permalink Blame History

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, prefix
  • phones[]: phone, type (CELL/MAIN/IPHONE/HOME/WORK), wa_id — si falta wa_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, title
  • addresses[]: street, city, state, zip, country, country_code (ISO-2), type
  • birthday: formato YYYY-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].

"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 define index al enviar.
  • URL: hasta 2; etiqueta 25; url máx 2000 caracteres, admite 1 variable al final (requiere example; 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_number má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.