{"id":744,"date":"2025-12-28T20:23:45","date_gmt":"2025-12-29T01:23:45","guid":{"rendered":"https:\/\/blog.utp.edu.co\/digital\/?p=744"},"modified":"2025-12-29T20:29:30","modified_gmt":"2025-12-30T01:29:30","slug":"envio-de-sms-desde-tu-app-tutorial-con-codigo","status":"publish","type":"post","link":"https:\/\/blog.utp.edu.co\/digital\/2025\/12\/28\/envio-de-sms-desde-tu-app-tutorial-con-codigo\/","title":{"rendered":"Envio de SMS desde tu App: Tutorial con Codigo"},"content":{"rendered":"<p><!--\n  Title: Envio de SMS desde tu App: Tutorial con Codigo\n  Target Site: \n  Target URL: \n  Source: 11-utp-sms-desde-app.md\n--><\/p>\n<p style=\"text-align: center\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-746\" src=\"https:\/\/blog.utp.edu.co\/digital\/files\/2025\/12\/Envio-de-SMS-desde-tu-App-Tutorial-con-Codigo.jpg\" alt=\"\" width=\"1600\" height=\"900\" srcset=\"https:\/\/blog.utp.edu.co\/digital\/files\/2025\/12\/Envio-de-SMS-desde-tu-App-Tutorial-con-Codigo.jpg 1600w, https:\/\/blog.utp.edu.co\/digital\/files\/2025\/12\/Envio-de-SMS-desde-tu-App-Tutorial-con-Codigo-300x169.jpg 300w, https:\/\/blog.utp.edu.co\/digital\/files\/2025\/12\/Envio-de-SMS-desde-tu-App-Tutorial-con-Codigo-1024x576.jpg 1024w, https:\/\/blog.utp.edu.co\/digital\/files\/2025\/12\/Envio-de-SMS-desde-tu-App-Tutorial-con-Codigo-768x432.jpg 768w, https:\/\/blog.utp.edu.co\/digital\/files\/2025\/12\/Envio-de-SMS-desde-tu-App-Tutorial-con-Codigo-1536x864.jpg 1536w\" sizes=\"auto, (max-width: 1600px) 100vw, 1600px\" \/><\/p>\n<h2 id=\"introduccion\">Introduccion<\/h2>\n<p>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.<\/p>\n<p>En este tutorial aprenderemos a enviar SMS desde cualquier aplicacion con ejemplos practicos de codigo.<\/p>\n<h2 id=\"requisitos-previos\">Requisitos Previos<\/h2>\n<ul>\n<li>Conocimientos basicos de programacion<\/li>\n<li>Una cuenta en un proveedor de SMS API<\/li>\n<li>Tu lenguaje de programacion preferido (mostraremos ejemplos en varios)<\/li>\n<\/ul>\n<h2 id=\"arquitectura-basica\">Arquitectura Basica<\/h2>\n<pre><code class=\"language-plaintext\">Tu Aplicacion\n      |\n      v\n   API REST  ---&gt; Proveedor SMS ---&gt; Operador ---&gt; Usuario\n      |\n      v\n  Webhook (estado de entrega)<\/code><\/pre>\n<h2 id=\"configuracion-inicial\">Configuracion Inicial<\/h2>\n<h3 id=\"paso-1-obtener-credenciales\">Paso 1: Obtener Credenciales<\/h3>\n<p>Registrate en un <a href=\"https:\/\/www.zavu.dev\/es\/sms-for-developers\" target=\"_blank\" rel=\"noopener noreferrer\">proveedor de SMS para desarrolladores<\/a> y obt\u00e9n tu API key.<\/p>\n<h3 id=\"paso-2-instalar-sdk\">Paso 2: Instalar SDK<\/h3>\n<p><strong>Node.js:<\/strong><\/p>\n<pre><code class=\"language-bash\">npm install @zavudev\/sdk<\/code><\/pre>\n<p><strong>Python:<\/strong><\/p>\n<pre><code class=\"language-bash\">pip install zavudev<\/code><\/pre>\n<p><strong>Go:<\/strong><\/p>\n<pre><code class=\"language-bash\">go get github.com\/zavudev\/zavu-go<\/code><\/pre>\n<h2 id=\"enviando-tu-primer-sms\">Enviando tu Primer SMS<\/h2>\n<h3 id=\"javascriptnodejs\">JavaScript\/Node.js<\/h3>\n<pre><code class=\"language-javascript\">import Zavudev from '@zavudev\/sdk';\n\nconst zavu = new Zavudev({\n  apiKey: process.env.ZAVUDEV_API_KEY\n});\n\nasync function enviarSMS() {\n  try {\n    const mensaje = await zavu.messages.send({\n      to: '+573001234567',\n      text: 'Hola desde mi aplicacion!'\n    });\n\n    console.log('SMS enviado:', mensaje.id);\n    console.log('Estado:', mensaje.status);\n\n    return mensaje;\n  } catch (error) {\n    console.error('Error:', error.message);\n    throw error;\n  }\n}\n\nenviarSMS();<\/code><\/pre>\n<h3 id=\"python\">Python<\/h3>\n<pre><code class=\"language-python\">from zavudev import Zavudev\nimport os\n\nzavu = Zavudev(api_key=os.environ['ZAVUDEV_API_KEY'])\n\ndef enviar_sms():\n    try:\n        mensaje = zavu.messages.send(\n            to='+573001234567',\n            text='Hola desde mi aplicacion!'\n        )\n\n        print(f'SMS enviado: {mensaje.id}')\n        print(f'Estado: {mensaje.status}')\n\n        return mensaje\n\n    except Exception as e:\n        print(f'Error: {e}')\n        raise\n\nenviar_sms()<\/code><\/pre>\n<h3 id=\"go\">Go<\/h3>\n<pre><code class=\"language-go\">package main\n\nimport (\n    \"fmt\"\n    \"os\"\n    \"github.com\/zavudev\/zavu-go\"\n)\n\nfunc main() {\n    client := zavu.NewClient(os.Getenv(\"ZAVUDEV_API_KEY\"))\n\n    mensaje, err := client.Messages.Send(&amp;zavu.MessageParams{\n        To:   \"+573001234567\",\n        Text: \"Hola desde mi aplicacion!\",\n    })\n\n    if err != nil {\n        fmt.Printf(\"Error: %v\\n\", err)\n        return\n    }\n\n    fmt.Printf(\"SMS enviado: %s\\n\", mensaje.ID)\n    fmt.Printf(\"Estado: %s\\n\", mensaje.Status)\n}<\/code><\/pre>\n<h3 id=\"php\">PHP<\/h3>\n<pre><code class=\"language-php\">&lt;?php\nrequire 'vendor\/autoload.php';\n\nuse Zavu\\Client;\n\n$client = new Client(getenv('ZAVUDEV_API_KEY'));\n\ntry {\n    $mensaje = $client-&gt;messages-&gt;send([\n        'to' =&gt; '+573001234567',\n        'text' =&gt; 'Hola desde mi aplicacion!'\n    ]);\n\n    echo \"SMS enviado: \" . $mensaje-&gt;id . \"\\n\";\n    echo \"Estado: \" . $mensaje-&gt;status . \"\\n\";\n\n} catch (Exception $e) {\n    echo \"Error: \" . $e-&gt;getMessage() . \"\\n\";\n}<\/code><\/pre>\n<h3 id=\"curl-api-rest-directa\">cURL (API REST Directa)<\/h3>\n<pre><code class=\"language-bash\">curl -X POST https:\/\/api.zavu.dev\/v1\/messages \\\n  -H \"Authorization: Bearer $ZAVUDEV_API_KEY\" \\\n  -H \"Content-Type: application\/json\" \\\n  -d '{\n    \"to\": \"+573001234567\",\n    \"text\": \"Hola desde mi aplicacion!\"\n  }'<\/code><\/pre>\n<h2 id=\"casos-de-uso-practicos\">Casos de Uso Practicos<\/h2>\n<h3 id=\"1-verificacion-de-usuario\">1. Verificacion de Usuario<\/h3>\n<pre><code class=\"language-javascript\">const crypto = require('crypto');\n\nclass VerificacionSMS {\n  constructor(client) {\n    this.client = client;\n    this.codigos = new Map(); \/\/ En produccion usar Redis\n  }\n\n  generarCodigo() {\n    return crypto.randomBytes(3).toString('hex').toUpperCase().slice(0, 6);\n  }\n\n  async enviarCodigo(telefono) {\n    const codigo = this.generarCodigo();\n\n    \/\/ Guardar codigo (expira en 5 min)\n    this.codigos.set(telefono, {\n      codigo,\n      expira: Date.now() + 5 * 60 * 1000\n    });\n\n    \/\/ Enviar SMS\n    await this.zavu.messages.send({\n      to: telefono,\n      text: `Tu codigo de verificacion es: ${codigo}. Valido por 5 minutos.`\n    });\n\n    return { enviado: true };\n  }\n\n  verificar(telefono, codigoIngresado) {\n    const datos = this.codigos.get(telefono);\n\n    if (!datos) {\n      return { valido: false, error: 'Codigo no encontrado' };\n    }\n\n    if (Date.now() &gt; datos.expira) {\n      this.codigos.delete(telefono);\n      return { valido: false, error: 'Codigo expirado' };\n    }\n\n    if (datos.codigo !== codigoIngresado) {\n      return { valido: false, error: 'Codigo incorrecto' };\n    }\n\n    this.codigos.delete(telefono);\n    return { valido: true };\n  }\n}\n\n\/\/ Uso\nconst verificacion = new VerificacionSMS(client);\nawait verificacion.enviarCodigo('+573001234567');\nconst resultado = verificacion.verificar('+573001234567', 'ABC123');<\/code><\/pre>\n<h3 id=\"2-notificaciones-de-pedidos\">2. Notificaciones de Pedidos<\/h3>\n<pre><code class=\"language-javascript\">class NotificacionesPedidos {\n  constructor(client) {\n    this.client = client;\n  }\n\n  async notificarEstado(pedido) {\n    const mensajes = {\n      confirmado: `Pedido #${pedido.id} confirmado! Total: ${pedido.total}. Preparando tu orden.`,\n      enviado: `Tu pedido #${pedido.id} ha sido enviado! Seguimiento: ${pedido.tracking}`,\n      entregado: `Pedido #${pedido.id} entregado! Gracias por tu compra.`\n    };\n\n    const texto = mensajes[pedido.estado];\n    if (!texto) return;\n\n    await this.zavu.messages.send({\n      to: pedido.cliente.telefono,\n      text: texto\n    });\n  }\n\n  async recordatorioPago(pedido) {\n    await this.zavu.messages.send({\n      to: pedido.cliente.telefono,\n      text: `Recordatorio: Tu pedido #${pedido.id} espera pago de ${pedido.total}. Completa tu compra en: ${pedido.urlPago}`\n    });\n  }\n}<\/code><\/pre>\n<h3 id=\"3-alertas-y-monitoreo\">3. Alertas y Monitoreo<\/h3>\n<pre><code class=\"language-javascript\">class AlertasSistema {\n  constructor(client, numeroAdmin) {\n    this.client = client;\n    this.numeroAdmin = numeroAdmin;\n  }\n\n  async alertaCritica(servicio, mensaje) {\n    await this.zavu.messages.send({\n      to: this.numeroAdmin,\n      text: `[ALERTA CRITICA] ${servicio}: ${mensaje}`\n    });\n  }\n\n  async reporteDiario(stats) {\n    const resumen = `\nReporte Diario:\n- Usuarios activos: ${stats.usuarios}\n- Transacciones: ${stats.transacciones}\n- Errores: ${stats.errores}\n    `.trim();\n\n    await this.zavu.messages.send({\n      to: this.numeroAdmin,\n      text: resumen\n    });\n  }\n}\n\n\/\/ Uso con monitoreo\nconst alertas = new AlertasSistema(client, '+573001234567');\n\n\/\/ En tu sistema de monitoreo\nif (cpuUsage &gt; 90) {\n  await alertas.alertaCritica('Servidor', 'CPU al 90%');\n}<\/code><\/pre>\n<h3 id=\"4-recordatorios-automaticos\">4. Recordatorios Automaticos<\/h3>\n<pre><code class=\"language-javascript\">const cron = require('node-cron');\n\nclass Recordatorios {\n  constructor(client, database) {\n    this.client = client;\n    this.db = database;\n  }\n\n  iniciar() {\n    \/\/ Recordatorios de citas cada hora\n    cron.schedule('0 * * * *', () =&gt; this.enviarRecordatoriosCitas());\n\n    \/\/ Recordatorios de renovacion cada dia a las 9 AM\n    cron.schedule('0 9 * * *', () =&gt; this.enviarRecordatoriosRenovacion());\n  }\n\n  async enviarRecordatoriosCitas() {\n    const enUnaHora = new Date(Date.now() + 60 * 60 * 1000);\n    const citas = await this.db.citas.find({\n      fecha: { $lte: enUnaHora, $gt: new Date() },\n      recordatorioEnviado: false\n    });\n\n    for (const cita of citas) {\n      await this.zavu.messages.send({\n        to: cita.paciente.telefono,\n        text: `Recordatorio: Tu cita es en 1 hora con ${cita.doctor}. Direccion: ${cita.direccion}`\n      });\n\n      await this.db.citas.update({ _id: cita._id }, { recordatorioEnviado: true });\n    }\n  }\n\n  async enviarRecordatoriosRenovacion() {\n    const enUnaSemana = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000);\n    const suscripciones = await this.db.suscripciones.find({\n      fechaRenovacion: { $lte: enUnaSemana },\n      recordatorioEnviado: false\n    });\n\n    for (const sub of suscripciones) {\n      await this.zavu.messages.send({\n        to: sub.usuario.telefono,\n        text: `Tu suscripcion vence el ${sub.fechaRenovacion.toLocaleDateString()}. Renueva ahora para mantener acceso.`\n      });\n\n      await this.db.suscripciones.update({ _id: sub._id }, { recordatorioEnviado: true });\n    }\n  }\n}<\/code><\/pre>\n<h2 id=\"manejo-de-webhooks\">Manejo de Webhooks<\/h2>\n<h3 id=\"configurar-endpoint\">Configurar Endpoint<\/h3>\n<pre><code class=\"language-javascript\">const express = require('express');\nconst crypto = require('crypto');\n\nconst app = express();\n\n\/\/ Verificar firma del webhook\nfunction verificarFirma(req, secret) {\n  const firma = req.headers['x-webhook-signature'];\n  const esperada = crypto\n    .createHmac('sha256', secret)\n    .update(JSON.stringify(req.body))\n    .digest('hex');\n\n  return firma === esperada;\n}\n\napp.post('\/webhooks\/sms', express.json(), async (req, res) =&gt; {\n  \/\/ Verificar autenticidad\n  if (!verificarFirma(req, process.env.WEBHOOK_SECRET)) {\n    return res.status(401).send('Firma invalida');\n  }\n\n  const { event, data } = req.body;\n\n  switch (event) {\n    case 'message.delivered':\n      console.log(`Mensaje ${data.messageId} entregado`);\n      await actualizarEstadoMensaje(data.messageId, 'entregado');\n      break;\n\n    case 'message.failed':\n      console.log(`Mensaje ${data.messageId} fallo: ${data.errorMessage}`);\n      await manejarFallo(data);\n      break;\n\n    case 'message.inbound':\n      console.log(`Mensaje recibido de ${data.from}: ${data.text}`);\n      await procesarMensajeEntrante(data);\n      break;\n  }\n\n  res.sendStatus(200);\n});\n\nasync function procesarMensajeEntrante(data) {\n  \/\/ Manejar respuestas automaticas\n  const texto = data.text.toLowerCase();\n\n  if (texto === 'stop' || texto === 'baja') {\n    await darDeBaja(data.from);\n  } else if (texto === 'ayuda') {\n    await zavu.messages.send({\n      to: data.from,\n      text: 'Comandos: STOP para darte de baja, AYUDA para ver opciones.'\n    });\n  }\n}<\/code><\/pre>\n<h2 id=\"mejores-practicas\">Mejores Practicas<\/h2>\n<h3 id=\"1-validacion-de-numeros\">1. Validacion de Numeros<\/h3>\n<pre><code class=\"language-javascript\">const { parsePhoneNumber, isValidPhoneNumber } = require('libphonenumber-js');\n\nfunction validarYFormatear(numero, paisDefault = 'CO') {\n  try {\n    const parsed = parsePhoneNumber(numero, paisDefault);\n\n    if (!parsed.isValid()) {\n      return { valido: false, error: 'Numero invalido' };\n    }\n\n    return {\n      valido: true,\n      formateado: parsed.format('E.164'),\n      pais: parsed.country\n    };\n  } catch (e) {\n    return { valido: false, error: 'No se pudo parsear' };\n  }\n}<\/code><\/pre>\n<h3 id=\"2-rate-limiting\">2. Rate Limiting<\/h3>\n<pre><code class=\"language-javascript\">const rateLimit = require('express-rate-limit');\n\nconst smsLimiter = rateLimit({\n  windowMs: 60 * 1000, \/\/ 1 minuto\n  max: 10, \/\/ 10 SMS por minuto\n  message: { error: 'Demasiadas solicitudes' }\n});\n\napp.post('\/api\/sms', smsLimiter, enviarSMSHandler);<\/code><\/pre>\n<h3 id=\"3-retry-con-backoff\">3. Retry con Backoff<\/h3>\n<pre><code class=\"language-javascript\">async function enviarConRetry(params, maxIntentos = 3) {\n  for (let intento = 1; intento &lt;= maxIntentos; intento++) {\n    try {\n      return await zavu.messages.send(params);\n    } catch (error) {\n      if (error.code === 'RATE_LIMITED' &amp;&amp; intento &lt; maxIntentos) {\n        await sleep(Math.pow(2, intento) * 1000);\n        continue;\n      }\n      throw error;\n    }\n  }\n}<\/code><\/pre>\n<h2 id=\"conclusion\">Conclusion<\/h2>\n<p>Enviar SMS desde tu aplicacion es mas facil que nunca con las <a href=\"https:\/\/www.zavu.dev\/es\/sms-for-developers\" target=\"_blank\" rel=\"noopener noreferrer\">APIs modernas para desarrolladores<\/a>. Ya sea para verificacion de usuarios, notificaciones o alertas, los SMS siguen siendo el canal mas confiable para comunicacion critica.<\/p>\n<p>Recuerda siempre validar numeros, implementar rate limiting y manejar errores apropiadamente para crear una experiencia robusta.<\/p>\n<h2 id=\"recursos\">Recursos<\/h2>\n<ul>\n<li>Documentacion de APIs<\/li>\n<li>Ejemplos de Codigo en GitHub<\/li>\n<li><a href=\"https:\/\/www.zavu.dev\/es\/sms-for-developers\" target=\"_blank\" rel=\"noopener noreferrer\">SMS API para Desarrolladores<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>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&#46;&#46;&#46;<\/p>\n","protected":false},"author":6487,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-744","post","type-post","status-publish","format-standard","hentry","category-sin-categoria"],"_links":{"self":[{"href":"https:\/\/blog.utp.edu.co\/digital\/wp-json\/wp\/v2\/posts\/744","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.utp.edu.co\/digital\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.utp.edu.co\/digital\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.utp.edu.co\/digital\/wp-json\/wp\/v2\/users\/6487"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.utp.edu.co\/digital\/wp-json\/wp\/v2\/comments?post=744"}],"version-history":[{"count":1,"href":"https:\/\/blog.utp.edu.co\/digital\/wp-json\/wp\/v2\/posts\/744\/revisions"}],"predecessor-version":[{"id":747,"href":"https:\/\/blog.utp.edu.co\/digital\/wp-json\/wp\/v2\/posts\/744\/revisions\/747"}],"wp:attachment":[{"href":"https:\/\/blog.utp.edu.co\/digital\/wp-json\/wp\/v2\/media?parent=744"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.utp.edu.co\/digital\/wp-json\/wp\/v2\/categories?post=744"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.utp.edu.co\/digital\/wp-json\/wp\/v2\/tags?post=744"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}