# Códigos de error: Interacciones: chat, bandeja y plantillas

> El chat de Boost: bandeja, historial, salida de mensajes desde el chat, plantillas de WhatsApp, links de pago y notas.

**Cómo se detecta (toda la familia):** El `code` viaja en la respuesta al front (DevTools → Red). Render solo muestra la petición y su status.

**Qué hacer (toda la familia):** La mayoría son de configuración del canal (número sin cuenta, canal sin configurar, contacto sin teléfono). Revisa la cuenta del canal en Configuración → Canales y los datos del contacto.

Lo que un código no dice lo hereda de la familia.

## `channel_accounts_not_in_entity`

- **Tipo:** HTTP · **HTTP:** 400 · **Estado:** vigente
- **Qué significa:** Se quisieron asignar a un empleado números que no son de la entidad.

## `CHAT_NOTE_NOT_OWNER`

- **Tipo:** HTTP · **HTTP:** 403 · **Estado:** vigente
- **Qué significa:** Una nota interna del chat la edita solo quien la escribió; la borra su autor, plataforma o quien tiene `settings.manage` en la entidad.

## `CONTACT_MERGE_AUDIT_UNAVAILABLE`

- **Tipo:** HTTP · **HTTP:** 503 · **Estado:** vigente
- **Qué significa:** Unir contactos: no se pudo registrar la decisión en `authz_decisions`; no se unió nada (503).
- **Qué hacer:** Revisar la auditoría de Roles (AuthzAuditService) y reintentar.

## `CONTACT_MERGE_BLOCKED`

- **Tipo:** HTTP · **HTTP:** 409 · **Estado:** vigente
- **Qué significa:** Unir contactos: al borrar el contacto origen, una FK todavía lo referenciaba; la transacción se deshizo completa.
- **Causa típica:** Una tabla nueva con `contact_id` hacia `contacts` que la unión no sabe mover.
- **Cómo detectarlo:** Log `🔴 [contact-merge] un contacto origen sigue referenciado` en Render, con el error de MySQL.
- **Qué hacer:** Agregar la tabla a `applyContactMerge` (src/interactions/contact-merge/contact-merge.store.ts) y a su laboratorio.

## `CONTACT_MERGE_CONTACT_NOT_FOUND`

- **Tipo:** HTTP · **HTTP:** 404 · **Estado:** vigente
- **Qué significa:** Unir contactos: uno de los contactos no existe en la entidad de la sesión (o ya se unió a otro).

## `CONTACT_MERGE_CONTACT_NOT_VISIBLE`

- **Tipo:** HTTP · **HTTP:** 403 · **Estado:** vigente
- **Qué significa:** Unir contactos: quien une no ve alguno de los contactos con el alcance del inbox (vendedor, lead o contacto).

## `CONTACT_MERGE_NOTHING_TO_MERGE`

- **Tipo:** HTTP · **HTTP:** 400 · **Estado:** vigente
- **Qué significa:** Unir contactos: no se eligió ningún contacto distinto del que queda.

## `CONTACT_MERGE_RETRY`

- **Tipo:** HTTP · **HTTP:** 409 · **Estado:** vigente
- **Qué significa:** Unir contactos: MySQL eligió la unión como víctima de un deadlock (1213) dos veces seguidas. La unión se reintenta UNA vez entera; la segunda vez responde 409 y no se unió nada.
- **Causa típica:** Otra transacción tomaba al mismo tiempo las mismas filas en otro orden, por ejemplo la página web de Workflows (bloquea la sesión y después la ejecución) o un paso del motor.
- **Cómo detectarlo:** Logs `🟠 [contact-merge] deadlock (1213)` en Render: el primero dice que se reintenta y el segundo que no se unió nada.
- **Qué hacer:** Volver a intentar. Si se repite con los mismos contactos, revisar qué otra transacción toca sus ejecuciones o sesiones de la página web.

## `CONTACT_MERGE_STALE_PREVIEW`

- **Tipo:** HTTP · **HTTP:** 409 · **Estado:** vigente
- **Qué significa:** Unir contactos: algo de los contactos cambió entre la vista previa y la unión (canales, identidades, chats, ejecuciones). No se unió nada.
- **Qué hacer:** Volver a pedir la vista previa y confirmar otra vez.

## `CONTACT_MERGE_TOO_MANY`

- **Tipo:** HTTP · **HTTP:** 400 · **Estado:** vigente
- **Qué significa:** Unir contactos: más contactos origen que el tope por operación (10).

## `CONTACT_MERGE_TWO_FACEBOOK`

