Ir al contenido

Cambios por versión

Esta página sigue la versión del contrato /v1: la que publica el OpenAPI (info.version) y GET /v1/capabilities en contrato. Hoy hay una sola, la v1.0.0. El binario del motor tiene su propia versión y su commit (los muestra motorctl, la página Operación del panel y la métrica motor_info): no confundas una con la otra.

La primera versión del contrato. Cubre las funciones de transporte del plan MW0 a MW12 (las que WhatsApp permite a un dispositivo vinculado y el SDK soporta), con entrega durable de los eventos. Se probó con el driver falso, con integración sobre Postgres y MinIO reales, y a mano con números reales en iOS y Android entre el 17 y el 23 de octubre de 2026 (109 casos: 80 pasan, 20 parciales, 5 sin ejecutar y 4 que no se pueden hacer). Lo parcial está en Limitaciones de WhatsApp.

Para migrar: nada. Es la primera versión.

  • Varias instancias (números) por app, con un cupo por app que se respeta de forma atómica (429 al pasarlo). Una key restringida a instancias no puede crear otras.
  • Vinculación por QR y por código (el teléfono en formato internacional, con +). La passkey está expuesta como experimental: el motor devuelve la acción real que pide WhatsApp.
  • Cada intento sube la generación de la instancia; generacion_esperada evita mandar por un número que se volvió a vincular.
  • Estado deseado y estado observado por separado, con motivos tipificados. Reconexión automática con espera creciente; pausar, reanudar, desconectar, desvincular (local o avisando a WhatsApp) y archivar sin borrar el ledger.
  • Diagnóstico sin datos personales (GET /v1/instances/{id}/diagnostics).
  • Proxy por instancia (HTTP con CONNECT o SOCKS5), elegido de una lista que administra el operador; nunca una URL suelta ni las variables HTTP_PROXY del entorno.
  • Un solo proceso es dueño de cada sesión, con fencing en la base: una sesión nunca queda abierta en dos procesos.
  • Un solo endpoint para mandar: POST /v1/instances/{id}/messages, con Idempotency-Key obligatoria. Responde 202 con el comando guardado; el resultado llega como evento.
  • Tipos: text (con cita, menciones y vista previa de enlaces), location, contacts, reaction, edit (hasta 20 minutos), revoke (borrar para todos), forward, disappearing (temporizador del chat) y poll (encuestas, con el voto vigente de cada votante y el resultado agregado).
  • Outbox con ID de proveedor fijo: un reintento nunca duplica. Un envío que pudo salir o no queda ambiguo y nunca se reenvía solo; si su eco o su recibo aparecen, se concilia.
  • Recibos por destinatario (entregado, leido, reproducido), marcar como leído o reproducido, presencia propia y suscripción a la presencia de un contacto.
  • Mensajes temporales: el motor respeta el vencimiento, borra el contenido y emite message.expired.
  • Lo que el motor no reconoce llega como no_soportado con el tipo del proveedor, nunca con un texto inventado.
  • Consulta del store propio: GET /v1/instances/{id}/messages, con filtros, cursor y el detalle de los recibos.
  • Almacenamiento privado en un bucket compatible con S3 (MinIO): MIME real, tamaño, digest, cuota por app y por instancia, y retención.
  • Envío de image, video, document y audio por media_id o por URL (con lista de hosts permitidos y protección contra SSRF).
  • Subtipos con conversión acotada (ffmpeg): nota de voz (ptt), vídeo circular (ptv), sticker (estático y animado) y gif.
  • Recepción con descarga durable (media.ready o media.failed) y lectura en streaming, también en base64 acotado.
  • tipo: interactive con botones (reply, copiar código, URL, llamada y PIX), lista nativa (con respaldo de texto opcional) y carrusel de 2 a 10 tarjetas.
  • Las respuestas llegan como interactive.response, correlacionadas con el comando que mandó el interactivo; lo que no se puede leer, como interactive.unknown.
  • Todos llevan el aviso «no garantizado en números no oficiales»: el motor informa el resultado real y nunca da por visto lo que WhatsApp puede no mostrar.
  • Crear, salir, cambiar nombre, descripción, foto y ajustes (anuncios, bloqueo, aprobación, modo de incorporación), administrar participantes y solicitudes, obtener o revocar la invitación, consultarla sin entrar, unirse y mandarla por mensaje.
  • Comunidades: crear, vincular y desvincular grupos (un vínculo por par, versionado) y listar sus grupos y participantes.
  • Lo que cambia desde un teléfono llega como group.changed, group.participants, group.joined y community.changed.
  • Crear, seguir y dejar de seguir (por JID o enlace), silenciar, consultar una invitación, listar publicaciones por server_id, reaccionar, marcar vistas y consultar los contadores.
  • Publicar en un canal es un envío más, con destino …@newsletter.
  • Publicar estados de texto, imagen o vídeo por el outbox, con la audiencia explícita (experimental).
  • Recibir los estados de los contactos con su retención: pasado el plazo, el contenido se borra y el evento queda redactado.
  • Eventos de cada señal de una llamada entrante (call.*), rechazo a pedido y rechazo automático por instancia, con un texto opcional a quien llamó.
  • Atender y hacer llamadas no está soportado: responde 501 llamadas_no_soportadas, nunca un éxito simulado.
  • Nombre, Info (recado) y foto propios; las diez opciones de privacidad del SDK y el temporizador por defecto de los mensajes temporales; bloquear, desbloquear y listar bloqueados.
  • Cada dato del perfil dice quién lo fijó (whatsapp, motor o consulta) y si WhatsApp lo confirmó.
  • Los contactos de transporte del número (libreta, push name, nombre de negocio, Info y foto), sincronizados con el teléfono. No son contactos de tu CRM.
  • Identidades PN y LID comprobadas por instancia, con un peer_ref estable.
  • Consultas con cuota diaria por app: si un número está en WhatsApp, el perfil público y la foto.
  • Estado de la app de WhatsApp: fijar (hasta 3 chats), archivar, silenciar, leído y no leído, destacar y borrar el chat, como comandos durables sincronizados con el teléfono. El candado que pone el teléfono también se refleja.
  • Etiquetas de WhatsApp Business: crear, editar, eliminar y poner o quitar en chats y mensajes.
  • Perfil comercial de un número (GET /v1/instances/{id}/business/profile).
  • Lectura del catálogo de productos y de las colecciones de un negocio, con cursor, caché y su cuota. Solo lectura: nada de crear productos, pedidos ni inventario.
  • Cada consulta remota deja query.completed o query.failed.
  • El protocolo del historial se procesa siempre; importar el contenido es opcional por instancia (apagado de fábrica), con tope de días y de mensajes.
  • Trabajos de historial (el inicial, el pedido de un chat y la importación hacia atrás), con progreso, cancelación y su resultado. WhatsApp no garantiza la historia completa, y el motor nunca lo afirma.
  • Ledger por instancia: cada hecho se guarda con un seq que crece sin huecos, en la misma transacción que lo acepta. El sobre de los eventos es el mismo por cualquier canal (schema_version: 1); el catálogo tiene los 75 tipos.
  • Lectura paginada: GET /v1/instances/{id}/events.
  • Webhooks firmados con HMAC-SHA256 (firma v1), rotación del secreto sin cortar entregas, orden por instancia, reintentos durante 72 horas, entregas fallidas visibles y replay que nunca vuelve a mandar nada a WhatsApp.
  • Streams SSE y WebSocket leídos del ledger, con cursor firmado y reanudación sin saltos ni repetidos.
  • Brokers: NATS, RabbitMQ, Kafka y SQS, configurados por el operador (no hay ruta en /v1). Pusher, S3 y los bots se integran por guía, sin adaptador propio.
  • SDK de Go (sdk/go): el cliente de /v1, el verificador y el receptor de webhooks, un inbox de ejemplo que deduplica por event_id, el cliente de streams y dobles para tus pruebas.
  • Backup diario cifrado (AES-256-GCM, archivo .mwbk), con el store de sesiones incluido, verificación al terminar y retención; RPO de 24 horas y RTO de 1 hora. El restore es aislado y arranca sin abrir sesiones hasta que el operador confirma el corte del original.
  • Actualizaciones: cada migración declara si permite volver atrás; migrate verificar revisa antes de actualizar; canario por instancias marcadas. Volver atrás de un cambio incompatible, o del store de whatsmeow, es restaurar un backup.
  • Métricas en formato Prometheus (/admin/api/metricas), watchdog de instancias trabadas (avisa, nunca reinicia) y límites del proceso desde Ajustes.
  • Panel de operadores servido por el propio motor en /admin: apps y keys, instancias y sus fichas, entregas, backups, operación y Ajustes; exportación de la configuración saneada.
  • Capacidad medida con carga sintética y el driver falso (hasta 10 instancias): no afirma el rendimiento con WhatsApp real.
  • El motor no se expone a internet. Dos identidades que no se mezclan: operadores con sesión, cookie y CSRF en /admin/api, y apps con API keys (Bearer mw_…) con scopes en /v1.
  • Las API keys se guardan con hash, se muestran una sola vez y rotar revoca la anterior al instante. Una app solo ve lo suyo: un recurso ajeno es 404, sin enumerar dueños.
  • El entorno solo lleva cuatro variables (DATABASE_URL, APP_MASTER_KEY, APP_ENV, PORT); el resto va en Ajustes, con los secretos sellados. Los payloads del ledger también van sellados.
  • Logs y auditoría sin secretos, teléfonos, JIDs ni contenido. Webhooks, brokers, proxies y descargas por URL pasan por una lista de destinos permitidos con protección contra SSRF.
  • Contenedor sin root y de solo lectura; el motor nunca reinicia una instancia en bucle. Secret scan, SBOM y licencias revisados.

