> ## Documentation Index
> Fetch the complete documentation index at: https://internal.softcrum.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Adaptador SMS

> Cuando esto se entregue, un tenant podrá enviar un OTP o un aviso de entrega por SMS en los países donde esté registrado para hacerlo.

> Traducción. Autoritativo: [`fs-msg-0009-sms-adapter.md`](/modules/messaging/features/fs-msg-0009-sms-adapter).

## Contexto

El SMS es el canal de mayor alcance en Latinoamérica y el de mayor fricción operativa de los que
soportamos. Se diferencia de todo otro adaptador en tres cosas que lo hacen su propia entrega:

**Necesita un vendor nuevo**, lo que exige un ADR antes del primer import (DEC-E1). **Cuesta dinero
real por mensaje**, así que un bucle descontrolado es una cuenta y no un gráfico. Y el **registro de
remitente es por país** — sender IDs alfanuméricos, short codes y long codes tienen reglas propias por
mercado, y enviar sin registro significa no-entrega silenciosa en vez de un error.

La fila del canal y el puerto existen desde el día uno (FS-MSG-0001). Solo falta el adaptador, que es
exactamente lo que DEC-E1 pretendía.

## Alcance *(normativo)*

* El adaptador SMS implementando `NotificationChannelPort`.
* `messaging.sms_sender_registrations`: por tenant, por país.
* Seguimiento de costo por mensaje, alimentando la medición.
* Conteo de segmentos con conciencia de codificación (GSM-7 versus UCS-2).
* Acuses de entrega mapeados al vocabulario estándar de estados.
* Un tope duro de gasto por tenant, independiente de la cuota de mensajes.

## Fuera de alcance *(normativo)*

* SMS entrante y conversación bidireccional. Otro producto.
* WhatsApp — F2, y otro canal pese a compartir un número.
* Elegir el proveedor. Ese es el ADR que bloquea esta feature.

## Comportamiento *(normativo)*

1. **Bloqueado hasta que exista el ADR de proveedor** (DEC-E1).
2. Enviar a un país donde el tenant no tiene registro verificado se **rechaza con error tipado**, no se
   intenta. Un envío sin registro lo descartan las operadoras en silencio, que es el peor modo de
   falla: parece que funcionó.
3. Los números se normalizan a **E.164** antes de enviar, y uno inválido falla terminalmente y suprime.
4. El largo se calcula **con conciencia de codificación**: un solo carácter acentuado cambia el
   mensaje a UCS-2 y reduce a la mitad el tamaño del segmento. La consola muestra el conteo de
   segmentos antes de enviar, porque un tenant que cree haber enviado un mensaje y pagó tres no lo va
   a considerar justo.
5. El costo por mensaje se **registra por envío** y alimenta la medición.
6. Aplica un **tope duro de gasto por tenant**, independiente de la cuota de mensajes, y detiene el
   envío en vez de facturar overage.
7. Los acuses de entrega se mapean al vocabulario estándar. Donde el proveedor no ofrezca acuse, el
   envío queda en `sent` y la limitación se documenta en vez de fingir un `delivered`.
8. El SMS está disponible **solo para el carril transaccional en F1b**. El SMS de marketing tiene
   requisitos de consentimiento por país más estrictos que el correo.

## Datos *(normativo)*

| Tabla                                | Invariantes clave                                                                                                                                    |
| ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| `messaging.sms_sender_registrations` | (`tenant_id`, `country_code`); `sender_type` alphanumeric\|short\_code\|long\_code; `sender_id`; `status` pending\|verified\|rejected; `verified_at` |

## API *(normativo)*

| Endpoint                                   | Clase      | Permiso                          | Presupuesto |
| ------------------------------------------ | ---------- | -------------------------------- | ----------- |
| `GET/POST /v1/messaging/sms-registrations` | Management | `messaging.sms.{read\|register}` | p95 \<1 s   |

## Eventos *(normativo)*

Ninguno más allá de los eventos estándar de estado.

## Criterios de aceptación *(normativo)*

1. Ningún vendor de SMS se importa hasta que su ADR esté aceptado — impuesto por la allowlist del
   lockfile.
2. Enviar a un país sin registro se rechaza con error tipado y sin llamada al proveedor.
3. Los números se normalizan a E.164; uno inválido falla terminalmente y suprime.
4. El conteo de segmentos es correcto para GSM-7 y UCS-2, probado con fixtures incluyendo un acento.
5. El costo se registra por envío y aparece en el snapshot de consumo.
6. El tope de gasto detiene el envío y no factura overage.
7. Un proveedor sin acuses deja el envío en `sent`, nunca un `delivered` inventado.
8. **Negativo:** ningún mensaje de categoría marketing se despacha por SMS en F1b.

## Ejecución

Bloqueado por el ADR de proveedor. Una vez aceptado: un archivo de adaptador más una fila de catálogo,
sin cambios en el despachador — que es el punto del puerto.

## Preguntas abiertas

| # | Pregunta                                                                            | Decide | Para                            |
| - | ----------------------------------------------------------------------------------- | ------ | ------------------------------- |
| 1 | ¿Qué proveedor, y cubre todos los países que soportamos?                            | Daniel | el ADR que bloquea este FS      |
| 2 | ¿El SMS se incluye en un plan o es siempre pago por uso, dado el costo por mensaje? | Daniel | antes del lanzamiento comercial |

## Changelog

| Versión | Fecha      | Cambio           | Por qué | Autor                  |
| ------- | ---------- | ---------------- | ------- | ---------------------- |
| 0.1.0   | 2026-08-17 | Borrador inicial | —       | daniel + claude-opus-5 |

## Registro de entrega

*Aún no implementado.*