- **Tipo:** HTTP · **HTTP:** 409 · **Estado:** vigente
- **Qué significa:** Unir contactos: la unión dejaría a un contacto con dos cuentas de Messenger distintas (PSID). No se une nada.
- **Causa típica:** Por contacto, como máximo un WhatsApp, un Facebook (Messenger) y un Instagram.
- **Qué hacer:** Es la regla: se quedan como contactos separados.

## `CONTACT_MERGE_TWO_INSTAGRAM`

- **Tipo:** HTTP · **HTTP:** 409 · **Estado:** vigente
- **Qué significa:** Unir contactos: la unión dejaría a un contacto con dos cuentas de Instagram distintas (IGSID). No se une nada.
- **Causa típica:** Por contacto, como máximo un WhatsApp, un Facebook (Messenger) y un Instagram.
- **Qué hacer:** Es la regla: se quedan como contactos separados.

## `CONTACT_MERGE_TWO_WHATSAPP`

- **Tipo:** HTTP · **HTTP:** 409 · **Estado:** vigente
- **Qué significa:** Unir contactos: la unión dejaría a un contacto con dos números de WhatsApp distintos. No se une nada y el segundo sigue siendo otro contacto.
- **Causa típica:** Por contacto, como máximo un WhatsApp, un Facebook (Messenger) y un Instagram. El mismo número en dos formatos (con y sin código de país) sí se une.
- **Qué hacer:** Es la regla, no un fallo: si son dos personas, se quedan separadas. Si es la misma persona con dos números, hoy no se pueden unir.

## `CONTACT_MERGE_WORKFLOW_QUEUED`

- **Tipo:** detalle · **HTTP:** — · **Estado:** vigente
- **Qué significa:** Unir contactos: hay un flujo a punto de correr (`queued_wait_conflict`) para alguno de los dos contactos. No existe un estado `queued` (`ExecutionStatus`).
- **Qué hacer:** Reintentar en unos segundos.

## `CONTACT_MERGE_WORKFLOW_RUNNING`

- **Tipo:** detalle · **HTTP:** — · **Estado:** vigente
- **Qué significa:** Unir contactos: hay una ejecución de workflow `running` de alguno de los dos contactos. No se toca a mitad de un paso (regla de Workflows).
- **Qué hacer:** Reintentar en unos segundos. Si no se libera, es un `running` zombie: lo cierra el janitor del motor.

## `conversation_without_lead`

- **Tipo:** HTTP · **HTTP:** 400 · **Estado:** vigente
- **Qué significa:** Este chat no tiene un cliente asociado: no hay ordenes que cobrar.

## `INGEST_SECRET_INVALID`

- **Tipo:** HTTP · **HTTP:** 401 · **Estado:** vigente
- **Qué significa:** El formulario externo mandó una clave de ingreso equivocada (401).

## `INGEST_SECRET_NOT_CONFIGURED`

- **Tipo:** HTTP · **HTTP:** 503 · **Estado:** vigente
- **Qué significa:** La clave de ingreso de formularios no está configurada en el servidor (503).

## `INTERACTIONS_CHAT_THREAD_OF_OTHER_ACCOUNT`

- **Tipo:** HTTP · **HTTP:** 409 · **Estado:** vigente
- **Qué significa:** El chat es un hilo de otra cuenta de canal, no del número por el que se quiso proyectar.

## `INTERACTIONS_CONTACT_CHANNEL_MISSING`

- **Tipo:** HTTP · **HTTP:** 400 · **Estado:** vigente
- **Qué significa:** El contacto no tiene identificador para ese canal (teléfono para WhatsApp, id para Messenger/Instagram, correo).

## `INTERACTIONS_CONTACT_INACTIVE`

- **Tipo:** HTTP · **HTTP:** 409 · **Estado:** vigente
- **Qué significa:** Envío (409) a un contacto inactivo, de una persona o de la automatización: mensaje, media, plantilla, inicio con plantilla, producto o cotización del catálogo, link de pago, respuesta rápida, auto-respuesta, sesión de compra o correo. No sale nada ni se escribe en la timeline.
- **Causa típica:** El contacto está inactivo (borrar un contacto lo inactiva) y alguien le escribe desde un chat abierto antes o por un enlace viejo, o un workflow que no pasa por los selectores de destinatario intenta escribirle (sus ejecuciones vivas se cancelan al inactivarlo). Un entrante lo reactiva antes de que corra cualquier workflow.
- **Cómo detectarlo:** La respuesta (`code`, con `contact_id`); en Render, `[interactions.contact-inactive] envío rechazado … automation=<true|false>`; en un workflow, la ejecución queda en `paused_error` con el mensaje. En la base: `contacts.deactivated_at` del contacto de la conversación.
- **Qué hacer:** El contacto se reactiva solo si el cliente escribe, o al crearlo de nuevo con su número.