Lo que la v1.0.0 no resuelve, sea por WhatsApp o por el motor:

  • Las listas nativas no se dibujan en iOS: usa el respaldo de texto (detalle).
  • De una ubicación en tiempo real solo llega el primer mensaje (detalle).
  • La presencia no trae el «en línea» real ni la última vez (detalle).
  • Las vistas y reacciones de un canal no llegan en vivo: se consultan (detalle).
  • La Info propia cambiada desde el teléfono no produce profile.updated (detalle).
  • El historial bajo pedido depende de que el teléfono conteste (detalle).
  • Sin soporte: llamadas de voz o vídeo, listas de difusión y plantillas de la Cloud API.
  • Las colecciones del catálogo dan solo la primera vista que entrega WhatsApp: la continuación remota es una brecha conocida.
  • Los brokers se probaron en contenedores locales; contra AWS SQS real y un broker gestionado, todavía no (casos B5 y B6).
  • APP_MASTER_KEY no se puede rotar en el lugar en esta versión.

La lista completa, con fechas y qué hacer, está en Limitaciones de WhatsApp.

Se considera un cambio incompatible, y no se hace dentro de /v1 ni de un mismo schema_version:

  • Quitar o renombrar una ruta, un parámetro, un campo de una respuesta o del sobre, un tipo de evento, un campo de data, un scope o un error_code.
  • Cambiar el tipo o el significado de un campo, o un código HTTP de una respuesta documentada.
  • Hacer obligatorio un campo de pedido que era opcional, o achicar un límite documentado.
  • Cambiar la firma de los webhooks o las garantías de entrega: el orden por instancia, el seq sin huecos y la entrega al menos una vez.

No se considera incompatible, y puede llegar en una versión menor de /v1:

  • Rutas, scopes y tipos de evento nuevos.
  • Campos opcionales nuevos en un pedido.
  • Campos nuevos en una respuesta, en el sobre o en data.
  • Valores nuevos en una enumeración: estados, motivos, error_code, contenido.tipo, acciones.

Para que una versión menor no rompa tu integración:

  • Ignora los campos que no conoces y no falles con un tipo de evento nuevo: guárdalo o descártalo.
  • Trata un valor desconocido de una enumeración como «otro», no como un error.
  • No mandes campos de una versión más nueva a un motor más viejo: los cuerpos son cerrados y responden 422.
  • Revisa GET /v1/capabilities al arrancar para saber qué ofrece el motor que tienes.

Un cambio incompatible en los eventos llegaría con un schema_version nuevo, y uno en la API, con otro prefijo de ruta. Esta página va a decir, por versión, qué cambió y cómo migrar.