Muetext logo Muetext

Puente SMS

Cómo las conversaciones llegan a números que no están en Muetext y qué puede hacer tu bot ahí.

Qué es el puente

Una persona en Muetext puede iniciar una conversación con cualquier número. Si ese número no está en Muetext, entra como participante por SMS: los mensajes de las personas salen como SMS y las respuestas vuelven a la conversación. Si después se registra con ese número, la conversación pasa a su app con todo el historial.

Los bots nunca envían SMS

Tu bot publica en conversaciones con SMS con el endpoint normal de mensajes. Esos mensajes se ven en la app pero nunca se envían por SMS: solo salen como SMS los mensajes escritos por personas. No existe un endpoint de bot que envíe SMS.

curl -X POST $BASE/api/public/v1/conversations/$CONV/messages \
  -H "Authorization: Bearer $KEY" \
  -H "Idempotency-Key: 6f1c2e0a-8b7d-4c1e-9a55-2d0f1b3c4e5f" \
  -H "content-type: application/json" \
  -d '{"body":"Borrador para Ada: el jueves a las 15 h me va bien."}'

# 201 — publicado (visible en la app, no se envía por SMS)
{ "status": "sent", "data": { "id": "…", "seq": 42, "body": "…", "created_at": "…" } }

# 200 — reintento con la misma Idempotency-Key: el mensaje original
{ "data": { "id": "…", "seq": 42, "body": "…", "created_at": "…" }, "idempotent_replay": true }

Primer contacto: la invitación

El primer mensaje de una persona a un número nuevo sale como invitación, una vez por conversación y número:

[Nombre] invited you to chat on Muetext: [enlace] . Reply STOP to opt out. "[primeros 120 caracteres]"

El enlace está firmado y ligado a esa conversación. Los siguientes mensajes salen como "Nombre: mensaje". Si el número ya tiene cuenta en Muetext, no se usa SMS.

Respuestas entrantes

El proveedor envía las respuestas a /api/channels/sms/inbound, con firma verificada (las falsas reciben 401). Cada respuesta va a la conversación que escribió a ese número más recientemente y se guarda como mensaje de texto sin sender_user_id ni sender_bot_id.

Las respuestas por SMS no disparan webhooks de bots. Léelas con ?after_seq= (o ?since=) buscando mensajes de texto con ambos remitentes en null.

curl "$BASE/api/public/v1/conversations/$CONV/messages?after_seq=42" \
  -H "Authorization: Bearer $KEY"

STOP y baja

STOP, STOPALL, UNSUBSCRIBE, CANCEL, END o QUIT detienen al instante todos los SMS a ese número. Recibe una sola confirmación; un STOP repetido no recibe otra. START, UNSTOP o YES lo reactivan. Ambos cambios se registran en el historial de consentimiento y en la conversación.

Límites

Espacio: 100 SMS al día; por encima se rechaza el envío antes de guardar el mensaje.

Por número: máximo 10 por hora y 3 seguidos sin respuesta.

Por remitente: máximo 20 invitaciones nuevas al día.

Horas de silencio: nada sale de 21 a 8 h en la zona del destinatario; se envía a las 8.

Los administradores pueden apagar los SMS; los espacios suspendidos no envían. Las llamadas REST del bot tienen sus propios límites (429 con Retry-After).

Estados de entrega

queued → sent → delivered, o failed. En la app se ve "SMS enviado" y luego "SMS entregado". Los retenidos quedan como deferred o blocked. La API de bots no expone estos estados.

Modo demo y real

Hoy Muetext funciona en modo demo: no se envían SMS reales y no cuesta nada. Los SMS se guardan en una bandeja de prueba y se marcan entregados segundos después. El responsable de Muetext activa el modo real en el servidor; tu código no cambia.

Para probar: en la app, inicia una conversación con un número inventado como +1 555 555 0199, añade tu bot, envía un mensaje y mira el estado.

Verifica tu webhook

HMAC-SHA256 de timestamp + "." + cuerpo con tu secreto, comparación en tiempo constante, rechaza más de cinco minutos.

const expected = "sha256=" + createHmac("sha256", secret).update(ts + "." + rawBody).digest("hex");
// compara con x-muetext-signature usando timingSafeEqual