## `INTERACTIONS_MESSAGE_NOT_RETRYABLE`

- **Tipo:** HTTP · **HTTP:** 404 · **Estado:** vigente
- **Qué significa:** Solo se reintenta un mensaje fallido que salio por la salida directa de Boost.

## `INTERACTIONS_OUTBOUND_CHANNEL_ACCOUNT_CHANNEL_MISMATCH`

- **Tipo:** HTTP · **HTTP:** 400 · **Estado:** vigente
- **Qué significa:** El número emisor elegido es de otro canal que el del envío (p. ej. un número de WhatsApp para un chat de Messenger).

## `INTERACTIONS_OUTBOUND_CHANNEL_ACCOUNT_FORBIDDEN`

- **Tipo:** HTTP · **HTTP:** 403 · **Estado:** vigente
- **Qué significa:** La persona no tiene permitido enviar con el número por defecto del chat (o con el que eligió).
- **Causa típica:** El número no está asignado a esa persona (números por empleado) y no tiene permiso para usar otros.
- **Qué hacer:** Elegir un número emisor asignado a la persona, o asignarle el número en Configuración → Canales.

## `INTERACTIONS_OUTBOUND_CHANNEL_ACCOUNT_NOT_CONFIGURED`

- **Tipo:** HTTP · **HTTP:** 400 · **Estado:** vigente
- **Qué significa:** El número elegido no tiene por dónde salir: el envío no pasa por la salida directa de Boost y el número no tiene configurado el camino heredado.

## `INTERACTIONS_OUTBOUND_CHANNEL_ACCOUNT_NOT_FOUND`

- **Tipo:** HTTP · **HTTP:** 400 · **Estado:** vigente
- **Qué significa:** El número emisor elegido no existe en esta entidad.

## `INTERACTIONS_OUTBOUND_CHANNEL_BLOCKED`

- **Tipo:** HTTP · **HTTP:** 400 · **Estado:** vigente
- **Qué significa:** El canal es de solo lectura (p. ej. `internet`): no se envían mensajes por él.

## `INTERACTIONS_OUTBOUND_CHANNEL_NOT_AVAILABLE`

- **Tipo:** HTTP · **HTTP:** 400 · **Estado:** vigente
- **Qué significa:** El tipo de canal no está habilitado para enviar.

## `INTERACTIONS_OUTBOUND_CHANNEL_NOT_CONFIGURED`

- **Tipo:** HTTP · **HTTP:** 400 · **Estado:** vigente
- **Qué significa:** El canal no tiene número emisor: ninguna cuenta de la entidad para esta conversación sale por Boost (`egress_owner = boost`).

## `INTERACTIONS_OUTBOUND_CHANNEL_REQUIRED`

- **Tipo:** HTTP · **HTTP:** 400 · **Estado:** vigente
- **Qué significa:** Falta o es inválido `channel_type_code` para iniciar la conversación.

## `INTERACTIONS_OUTBOUND_CONTACT_CHANNEL_MISSING`

- **Tipo:** HTTP · **HTTP:** 400 · **Estado:** vigente
- **Qué significa:** El contacto del chat no tiene destinatario para ese canal.

## `INTERACTIONS_QUOTE_CHANNEL_UNAVAILABLE`

- **Tipo:** HTTP · **HTTP:** 409 · **Estado:** vigente
- **Qué significa:** La cotización no se puede mandar por correo desde su vista previa (409): el contacto no tiene dirección de correo o el actor no tiene un buzón para escribirle (`reason`: no_mailbox, no_recipient, no_conversation…).

## `INTERACTIONS_QUOTE_NO_CONVERSATION`

- **Tipo:** HTTP · **HTTP:** 404 · **Estado:** vigente
- **Qué significa:** No hay una conversación de interacciones para el cliente de esta cotización.

## `INTERACTIONS_REPLY_CHANNEL_WINDOW_CLOSED`

