Enviar SMS desde Node.js: Tutorial Práctico con API REST
Aprende a integrar el envío de SMS en tus aplicaciones Node.js con ejemplos prácticos, manejo de errores y mejores prácticas.
En este tutorial te mostraremos cómo enviar SMS desde Node.js usando la API de LETEL. Cubriremos desde la configuración básica hasta ejemplos avanzados con Express.
Requisitos Previos
Antes de comenzar, asegúrate de tener:
node --version # Version 18+ recomendada
npm --version # Version 9+ Instalar Dependencias
Instala las dependencias necesarias:
const axios = require('axios');
const sendSMS = async (phone, message) => {
try {
const response = await axios.post(
process.env.LETEL_API_URL || 'https://api.letel.cl/v1/sms/send',
{ phone, message },
{
headers: {
'Authorization': `Bearer ${process.env.LETEL_API_KEY}`,
'Content-Type': 'application/json'
}
}
);
console.log('SMS enviado:', response.data);
return response.data;
} catch (error) {
console.error('Error al enviar SMS:', error.response?.data || error.message);
throw error;
}
};
// Uso
sendSMS('+56912345678', 'Hola desde Node.js'); Configuración Básica
Crea un archivo .env con tus credenciales:
# .env
LETEL_API_KEY=tu_api_key_aqui LETEL_API_URL=https://api.letel.cl/v1/sms/send
Código Básico
Ejemplo mínimo para enviar un SMS:
const axios = require('axios');
require('dotenv').config();
async function sendSMS(phone, message) {
try {
const response = await axios.post(
process.env.LETEL_API_URL,
{
phone: phone,
message: message
},
{
headers: {
'Authorization': `Bearer ${process.env.LETEL_API_KEY}`,
'Content-Type': 'application/json'
}
}
);
console.log('SMS enviado:', response.data);
return response.data;
} catch (error) {
console.error('Error al enviar SMS:', error.response?.data || error.message);
throw error;
}
}
// Ejemplo de uso
sendSMS('56912345678', 'Hola desde Node.js!'); Servicio SMS Avanzado
Clase completa con manejo de errores, reintentos y métodos útiles:
const axios = require('axios');
require('dotenv').config();
class SmsService {
constructor(apiKey, apiUrl) {
this.apiKey = apiKey;
this.apiUrl = apiUrl;
this.client = axios.create({
baseURL: this.apiUrl,
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json'
}
});
}
async send(phone, message, options = {}) {
const payload = {
phone: this.formatPhone(phone),
message,
...options
};
try {
const response = await this.client.post('/send', payload);
return {
success: true,
messageId: response.data.messageId,
status: response.data.status,
timestamp: response.data.timestamp
};
} catch (error) {
return {
success: false,
error: error.response?.data?.message || error.message
};
}
}
async sendVerificationCode(phone, code) {
const message = `Tu código de verificación LETEL es: ${code}. Válido por 10 minutos.`;
return this.send(phone, message);
}
async sendBulk(recipients) {
const results = await Promise.allSettled(
recipients.map((r) => this.send(r.phone, r.message))
);
return {
total: recipients.length,
successful: results.filter(
(r) => r.status === 'fulfilled' && r.value?.success
).length,
failed: results.filter(
(r) => r.status === 'fulfilled' && !r.value?.success
).length,
details: results
};
}
formatPhone(phone) {
// Eliminar caracteres no numéricos
let cleaned = phone.replace(/\D/g, '');
// Agregar código de país si no lo tiene
if (!cleaned.startsWith('56')) {
cleaned = '56' + cleaned;
}
return cleaned;
}
}
// Uso
const smsService = new SmsService(
process.env.LETEL_API_KEY,
process.env.LETEL_API_URL
);
// Enviar SMS simple
await smsService.send('912345678', 'Mensaje de prueba');
// Enviar código de verificación
await smsService.sendVerificationCode('912345678', '123456');
// Envío masivo
await smsService.sendBulk([
{ phone: '912345678', message: 'Hola cliente 1' },
{ phone: '987654321', message: 'Hola cliente 2' }
]); Integración con Express
Cómo crear una API REST con endpoints para enviar SMS:
const express = require('express');
const SmsService = require('./smsService');
const app = express();
app.use(express.json());
const smsService = new SmsService(
process.env.LETEL_API_KEY,
process.env.LETEL_API_URL
);
// Endpoint para enviar SMS
app.post('/api/sms/send', async (req, res) => {
const { phone, message } = req.body;
if (!phone || !message) {
return res.status(400).json({
error: 'Phone and message are required'
});
}
const result = await smsService.send(phone, message);
res.json(result);
});
// Endpoint para codigo de verificacion
app.post('/api/sms/verify', async (req, res) => {
const { phone, code } = req.body;
const result = await smsService.sendVerificationCode(phone, code);
res.json(result);
});
app.listen(3000, () => {
console.log('Server running on port 3000');
}); Manejo de Errores
Ejemplo de implementación con reintentos:
// Manejo de errores recomendado
async function sendSMSWithRetry(phone, message, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = await axios.post(
process.env.LETEL_API_URL,
{ phone, message },
{
headers: {
'Authorization': `Bearer ${process.env.LETEL_API_KEY}`,
'Content-Type': 'application/json'
},
timeout: 10000 // 10 segundos de timeout
}
);
return { success: true, data: response.data };
} catch (error) {
console.error(`Intento ${attempt} fallido:`, error.message);
// No reintentar errores de cliente (4xx)
if (error.response?.status >= 400 && error.response?.status < 500) {
return {
success: false,
error: 'Error del cliente',
details: error.response.data
};
}
// Esperar antes de reintentar (exponential backoff)
if (attempt < maxRetries) {
await new Promise(r => setTimeout(r, attempt * 1000));
}
}
}
return { success: false, error: 'Maximos reintentos alcanzados' };
} Validación de Números Telefónicos
Antes de enviar SMS, es crítico validar que el número de teléfono sea correcto. Un número inválido resultará en error y desperdiciará créditos. Aquí te mostramos cómo implementar validación robusta:
// Validador de números telefónicos para Chile
class PhoneValidator {
// Valida formato de teléfono chileno
static isValidChilePhone(phone) {
// Eliminar espacios y caracteres especiales
let cleaned = phone.replace(/\D/g, '');
// Debe empezar con código de país (56) o ser número local
if (cleaned.startsWith('56')) {
// Formato internacional: 56 + 9 dígitos = 11 total
return cleaned.length === 11;
} else {
// Formato local: 9 dígitos
return cleaned.length === 9;
}
}
// Normaliza el número al formato internacional
static normalize(phone) {
let cleaned = phone.replace(/\D/g, '');
// Si no tiene código de país, agregarlo
if (!cleaned.startsWith('56')) {
cleaned = '56' + cleaned;
}
return cleaned;
}
// Validación completa con error messages
static validate(phone) {
if (!phone || phone.trim() === '') {
return { valid: false, error: 'Número de teléfono requerido' };
}
if (!this.isValidChilePhone(phone)) {
return { valid: false, error: 'Formato de teléfono inválido. Usa 9XXXXXXXX o +569XXXXXXXX' };
}
return { valid: true, normalized: this.normalize(phone) };
}
}
// Uso en tu aplicación
const result = PhoneValidator.validate('912345678');
if (result.valid) {
await smsService.send(result.normalized, 'Tu mensaje aquí');
} else {
console.error(result.error);
} Integración con Formulario HTML
Un caso real común es capturar números de teléfono desde un formulario HTML y enviar SMS. Aquí mostramos cómo implementarlo de forma segura con validación en cliente y servidor:
// Backend: Express endpoint para enviar SMS desde formulario
const express = require('express');
const axios = require('axios');
require('dotenv').config();
const app = express();
app.use(express.json());
class PhoneValidator {
static validate(phone) {
const cleaned = phone.replace(/\D/g, '');
if (cleaned.length !== 9 && cleaned.length !== 11) {
return { valid: false, error: 'Teléfono inválido' };
}
return { valid: true, normalized: (cleaned.length === 9 ? '56' + cleaned : cleaned) };
}
}
// Endpoint para enviar SMS desde formulario
app.post('/api/contact/send-sms', async (req, res) => {
try {
const { phone, message, email } = req.body;
// Validar entrada
if (!phone || !message) {
return res.status(400).json({
error: 'Teléfono y mensaje requeridos'
});
}
const validation = PhoneValidator.validate(phone);
if (!validation.valid) {
return res.status(400).json({
error: validation.error
});
}
// Enviar SMS
const response = await axios.post(
process.env.LETEL_API_URL,
{
phone: validation.normalized,
message: message
},
{
headers: {
'Authorization': `Bearer ${process.env.LETEL_API_KEY}`,
'Content-Type': 'application/json'
},
timeout: 10000
}
);
// Guardar en logs (opcional)
console.log(`SMS enviado a ${validation.normalized} desde ${email}`);
res.json({
success: true,
messageId: response.data.messageId,
message: 'SMS enviado correctamente'
});
} catch (error) {
console.error('Error al enviar SMS:', error.message);
res.status(500).json({
error: 'Error al enviar SMS. Intenta nuevamente.'
});
}
});
app.listen(3000, () => {
console.log('Servidor listo en puerto 3000');
}); Testing y Debugging
Durante el desarrollo, necesitas probar tus envíos SMS sin gastar créditos reales. Aquí mostramos cómo hacerlo y cómo debuggear errores comunes:
// Herramientas para testing y debugging
// 1. Mock de API para testing sin gastar créditos
class MockSmsService {
async send(phone, message) {
console.log('[MOCK] Enviando SMS');
console.log('Teléfono:', phone);
console.log('Mensaje:', message);
return {
success: true,
messageId: 'mock-' + Date.now(),
status: 'delivered'
};
}
}
// 2. Usar en testing
const isMockMode = process.env.NODE_ENV === 'test';
const smsService = isMockMode
? new MockSmsService()
: new RealSmsService();
// 3. Logging detallado para debugging
function logSmsEvent(event, details) {
const timestamp = new Date().toISOString();
console.log(`[${timestamp}] SMS_${event}:`, JSON.stringify(details, null, 2));
}
// 4. Ejemplo de envío con logging
async function sendSmsWithDebug(phone, message) {
logSmsEvent('SEND_START', { phone, messageLength: message.length });
try {
const result = await smsService.send(phone, message);
logSmsEvent('SEND_SUCCESS', { phone, messageId: result.messageId });
return result;
} catch (error) {
logSmsEvent('SEND_ERROR', {
phone,
error: error.message,
status: error.response?.status,
data: error.response?.data
});
throw error;
}
}
// 5. Prueba con curl (desde terminal)
// curl -X POST http://localhost:3000/api/sms/send \
// -H "Content-Type: application/json" \
// -d '{"phone":"912345678","message":"Hola desde curl"}' Mejores Prácticas
- Nunca expongas tu API Key en código del cliente
- Usa variables de entorno (.env) para credenciales
- Implementa reintentos con exponential backoff
- Valida números de teléfono antes de enviar
- Monitorea tus envíos y costos
Integra SMS en tu App Node.js con LETEL
Ya tienes el código. Ahora necesitas un proveedor confiable. LETEL ofrece la API SMS más fácil de usar en Chile, con ejemplos en Node.js, soporte técnico dedicado y planes flexibles para crecer.
- ✓ Ejemplos completamente documentados en Node.js
- ✓ SDKs para Express, NestJS y cualquier framework
- ✓ Entrega garantizada 98%+ en Chile
- ✓ Soporte técnico en español 24/7
Conclusión
Integrar SMS en Node.js es sencillo con la API REST de LETEL. Este tutorial cubre los casos más comunes, pero puedes expandir las funcionalidades según las necesidades de tu aplicación.
¿Necesitas ayuda con la integración?
Nuestro equipo puede guiarte en la integración de SMS en Node.js. Contactar desarrolladores para resolver tus dudas.
LETEL
Expertos en telecomunicaciones y automatización empresarial
🔗 Continuá tu Aprendizaje
Después de dominar Node.js, explora estos temas relacionados:
- → Entender los detalles de la API SMS - Referencia completa de endpoints y autenticación
- → Implementar Webhooks - Recibe eventos de entrega en tiempo real
- → Ver planes y precios - Escalá según tu volumen de mensajes