Skip to content

Cumplimiento y restricciones innegociables

Estas reglas no son "lineamientos sugeridos"; están en el PR/FAQ como condiciones para aprobar el proyecto. Si rompemos una, rompemos el contrato con la unidad de negocio.

ALCOA+: pilar por pilar, con nuestra parte técnica

PilarQué exigeCómo lo aterrizamos del lado API
AtribuibleCada transacción identifica autor, momento y lugar.Headers obligatorios: X-Customer-Code (o teléfono E.164), X-Gps-Lat/Lng cuando el agente los tenga. Timestamp server-side, nunca confiar en el cliente. Log inmutable.
LegibleLa evidencia puede ser leída e interpretada.POD almacenado como JPEG + JSON estructurado (no transcripciones manuales). Versionado en bucket inmutable.
ContemporáneoEl registro ocurre cerca del evento.POST /v1/orders → SAP en <60 s P95. Sin back-dating bajo ninguna circunstancia. Alarmas cuando el SLA se viola.
OriginalEl dato viaja sin re-tipeo humano.Pasamos el payload tal cual del agente al iFlow BTP. Si transformamos, conservamos el original en audit log.
ExactoLos valores reflejan la verdad de los maestros.Precios SIEMPRE desde SAP MDM, jamás hardcoded ni cacheados sin TTL+invalidación. Tier (graduación) se lee con cada cotización.
CompletoNada se descarta silenciosamente.Ningún campo se elimina en transformaciones. Si el agente no envía algo, error explícito; no llenado por default.
ConsistenteMismos datos producen el mismo resultado.Idempotencia en POST /v1/orders. Pruebas de contrato (Pact o similar) contra los iFlows BTP.
DuraderoEl dato sobrevive.Retención 5 años en bucket inmutable (versioning + object lock) y en SAP. Backups de Cloud SQL diarios.
DisponibleAuditor puede leerlo cuando lo necesite.Endpoint interno de consulta de audit trail; dashboards en Cloud Logging.

Cumplimiento fiscal mexicano

El 50% de los clientes VaB no tienen RFC propio. Esto no es un caso borde — la solución debe contemplarlo de origen.

Protocolo de facturación para clientes no fiscales

Cuando el agente Nilo identifica que el cliente no es fiscal y llamamos a POST /v1/business-partners o creamos la orden, nosotros automatizamos:

CampoValor obligatorioPor qué
RFCXAXX010101000Clave genérica nacional del SAT
Razón socialPÚBLICO EN GENERALNombre fiscal estándar
Régimen fiscal616"Sin obligaciones fiscales"
Uso de CFDIS01"Sin efectos fiscales"
Código postalDel emisor (Rotoplas), no del clienteNorma SAT

Implementación:

  • SvcFiscal detecta el caso (campo fiscal: false o ausencia de RFC válido).
  • Crea el Business Partner en SAP vía BAPI BAPI_BUPA_CREATE_FROM_DATA con los valores anteriores.
  • Marca la orden para incorporación a la factura global.

Facturas globales

El SAT permite agrupar ventas a público en general en una sola factura global (diaria/quincenal). Esto evita que el asesor facture manualmente cada micro-transacción.

  • Job batch nuestro (Cloud Run con Scheduler o VM con cron) que corre al cierre del día/quincena.
  • Agrupa todas las órdenes marcadas factura_global = true.
  • Emite un único CFDI consolidado en SAP.
  • Genera reporte para Finanzas.

Confirmar con Finanzas: cadencia exacta (diaria vs quincenal), criterios de agrupación, layout del reporte.

Seguridad: SIM Swapping y HU-08

La HU-08 (venta agéntica multimodal — fotos de anaquel, notas de voz que se traducen a pedidos) habilita pagos y manejo de crédito revolvente vía WhatsApp. Esto eleva el riesgo de SIM Swapping: si un atacante secuestra el número del ferretero, puede:

  • Comprar a su nombre.
  • Consumir el crédito revolvente.
  • Cambiar el destino de entrega.

El PR/FAQ exige auditoría de ciberseguridad anti SIM Swapping como parte del Definition of Done. Implicaciones para nosotros:

  1. La autenticación NO puede basarse solo en "tengo el número". Agregar al menos un segundo factor para acciones financieras: PIN del lado del agente, verificación biométrica si la PWA está habilitada, o reto out-of-band.
  2. Límites por monto / por velocidad en POST /v1/orders y POST /v1/credit/apply. Una orden inusualmente grande debe disparar verificación adicional.
  3. Detección de cambio de SIM: muchos operadores exponen API para detectarlo (Twilio Verify, Telesign). Evaluar.
  4. Geolocalización coherente: si el GPS reportado por el agente cambia drásticamente entre transacciones, levantar bandera.
  5. Notificaciones de seguridad: avisar al asesor cuando un cliente clave hace cambios sensibles.

Diseñar esto antes de cablear pagos. La auditoría es un gate del despliegue, no algo que se hace después.