- **Tipo:** HTTP · **HTTP:** 400 · **Estado:** vigente
- **Qué significa:** Una persona respondió por un canal o número cuya ventana de 24 h está cerrada, pero OTRO canal del mismo contacto la tiene abierta (el cliente escribió por ahí): el chat único junta WhatsApp, Messenger e Instagram y cada uno tiene su ventana.
- **Causa típica:** El compositor quedó en un canal o número viejo (p. ej. WhatsApp por el número de pruebas) mientras el cliente acaba de escribir por Messenger. Nace del 01/10/2026: la respuesta de la conversación 887 salió por WhatsApp con la ventana vencida y el error decía "solo plantillas".
- **Cómo detectarlo:** Respuesta 400 con `reason_code: WINDOW_CLOSED`, `cause_code` (el código original, p. ej. WHATSAPP_SESSION_EXPIRED), el canal y la cuenta que fallaron (`channel_type_code`, `entity_channel_account_id`) y `open_channels` (los abiertos, el del último entrante primero). En Render: `[interactions.outbound] ventana cerrada en el canal elegido; abierto …`. Solo envíos de una persona; la automatización sigue recibiendo el código original.
- **Qué hacer:** Responder por el canal que trae `open_channels[0]` (la web ofrece "Enviar por …" en el mensaje que no salió). Si no hay ningún canal abierto, este código no aparece: sale el de siempre y solo queda una plantilla.

## `INTERACTIONS_WHATSAPP_CHANNEL_NOT_CONFIGURED`

- **Tipo:** HTTP · **HTTP:** 400 · **Estado:** vigente
- **Qué significa:** No hay canal de WhatsApp configurado para esta conversación

## `INTERACTIONS_WHATSAPP_TEMPLATE_CHANNEL_ACCOUNT_DISCONNECTED`

- **Tipo:** HTTP · **HTTP:** 400 · **Estado:** vigente
- **Qué significa:** El número elegido para crear o borrar plantillas fue dado de baja (`account_status = 'disconnected'`); hay que usar el número conectado que lo reemplazó.
- **Causa típica:** Una pantalla abierta desde antes de la baja, o una llamada directa a la API con el id viejo: el selector de números ya no ofrece cuentas dadas de baja.
- **Qué hacer:** Recargar la pantalla y elegir el número conectado.

## `INTERACTIONS_WHATSAPP_TEMPLATE_CHANNEL_ACCOUNT_NOT_FOUND`

- **Tipo:** HTTP · **HTTP:** 400 · **Estado:** vigente
- **Qué significa:** El número elegido para las plantillas no existe en esta entidad.

## `INTERACTIONS_WHATSAPP_TEMPLATE_CHANNEL_ACCOUNT_NOT_WHATSAPP`

- **Tipo:** HTTP · **HTTP:** 400 · **Estado:** vigente
- **Qué significa:** El número elegido no es de WhatsApp: las plantillas son solo de WhatsApp.

## `INTERACTIONS_WHATSAPP_TEMPLATE_INVALID`

- **Tipo:** HTTP · **HTTP:** 400 · **Estado:** vigente
- **Qué significa:** La plantilla que se quiere crear no cumple lo que exige Meta; el mensaje lista cada campo con problema.

## `INTERACTIONS_WHATSAPP_TEMPLATES_RATE_LIMITED`

- **Tipo:** HTTP · **HTTP:** 429 · **Estado:** vigente
- **Qué significa:** Meta limitó temporalmente las lecturas de plantillas de la WABA (429). Nunca se disfraza de 500.
- **Causa típica:** Demasiadas lecturas de plantillas en poco tiempo (Meta #80008).
- **Cómo detectarlo:** Respuesta 429 con `retry_after_seconds` / `retry_at` tal como los dio Meta, o en `null` si no los dio (`constraint.whatsapp-templates-rate-limit-is-a-typed-429-never-a-local-guess-2`).
- **Qué hacer:** Esperar; el front muestra la espera sin cuenta regresiva si no hay tiempo. No reintentar en bucle.

## `payment_link_not_sent`

- **Tipo:** HTTP · **HTTP:** 502 · **Estado:** vigente
- **Qué significa:** El link de pago se generó pero no se pudo mandar por WhatsApp; la respuesta trae el `payment_url` para mandarlo a mano.

## `payment_link_whatsapp_only`

- **Tipo:** HTTP · **HTTP:** 400 · **Estado:** vigente
- **Qué significa:** El link de pago se manda como boton de WhatsApp, y este chat no esta en WhatsApp.

## `whatsapp_message_limits_exceeded`

- **Tipo:** HTTP · **HTTP:** 400 · **Estado:** vigente
- **Qué significa:** El mensaje pasa los límites de WhatsApp (largo del texto, botones, filas de lista); `violations` dice cuáles.
