Envio de SMS desde tu App: Tutorial con Codigo

Introduccion
Integrar el envio de SMS en tu aplicacion es una de las funcionalidades mas utiles que puedes agregar. Desde verificacion de usuarios hasta notificaciones de pedidos, los SMS siguen siendo el canal de comunicacion mas confiable y universal.
En este tutorial aprenderemos a enviar SMS desde cualquier aplicacion con ejemplos practicos de codigo.
Requisitos Previos
- Conocimientos basicos de programacion
- Una cuenta en un proveedor de SMS API
- Tu lenguaje de programacion preferido (mostraremos ejemplos en varios)
Arquitectura Basica
Tu Aplicacion
|
v
API REST ---> Proveedor SMS ---> Operador ---> Usuario
|
v
Webhook (estado de entrega)
Configuracion Inicial
Paso 1: Obtener Credenciales
Registrate en un proveedor de SMS para desarrolladores y obtén tu API key.
Paso 2: Instalar SDK
Node.js:
npm install @zavudev/sdk
Python:
pip install zavudev
Go:
go get github.com/zavudev/zavu-go
Enviando tu Primer SMS
JavaScript/Node.js
import Zavudev from '@zavudev/sdk';
const zavu = new Zavudev({
apiKey: process.env.ZAVUDEV_API_KEY
});
async function enviarSMS() {
try {
const mensaje = await zavu.messages.send({
to: '+573001234567',
text: 'Hola desde mi aplicacion!'
});
console.log('SMS enviado:', mensaje.id);
console.log('Estado:', mensaje.status);
return mensaje;
} catch (error) {
console.error('Error:', error.message);
throw error;
}
}
enviarSMS();
Python
from zavudev import Zavudev
import os
zavu = Zavudev(api_key=os.environ['ZAVUDEV_API_KEY'])
def enviar_sms():
try:
mensaje = zavu.messages.send(
to='+573001234567',
text='Hola desde mi aplicacion!'
)
print(f'SMS enviado: {mensaje.id}')
print(f'Estado: {mensaje.status}')
return mensaje
except Exception as e:
print(f'Error: {e}')
raise
enviar_sms()
Go
package main
import (
"fmt"
"os"
"github.com/zavudev/zavu-go"
)
func main() {
client := zavu.NewClient(os.Getenv("ZAVUDEV_API_KEY"))
mensaje, err := client.Messages.Send(&zavu.MessageParams{
To: "+573001234567",
Text: "Hola desde mi aplicacion!",
})
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("SMS enviado: %s\n", mensaje.ID)
fmt.Printf("Estado: %s\n", mensaje.Status)
}
PHP
<?php
require 'vendor/autoload.php';
use Zavu\Client;
$client = new Client(getenv('ZAVUDEV_API_KEY'));
try {
$mensaje = $client->messages->send([
'to' => '+573001234567',
'text' => 'Hola desde mi aplicacion!'
]);
echo "SMS enviado: " . $mensaje->id . "\n";
echo "Estado: " . $mensaje->status . "\n";
} catch (Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
}
cURL (API REST Directa)
curl -X POST https://api.zavu.dev/v1/messages \
-H "Authorization: Bearer $ZAVUDEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": "+573001234567",
"text": "Hola desde mi aplicacion!"
}'
Casos de Uso Practicos
1. Verificacion de Usuario
const crypto = require('crypto');
class VerificacionSMS {
constructor(client) {
this.client = client;
this.codigos = new Map(); // En produccion usar Redis
}
generarCodigo() {
return crypto.randomBytes(3).toString('hex').toUpperCase().slice(0, 6);
}
async enviarCodigo(telefono) {
const codigo = this.generarCodigo();
// Guardar codigo (expira en 5 min)
this.codigos.set(telefono, {
codigo,
expira: Date.now() + 5 * 60 * 1000
});
// Enviar SMS
await this.zavu.messages.send({
to: telefono,
text: `Tu codigo de verificacion es: ${codigo}. Valido por 5 minutos.`
});
return { enviado: true };
}
verificar(telefono, codigoIngresado) {
const datos = this.codigos.get(telefono);
if (!datos) {
return { valido: false, error: 'Codigo no encontrado' };
}
if (Date.now() > datos.expira) {
this.codigos.delete(telefono);
return { valido: false, error: 'Codigo expirado' };
}
if (datos.codigo !== codigoIngresado) {
return { valido: false, error: 'Codigo incorrecto' };
}
this.codigos.delete(telefono);
return { valido: true };
}
}
// Uso
const verificacion = new VerificacionSMS(client);
await verificacion.enviarCodigo('+573001234567');
const resultado = verificacion.verificar('+573001234567', 'ABC123');
2. Notificaciones de Pedidos
class NotificacionesPedidos {
constructor(client) {
this.client = client;
}
async notificarEstado(pedido) {
const mensajes = {
confirmado: `Pedido #${pedido.id} confirmado! Total: ${pedido.total}. Preparando tu orden.`,
enviado: `Tu pedido #${pedido.id} ha sido enviado! Seguimiento: ${pedido.tracking}`,
entregado: `Pedido #${pedido.id} entregado! Gracias por tu compra.`
};
const texto = mensajes[pedido.estado];
if (!texto) return;
await this.zavu.messages.send({
to: pedido.cliente.telefono,
text: texto
});
}
async recordatorioPago(pedido) {
await this.zavu.messages.send({
to: pedido.cliente.telefono,
text: `Recordatorio: Tu pedido #${pedido.id} espera pago de ${pedido.total}. Completa tu compra en: ${pedido.urlPago}`
});
}
}
3. Alertas y Monitoreo
class AlertasSistema {
constructor(client, numeroAdmin) {
this.client = client;
this.numeroAdmin = numeroAdmin;
}
async alertaCritica(servicio, mensaje) {
await this.zavu.messages.send({
to: this.numeroAdmin,
text: `[ALERTA CRITICA] ${servicio}: ${mensaje}`
});
}
async reporteDiario(stats) {
const resumen = `
Reporte Diario:
- Usuarios activos: ${stats.usuarios}
- Transacciones: ${stats.transacciones}
- Errores: ${stats.errores}
`.trim();
await this.zavu.messages.send({
to: this.numeroAdmin,
text: resumen
});
}
}
// Uso con monitoreo
const alertas = new AlertasSistema(client, '+573001234567');
// En tu sistema de monitoreo
if (cpuUsage > 90) {
await alertas.alertaCritica('Servidor', 'CPU al 90%');
}
4. Recordatorios Automaticos
const cron = require('node-cron');
class Recordatorios {
constructor(client, database) {
this.client = client;
this.db = database;
}
iniciar() {
// Recordatorios de citas cada hora
cron.schedule('0 * * * *', () => this.enviarRecordatoriosCitas());
// Recordatorios de renovacion cada dia a las 9 AM
cron.schedule('0 9 * * *', () => this.enviarRecordatoriosRenovacion());
}
async enviarRecordatoriosCitas() {
const enUnaHora = new Date(Date.now() + 60 * 60 * 1000);
const citas = await this.db.citas.find({
fecha: { $lte: enUnaHora, $gt: new Date() },
recordatorioEnviado: false
});
for (const cita of citas) {
await this.zavu.messages.send({
to: cita.paciente.telefono,
text: `Recordatorio: Tu cita es en 1 hora con ${cita.doctor}. Direccion: ${cita.direccion}`
});
await this.db.citas.update({ _id: cita._id }, { recordatorioEnviado: true });
}
}
async enviarRecordatoriosRenovacion() {
const enUnaSemana = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000);
const suscripciones = await this.db.suscripciones.find({
fechaRenovacion: { $lte: enUnaSemana },
recordatorioEnviado: false
});
for (const sub of suscripciones) {
await this.zavu.messages.send({
to: sub.usuario.telefono,
text: `Tu suscripcion vence el ${sub.fechaRenovacion.toLocaleDateString()}. Renueva ahora para mantener acceso.`
});
await this.db.suscripciones.update({ _id: sub._id }, { recordatorioEnviado: true });
}
}
}
Manejo de Webhooks
Configurar Endpoint
const express = require('express');
const crypto = require('crypto');
const app = express();
// Verificar firma del webhook
function verificarFirma(req, secret) {
const firma = req.headers['x-webhook-signature'];
const esperada = crypto
.createHmac('sha256', secret)
.update(JSON.stringify(req.body))
.digest('hex');
return firma === esperada;
}
app.post('/webhooks/sms', express.json(), async (req, res) => {
// Verificar autenticidad
if (!verificarFirma(req, process.env.WEBHOOK_SECRET)) {
return res.status(401).send('Firma invalida');
}
const { event, data } = req.body;
switch (event) {
case 'message.delivered':
console.log(`Mensaje ${data.messageId} entregado`);
await actualizarEstadoMensaje(data.messageId, 'entregado');
break;
case 'message.failed':
console.log(`Mensaje ${data.messageId} fallo: ${data.errorMessage}`);
await manejarFallo(data);
break;
case 'message.inbound':
console.log(`Mensaje recibido de ${data.from}: ${data.text}`);
await procesarMensajeEntrante(data);
break;
}
res.sendStatus(200);
});
async function procesarMensajeEntrante(data) {
// Manejar respuestas automaticas
const texto = data.text.toLowerCase();
if (texto === 'stop' || texto === 'baja') {
await darDeBaja(data.from);
} else if (texto === 'ayuda') {
await zavu.messages.send({
to: data.from,
text: 'Comandos: STOP para darte de baja, AYUDA para ver opciones.'
});
}
}
Mejores Practicas
1. Validacion de Numeros
const { parsePhoneNumber, isValidPhoneNumber } = require('libphonenumber-js');
function validarYFormatear(numero, paisDefault = 'CO') {
try {
const parsed = parsePhoneNumber(numero, paisDefault);
if (!parsed.isValid()) {
return { valido: false, error: 'Numero invalido' };
}
return {
valido: true,
formateado: parsed.format('E.164'),
pais: parsed.country
};
} catch (e) {
return { valido: false, error: 'No se pudo parsear' };
}
}
2. Rate Limiting
const rateLimit = require('express-rate-limit');
const smsLimiter = rateLimit({
windowMs: 60 * 1000, // 1 minuto
max: 10, // 10 SMS por minuto
message: { error: 'Demasiadas solicitudes' }
});
app.post('/api/sms', smsLimiter, enviarSMSHandler);
3. Retry con Backoff
async function enviarConRetry(params, maxIntentos = 3) {
for (let intento = 1; intento <= maxIntentos; intento++) {
try {
return await zavu.messages.send(params);
} catch (error) {
if (error.code === 'RATE_LIMITED' && intento < maxIntentos) {
await sleep(Math.pow(2, intento) * 1000);
continue;
}
throw error;
}
}
}
Conclusion
Enviar SMS desde tu aplicacion es mas facil que nunca con las APIs modernas para desarrolladores. Ya sea para verificacion de usuarios, notificaciones o alertas, los SMS siguen siendo el canal mas confiable para comunicacion critica.
Recuerda siempre validar numeros, implementar rate limiting y manejar errores apropiadamente para crear una experiencia robusta.
Recursos
- Documentacion de APIs
- Ejemplos de Codigo en GitHub
- SMS API para Desarrolladores