Riesgo heredado: lógica de precios VB6

El PR/FAQ §4.1 lo marca como riesgo: la lógica de precios actual vive en Visual Basic 6, con descuentos por graduación, promociones y reglas que se aplican en sitio. Si no se migra correctamente al motor de Nilo / SAP MDM, hay riesgo de discrepancia financiera entre la oferta del agente y el cargo final.

Acción del Hito 3 del roadmap: identificar y migrar esa lógica antes del despliegue. Para nosotros como dev de la capa API esto significa:

  • Mientras la migración no esté completa, fallar cerrado: si MDM no responde con precio, devolver 503; nunca caer a un default.
  • Pruebas de regresión que comparen precios VB6 vs MDM para una muestra representativa de SKUs × Tiers.
  • Pedir a quien lidere la migración (por confirmar — pendiente #13) un canal de comunicación claro sobre el progreso.

Privacidad de identificadores (Usernames / BSUID)

A partir de junio 2026 Meta despliega de forma gradual los WhatsApp usernames: el usuario podrá crear un alias y ocultar su número al mensajear con negocios. Esto cambia el contrato del webhook de la Cloud API y, por extensión, nuestra noción de "identidad del cliente".

Timeline oficial de Meta

FechaHito
31 marzo 2026BSUIDs empiezan a llegar en webhooks productivos
Abril 2026Launch de Contact Book (mapping teléfono ↔ BSUID hosted por Meta, scoped al portafolio)
Junio 2026El campo to del envío acepta BSUID + rollout gradual de usernames a usuarios finales

Estamos hoy dentro de la fase de inbound BSUID activo, outbound BSUID aún no abierto. Es la ventana cómoda para migrar antes de tener clientes con username.

Qué cambia en el webhook

CampoHoyPost-rollout (usuario con username)
contacts[].wa_id / messages[].fromTeléfono E.164 sin +Puede venir vacío
contacts[].user_id / messages[].from_user_idBSUID (ya viaja hoy)BSUID — único identificador garantizado
metadata.display_phone_number / phone_number_idNuestro númeroSin cambios (es del lado Rotoplas)

BSUID = Business-Scoped User ID. Formato {ISO 3166 alpha-2}.{hasta 128 alfanuméricos}. Propiedades:

  • Único por par usuario↔portafolio: el mismo humano tiene un BSUID distinto para cada portafolio de negocio.
  • Estable ante cambio de username, pero se regenera si el usuario cambia de teléfono.
  • Hay que pasarlo íntegro (prefijo + punto + ID); modificarlo hace que la petición falle.

Aclaración: la privacidad de número en Comunidades / Grupos (donde miembros no se ven el teléfono entre sí) es un feature distinto, del cliente, que no afecta mensajes directos ni la Business API.

Cuándo sigue llegando el teléfono

Meta garantiza el teléfono en el webhook cuando se cumple alguna:

  1. Nuestro negocio le mandó o llamó al usuario en los últimos 30 días (rolling, evaluado por número de negocio, no por portafolio).
  2. El usuario nos escribió o llamó en los últimos 30 días (mismas condiciones).
  3. El usuario está en el Contact Book del portafolio.

Si ninguna aplica, llega solo el BSUID.

Comportamiento del envío (outbound)

El campo to del endpoint de envío acepta teléfono O BSUID indistintamente (Meta detecta el formato). Casos:

EscenarioIdentificador que funciona
Usuario sin usernameTeléfono ✅ · BSUID ✅
Usuario con username, interacción <30 días o en Contact BookTeléfono ✅ · BSUID ✅
Usuario con username, sin interacción reciente y fuera de Contact BookBSUID obligatorio
Usuario que adoptó username de entrada y nunca compartió teléfonoBSUID obligatorio

Restricción dura: las plantillas de autenticación one-tap, zero-tap y copy-code siguen requiriendo teléfono. No aceptan BSUID. Cualquier flujo de OTP por WhatsApp queda bloqueado para usuarios que ocultaron su número.

Implicación para ALCOA+ "Atribuible"

El pilar "Atribuible" (ver tabla arriba) asumía teléfono E.164 como identificador del autor. Se ajusta así:

  • Identificador primario del cliente: BSUID (no el teléfono).
  • Teléfono: atributo opcional, persistido cuando esté disponible, usado para canales legacy (SAP, 3PL, contacto fuera de WhatsApp).
  • El header X-Customer-Code sigue siendo el código SAP del cliente. La novedad es cómo lo resolvemos a partir del webhook: por BSUID primero, teléfono como fallback.

Reglas para nuestra capa API

  1. Persistir BSUID desde el día 1. Aunque hoy el teléfono siga llegando, guardar from_user_id en cada mensaje entrante. Es la única forma de tener histórico cuando el rollout empiece.
  2. BSUID como identificador estable del contacto WhatsApp en cualquier persistencia que hagamos. Teléfono va a columna/atributo separado, nullable.
  3. Unicidad forzada por (plataforma, identificador) — y si vamos multi-tenant, sumar el business_account_id/portafolio (el BSUID es único por par usuario↔portafolio, no global).
  4. Resolución de contacto en webhook entrante (orden estricto):
    1. Match por BSUID → usar ese contacto.
    2. Si no hay match y viene teléfono → match por teléfono; si existe, actualizar el registro inyectando el BSUID recién visto (cosido oportunista).
    3. Sin match → crear contacto nuevo.
  5. Onboarding ferretero (VaB → WhatsApp): el flujo de alta debe capturar y asociar BSUID ↔ customer_code SAP en el primer turno. Si lo posponemos, un usuario con username solo se puede re-vincular cuando él vuelva a escribir.
  6. Outbound proactivo: si después de 30 días sin interacción solo nos queda BSUID, el contacto sigue siendo alcanzable por BSUID — el Contact Book de Meta resuelve los casos antes vinculados. Lo que no se puede es iniciar una conversación contra un username que el usuario nunca nos haya escrito.

Interacción con anti SIM-swapping y segundo factor

Doble impacto del rollout de usernames sobre el modelo de seguridad de HU-08:

  • Detección de cambio de SIM (Twilio Verify / Telesign): si el teléfono no está visible, esos servicios no aplican para el usuario en cuestión.
  • OTP por WhatsApp: las 3 variantes de plantilla de autenticación (one-tap, zero-tap, copy-code) requieren teléfono. Confirmado por Meta y reflejado en la documentación de Cloud API. No existe envío de OTP a un BSUID solo.

Workaround oficial: pedir teléfono explícitamente en la conversación

Meta documenta el patrón: si el negocio necesita el teléfono (p. ej., para OTP), debe pedirlo dentro de la conversación como un mensaje normal. La decisión queda con el usuario. Si lo comparte, se persiste como atributo del contacto y a partir de ahí el OTP por WhatsApp funciona; si no, ese canal queda cerrado para ese usuario y hay que ir por la rama alterna.

Implicaciones del patrón:

  • El número compartido en chat no llega vía wa_id; llega como contenido de mensaje y nosotros somos responsables de parsearlo y validarlo (E.164, MX prefix, longitud).
  • Conviene ofrecerlo como botón "Compartir mi número" vía Contact List Message en lugar de pedir tipeo libre, para minimizar error.
  • Hay que registrar el consentimiento explícito (timestamp, mensaje del usuario que lo otorga) como parte del audit trail ALCOA+ "Atribuible".

Árbol de decisión: segundo factor para acciones financieras

Acción financiera disparada (orden alto monto, aplicar crédito revolvente, cambiar destino)

├── ¿Tenemos teléfono E.164 verificado del usuario?
│   │   (no adoptó username, está en Contact Book, o lo compartió en chat con consentimiento)
│   │
│   ├── SÍ → Path rápido:
│   │   ├── OTP via plantilla de autenticación WhatsApp (one-tap preferente en Android)
│   │   └── + verificación de SIM-swap (Twilio Verify / Telesign) antes de mandar el OTP
│   │
│   └── NO → Path alterno (al menos UNO de los siguientes):
│       ├── PIN local del agente (cuenta Rotoplas del asesor, no del cliente)
│       ├── Biometría en PWA si está habilitada en el dispositivo
│       ├── Reto out-of-band: push a la app Rotoplas o llamada de back-office al asesor
│       └── Solicitar teléfono explícitamente con Contact List Message
│           ├── Si acepta → reanudar el path rápido
│           └── Si rechaza → escalar a aprobación humana (asesor regional)

Regla operativa para el diseño

  • El segundo factor universal NO puede ser OTP por WhatsApp. Debe ser algo independiente del teléfono.
  • OTP por WhatsApp queda como path acelerado opcional, disponible solo cuando el teléfono está verificado.
  • Ninguna acción financiera puede depender exclusivamente del canal WhatsApp + teléfono, porque deja desatendido al subconjunto de usuarios con username adoptado.

Pendiente con Nilo

  • Confirmar que la PWA/agente IA expone BSUID como ciudadano de primera clase en los payloads que nos manda.
  • Acordar el contrato de qué hacer cuando el agente recibe un mensaje sin teléfono pero el negocio necesita facturar a un cliente fiscal (caso: el usuario tiene RFC pero ocultó número — ¿pedir teléfono explícito al usuario en el flujo de alta?).
  • Definir el reemplazo de OTP-por-WhatsApp en el flujo de segundo factor para HU-08.

Resumen de obligaciones técnicas

Si tuvieras que tatuarte 5 reglas en la mano:

  1. Timestamps server-side, GPS server-side, nada confiable del cliente (Atribuible).
  2. Precios SIEMPRE desde SAP MDM, jamás hardcoded (Exacto).
  3. Idempotencia en toda escritura (Consistente + Original).
  4. 5 años de retención en bucket inmutable (Duradero).
  5. Auth con segundo factor para acciones financieras (anti SIM Swapping).