Números comerciales y menús telefónicos para Estados Unidos y Canadá. ENFR(510) 288-6288[email protected]Iniciar sesión

Inicio › Twilio › Lista de producción

Twilio

La lista de producción de Twilio que los tutoriales omiten.

Todo tutorial de voz de Twilio termina cuando suena el teléfono. Ahí empieza el trabajo de verdad: un menú telefónico es un punto de acceso público que gasta dinero por minuto, graba a las personas y falla en silencio. Esta es la lista que querríamos ver cumplida antes de que un cliente real marque el número, con la documentación de Twilio citada en cada punto y código donde el código explica mejor.

Revisado el 26 de octubre de 2026 · 38 fuentes citadas · 32 min de lectura

A production checklist for a voice app

Para qué sirve esta lista

La aplicación que tenemos en mente es la de siempre: un número comercial que contesta con un saludo, ofrece un menú corto, desvía al llamante al celular de alguien y toma un mensaje de voz cuando nadie contesta. En Twilio Programmable Voice eso son unos cuantos webhooks que devuelven TwiML. Funciona en una tarde, y ese es el problema: también parece terminado en una tarde.

Lo que separa esa demostración de algo que usted puede poner en una camioneta de trabajo no tiene gloria. ¿Quién más puede llamar a sus webhooks? ¿Qué oye el llamante cuando su servidor está caído? ¿Quién se entera? ¿Qué impide que una credencial comprometida o una regla de desvío fraudulenta genere una factura de cinco cifras en un fin de semana? ¿A dónde van los mensajes de voz y cuándo se borran? Esta página recorre esas preguntas en el orden en que las abordaríamos.

Todo lo específico de Twilio que aparece abajo está citado a la documentación de Twilio, a sus páginas de precios o al código fuente de su biblioteca auxiliar, tal como se leyeron el 26 de octubre de 2026. Cuando la documentación guarda silencio, lo decimos en lugar de rellenar el vacío. Las opiniones están señaladas. El código es Node.js con el paquete oficial twilio (6.x) y, cuando ayuda, Python con twilio 9.x; ambos son bocetos para adaptar, no servicios listos para usar.

La lista de verificación

La tabla es el resumen; cada fila enlaza a su explicación. "Si lo omite" es lo que ocurre por defecto, hasta donde lo dice la documentación.

#PuntoEstá listo cuandoSi lo omite
1Validar X-Twilio-SignatureTodas las rutas que Twilio llama, incluidas las devoluciones de estado y de grabación, rechazan las solicitudes sin firma con el validador oficialCualquiera que conozca una URL puede manejar su menú, falsificar registros de llamadas o activar su controlador de suspensión
2URL de respaldovoice_fallback_url apunta a TwiML estático en una infraestructura distinta que sigue desviando y tomando mensajesSi el servidor se cae, las llamadas fallan y no hay nada a lo que recurrir
3Tiempos de espera y reintentosLos webhooks de voz responden en mucho menos de 15 segundos; el trabajo lento sale de la solicitudTwilio reintenta una vez, y solo ante fallas de conexión; después se rinde
4Devoluciones de estado y registro de llamadasEl estado final de cada llamada y el DialCallStatus de cada desvío llegan a su propia base de datosDepende de la Consola, cuya búsqueda en el Debugger cubre 30 días
5Alarmas y webhook de erroresUna alarma ante cualquier error (ventana de 5 minutos) envía un correo a una persona y publica en su webhook de localizadorLos errores se acumulan en el Debugger y nadie se entera
6Voice InsightsAlguien revisa los paneles con regularidad; Advanced Features activado si necesita métricas por llamada a través de la APIQuejas de "la línea se oye mal" sin datos, y 30 días de historial como máximo
7Permisos geográficosSolo están habilitados los países a los que usted desvía; los rangos de alto riesgo siguen apagadosUna cuenta comprometida o un error de desvío a cualquier número puede llamar a rangos de tarifa especial
8Triggers de usoUn trigger de gasto diario por subcuenta que le avisa y suspende la subcuenta automáticamenteSin tope: el consumo sigue hasta que el saldo queda en negativo
9API keys, no el auth tokenLas aplicaciones usan API keys Standard o Restricted; el auth token solo está donde se validan las firmas; usted ya ensayó la rotaciónUn solo secreto filtrado da control total de la cuenta
10Una subcuenta por clienteLos números, el consumo y las grabaciones de cada cliente viven en su propia subcuentaEl fraude o la solicitud de eliminación de un cliente afecta a todos
11Retención y eliminación de grabacionesLos mensajes de voz se copian fuera (o no) y luego se eliminan según un calendario escritoLas grabaciones se acumulan y se cobra su almacenamiento cada mes
12Cifrado de grabacionesDecidido; y si está activo, la clave privada tiene respaldo y acceso controladoGrabaciones legibles por cualquiera con acceso a la cuenta
13Datos de los llamantes canadiensesEl aviso de privacidad indica que los datos pueden procesarse fuera de Canadá; evaluación de Québec redactada si atiende a QuébecUna brecha en sus obligaciones bajo PIPEDA y la Ley 25
14HIPAA y PCIBAA firmado en una edición elegible antes de manejar cualquier PHI; PCI Mode comprendido antes de activarloPHI en una cuenta sin BAA
15Límites de frecuencia y reintentosLas llamadas REST retroceden ante un 429; los controladores son idempotentesLas ráfagas fallan; las devoluciones reintentadas crean filas duplicadas
16PruebasWebhooks falsos firmados en CI; credenciales de prueba para las rutas REST; un número de ensayo para el restoLa validación se apaga en las pruebas y, con el tiempo, en producción
17Llamadas de prueba sintéticasUna llamada real programada recorre el menú y avisa cuando falla un pasoSe entera de que el menú está roto por un cliente
18Modelo de costosUn costo por llamada que cuenta los dos tramos de un desvío, TTS, grabación y almacenamientoLa factura es una sorpresa, casi siempre por los desvíos

Deslice la tabla hacia los lados para ver todas las columnas.

1. Valide la firma en cada webhook

Su URL de voz es un punto de acceso HTTPS público. Twilio no la llama desde un conjunto fijo de direcciones: la documentación dice que Twilio "not having a fixed range of IP addresses that issue webhooks" (no tiene un rango fijo de direcciones IP que emitan webhooks),1 así que una lista de IP permitidas no es el control. El control es la firma. En cada solicitud, Twilio calcula un HMAC-SHA1 "using your account auth token as the secret key" (usando el auth token de su cuenta como clave secreta) sobre la URL del webhook con los parámetros POST "sorted alphabetically" (ordenados alfabéticamente) y anexados, y lo envía en X-Twilio-Signature.1

Twilio es directo sobre la implementación: "Twilio recommends using the provided signature validation library from a Twilio SDK" y "Don't implement your own signature validation" (recomienda usar la biblioteca de validación de firmas de un SDK de Twilio y no implementar su propia validación).1 En Node, el middleware de Express twilio.webhook() lo hace. Leído en el código fuente de la biblioteca, su comportamiento es este: la validación está activa por defecto; una solicitud sin encabezado de firma recibe un 400; una solicitud cuya firma no coincide recibe "a text body and a 403" (un cuerpo de texto y un 403); y si no hay auth token configurado devuelve un 500 en lugar de dejar pasar la solicitud.2 Lee el token de TWILIO_AUTH_TOKEN a menos que usted le pase uno.2

// npm install express twilio   (twilio-node 6.x)
const express = require('express');
const twilio = require('twilio');
const { VoiceResponse } = twilio.twiml;

const app = express();
app.use(express.urlencoded({ extended: false })); // the middleware needs the parsed form body

// Tell the validator the URL exactly as Twilio has it configured. Behind a proxy or
// load balancer that terminates TLS, your app sees http:// and an internal host name,
// and every signature fails unless you pin these.
const twilioOnly = twilio.webhook({ protocol: 'https', host: 'ivr.example.com' });

app.post('/voice', twilioOnly, (req, res) => {
  const vr = new VoiceResponse();
  const menu = vr.gather({ numDigits: 1, timeout: 6, action: '/menu' });
  menu.play('https://cdn.example.com/audio/greeting.mp3');
  vr.redirect('/voicemail');            // no key pressed: go to voicemail
  res.type('text/xml').send(vr.toString());
});

// The same middleware goes on EVERY route Twilio calls:
// /menu, /dial-result, /voicemail, /events/call-status, /events/recording, /usage-alarm ...

En Python el equivalente es RequestValidator, cuya firma de método es validate(uri, params, signature) y que acepta directamente el formulario multivalor de Flask.3

# pip install flask twilio   (twilio-python 9.x)
import os
from functools import wraps
from flask import Flask, request, abort
from twilio.request_validator import RequestValidator

app = Flask(__name__)
validator = RequestValidator(os.environ["TWILIO_AUTH_TOKEN"])
PUBLIC_BASE = "https://ivr.example.com"   # scheme + host exactly as configured in Twilio

def twilio_only(view):
    @wraps(view)
    def wrapped(*args, **kwargs):
        qs = request.query_string.decode()          # raw, still percent-encoded
        url = PUBLIC_BASE + request.path + ("?" + qs if qs else "")
        signature = request.headers.get("X-Twilio-Signature", "")
        if not validator.validate(url, request.form, signature):
            abort(403)
        return view(*args, **kwargs)
    return wrapped

Las formas en que esto sale mal en producción tienen que ver con la URL, porque la firma la cubre:

  • TLS terminado antes de su aplicación. El tutorial de Twilio advierte que la validación falla cuando la URL configurada es https:// pero el SSL se termina antes de llegar a su aplicación, porque la URL que ve su aplicación no es la que Twilio solicitó.4 Fije protocol y host (o pase la opción url completa) como arriba.2
  • Cadenas de consulta recodificadas. Use "the exact URL from Twilio including any URL-encoded characters" (la URL exacta de Twilio, con los caracteres codificados); "If you decode or re-encode the URL, signature validation fails" (si decodifica o recodifica la URL, la validación de la firma falla).1 Por eso el boceto de Python usa la cadena de consulta sin procesar.
  • Connection overrides. Si agrega a la URL de un webhook ajustes del estilo #rt=... (siguiente sección), omita ese fragmento al validar.5
  • Puertos. El validador de Node ya prueba la URL con y sin el puerto, "since that is the string Twilio signed" (porque esa es la cadena que Twilio firmó).2 No agregue sus propios malabares con puertos encima.
  • Cuerpos JSON. Los webhooks de voz se codifican como formulario, pero si un producto envía JSON, Twilio agrega un parámetro de consulta bodySHA256 y el validateRequestWithBody del SDK también comprueba el hash del cuerpo.1

Otras dos capas son baratas. Twilio "supports HTTP Basic and Digest Authentication" (admite autenticación HTTP Basic y Digest) en las URL de los webhooks,1 lo que le da un segundo secreto independiente. Y Twilio "won’t connect to an HTTPS URL with a self-signed certificate" (no se conecta a una URL HTTPS con un certificado autofirmado),1 así que use un certificado real desde el principio en vez de descubrirlo el día del lanzamiento.

Nuestra opinión: las rutas de devolución de estado, de devolución de grabación y de triggers de uso importan tanto como la ruta del menú. Son las que escriben en su base de datos o, en el controlador de gasto que aparece más abajo, suspenden una cuenta. Una sin validar es una forma de que un desconocido falsifique sus registros o lo desconecte.

2–3. Cuando su webhook se cae: URL de respaldo, tiempos de espera y reintentos

Toda llamada entrante comienza con Twilio obteniendo TwiML de su voice_url. El número telefónico también tiene una voice_fallback_url, que es "The URL that we call when an error occurs retrieving or executing the TwiML requested by url" (la URL a la que llamamos cuando ocurre un error al obtener o ejecutar el TwiML solicitado en url), y un voice_fallback_method de GET o POST.6 La página de solución de problemas de Twilio para el error 11200 (HTTP retrieval failure) da el consejo que importa: configure una URL de respaldo "ideally hosted on separate infrastructure" (idealmente alojada en una infraestructura distinta).7 Un respaldo en el mismo servidor que acaba de fallar es decoración.

Conozca el reloj. Los valores predeterminados de Twilio son 5,000 ms de tiempo de conexión, 15,000 ms de tiempo de lectura y 15,000 ms en total; el número de reintentos predeterminado es 1 y la política de reintentos predeterminada es ct, es decir, Twilio reintenta "only on TCP connect or TLS handshake failures" (solo ante fallas de conexión TCP o de negociación TLS).5 Un 500 lento no se reintenta por defecto. Para voz hay además un techo: Twilio "enforces a hard 15-second timeout on all call-related HTTP requests" (impone un límite estricto de 15 segundos a todas las solicitudes HTTP relacionadas con llamadas), que prevalece sobre otros ajustes.5 La página del 11200 enumera "Your server takes too long to respond" (su servidor tarda demasiado en responder) entre las causas y recomienda responder de inmediato cuando el procesamiento es lento.7 El llamante está ahí en silencio mientras usted piensa; en nuestra opinión, el webhook de un menú debe responder en mucho menos de un segundo, con las escrituras en la base de datos y las consultas al CRM movidas a una cola.

Puede ajustar esto por URL con un fragmento, por ejemplo https://example.com/foo#ct=1000&rt=5000&rp=ct,rt; las opciones incluyen ct, rt, tt, rc (0 a 5), rp (4xx, 5xx, ct, rt, all) y e para la ubicación edge de Twilio, y funcionan en los webhooks de voz con sujeción al límite de 15 segundos.5 Acortar rt en la URL principal hace que un servidor colgado pase al respaldo antes, en lugar de gastar los 15 segundos completos. Nuestra opinión: reintentar ante 5xx solo es seguro si el controlador es idempotente (vea límites de frecuencia).

Qué debe hacer el respaldo. El respaldo robusto más simple es un archivo TwiML estático en otro proveedor (almacenamiento de objetos o una CDN), obtenido con GET porque los alojamientos estáticos suelen atender solo GET. Debe hacer lo único que importa, que es llegar a una persona o tomar un mensaje, sin nada de la lógica de su aplicación:

<?xml version="1.0" encoding="UTF-8"?>
<!-- https://static.example.net/ivr/fallback.xml -->
<Response>
  <Say>Thanks for calling. Connecting you now.</Say>
  <Dial timeout="25">
    <Number>+15145550142</Number>
  </Dial>
  <Say>Sorry, nobody is available. Please leave a message after the tone.</Say>
  <Record maxLength="120" action="https://static.example.net/ivr/fallback-bye.xml" method="GET" />
</Response>

Aquí el action de <Record> no es opcional. Sin él, "<Record> will request the current document’s URL" (<Record> solicitará la URL del documento actual), algo que según Twilio "can lead to unwanted looping behavior" (puede provocar bucles no deseados).21 Apúntelo a un segundo archivo estático que se despida y cuelgue. Si <Dial> no tiene action, Twilio pasa al siguiente verbo cuando termina la llamada marcada,9 que es lo que lleva un desvío sin respuesta al aviso del buzón de voz. El mensaje igualmente llega a las Recordings de la cuenta, así que no se pierde nada mientras su servidor está caído.

Configure ambas URL con Twilio CLI, cuyo comando phone-numbers:update tiene las opciones --voice-url, --voice-fallback-url y --voice-fallback-method:34

twilio phone-numbers:update +15145550199 \
  --voice-url https://ivr.example.com/voice \
  --voice-fallback-url https://static.example.net/ivr/fallback.xml \
  --voice-fallback-method GET

Después pruébelo de la única forma honesta: apunte voice_url a una dirección que rechace conexiones, llame al número y confirme que llega al celular y luego al aviso del buzón de voz.

4. Devoluciones de estado y su propio registro de llamadas

La Consola le mostrará las llamadas, pero un servicio en producción necesita su propio registro: para responder "¿la llamada de ese cliente llegó a alguien el martes?", para facturar y para alertar. Tres devoluciones le dan casi todo.

  • El status_callback del número: "The URL we call using the status_callback_method to send status information to your application." (la URL a la que llamamos con status_callback_method para enviar información de estado a su aplicación).6 Para las llamadas que usted realiza por la API, elige los eventos con StatusCallbackEvent (initiated, ringing, answered, completed), y "If no event is specified, we send the completed status." (si no se especifica ningún evento, enviamos el estado completed).8 La carga incluye CallSid, From, To, Direction, CallStatus, Timestamp y SequenceNumber; CallDuration está presente "only in terminal events" (solo en los eventos finales).8
  • La URL action de <Dial>, solicitada "after the dialed call ends" (cuando termina la llamada marcada), con un DialCallStatus de completed, answered, busy, no-answer, failed o canceled y el DialCallSid del nuevo tramo.9 Este es el evento que le dice si un desvío llegó a una persona, algo que el estado de la llamada principal no indica.
  • recordingStatusCallback en <Record>, solicitado cuando la grabación está disponible, con los eventos in-progress, completed y absent (predeterminado completed).21 Ese es su disparador de "mensaje de voz nuevo".
// Forward, then log the outcome and fall through to voicemail when nobody answered.
app.post('/menu', twilioOnly, (req, res) => {
  const vr = new VoiceResponse();
  if (req.body.Digits === '1') {
    const dial = vr.dial({ timeout: 20, action: '/dial-result', answerOnBridge: true });
    dial.number('+15145550142');
  } else {
    vr.redirect('/voicemail');
  }
  res.type('text/xml').send(vr.toString());
});

app.post('/dial-result', twilioOnly, async (req, res) => {
  await events.insert({
    callSid: req.body.CallSid, kind: 'dial', status: req.body.DialCallStatus,
    childSid: req.body.DialCallSid || null,
  });
  const vr = new VoiceResponse();
  if (req.body.DialCallStatus !== 'completed') vr.redirect('/voicemail');
  else vr.hangup();
  res.type('text/xml').send(vr.toString());
});

// Final status for every call on the number (set as the number's status_callback).
app.post('/events/call-status', twilioOnly, async (req, res) => {
  const b = req.body;
  // Unique key on (callSid, kind, status) so a retried callback is a no-op.
  await events.insertIgnoreDuplicate({
    callSid: b.CallSid, kind: 'call', status: b.CallStatus, from: b.From, to: b.To,
    durationS: b.CallDuration ? Number(b.CallDuration) : null, at: b.Timestamp || null,
  });
  res.sendStatus(200);
});

Dos detalles de la referencia de <Dial> importan para un menú que desvía llamadas. El timeout predeterminado es de 30 segundos, y "Twilio always adds a five-second timeout buffer" (Twilio siempre agrega un margen de cinco segundos), así que un timeout de 20 segundos suena unos 25.9 Fíjelo por debajo del momento en que contesta el buzón de voz del operador del celular, o sus llamantes dejarán mensajes en un buzón personal en lugar del suyo. Y answerOnBridge="true" mantiene sonando la llamada entrante hasta que contesta el número marcado cuando <Dial> es el primer verbo.9

Puede asociar la devolución de estado al número con la biblioteca auxiliar (client.incomingPhoneNumbers(sid).update({ statusCallback: ..., statusCallbackMethod: 'POST' })) como parte del mismo script de aprovisionamiento que fija las URL de voz y de respaldo, de modo que a un número recién comprado nunca le falte.

5. El Debugger, las alarmas y el webhook de errores

El Debugger de Twilio (Consola, Monitor > Debugger) enumera eventos con nivel, código de error, origen y descripción; "Warnings mean Twilio could still process the request, and errors mean it couldn’t" (las advertencias significan que Twilio aún pudo procesar la solicitud, y los errores que no pudo), y su búsqueda llega a "event data from within the last 30 days" (datos de eventos de los últimos 30 días).10 También puede enviar los errores a su propio punto de acceso: "To configure error webhooks, go to Monitor > Error webhook." (para configurar los webhooks de errores, vaya a Monitor > Error webhook).10 Ese es el flujo que conviene conectar a lo que ya le envía alertas.

Las alarmas agregan umbrales. "Monitor for specific error codes or error types" (vigilan códigos o tipos de error específicos; cualquier error, cualquier advertencia o ambos), se activan cuando la cantidad supera su umbral en una ventana de 5 minutos, 15 minutos, 1 hora, 12 horas o 24 horas, y notifican en 15 segundos por correo, por un POST a su webhook, o ambos.11 El webhook trae ErrorCode, CurrentValue, TriggerValue, TimePeriod y un IdempotencyToken para eliminar duplicados.11

Hay dos límites fáciles de pasar por alto y ambos importan en una configuración con varios clientes: las alarmas "are only available in the US1 region" (solo están disponibles en la región US1) y "don’t aggregate from subaccounts into parent accounts" (no se agregan de las subcuentas a las cuentas principales).11 Si usted da a cada cliente una subcuenta, cada subcuenta necesita sus propias alarmas, creadas por el mismo script de aprovisionamiento que crea la subcuenta.

Nuestra opinión sobre un conjunto inicial razonable: una alarma para el error 11200 (falla al obtener el webhook7) con umbral de 1 en 5 minutos, porque en una línea de voz cada ocurrencia es un llamante que acaba de caer en su respaldo; y una alarma de "cualquier error" con un umbral modesto en una hora para atrapar lo que no se le ocurrió.

6. Voice Insights para la calidad de las llamadas

Los errores no son la única falla. Las llamadas que se conectan pero se oyen mal generan quejas y ningún código de error. Voice Insights "provides call quality analytics and aggregation tools for investigating Twilio calls and conferences" (ofrece analítica de calidad de llamadas y herramientas de agregación para investigar llamadas y conferencias de Twilio), con paneles a nivel de cuenta sobre volumen, duración, conectividad y calidad de audio, y un Call Summary por llamada con "call metadata, connection parameters, and quality indicators" (metadatos de la llamada, parámetros de conexión e indicadores de calidad).12

Los recursos REST de métricas y eventos, la exploración de series de tiempo y los flujos de eventos están detrás de Advanced Features, que "are available at an additional cost to regular call charges" (tienen un costo adicional a los cargos normales de llamadas);12 la página de precios de EE. UU. enumera Voice Insights Advanced Features a $0.0024 por minuto.37 Lo que active, "Voice Insights data is available for calls or conferences made within the last 30 days" (los datos de Voice Insights están disponibles para llamadas o conferencias de los últimos 30 días).12

Nuestra opinión: para una línea pequeña de menú y desvío bastan los paneles gratuitos revisados cada semana, más el Call Summary cuando llega una queja concreta. Active Advanced Features cuando necesite datos de calidad en sus propios sistemas, y exporte lo que quiera conservar más allá de la ventana de 30 días.

7. Permisos geográficos: bloquee el fraude telefónico antes de que empiece

Un menú telefónico de entrada parece no tener nada que robar. Sí lo tiene: cada desvío es una llamada saliente que se le factura a usted. La guía antifraude de Twilio dice de Programmable Voice que los cargos del fraude telefónico "are billed to the owner of the calling number — so if it’s your number, you’re the victim of the fraud" (se facturan al titular del número que llama; si es su número, usted es la víctima del fraude), y que "Charges are by the minute, so the longer the duration of each call, the more the fraudster will earn from it" (los cargos son por minuto, así que cuanto más dura cada llamada, más gana el estafador).14 El patrón es el International Revenue Sharing Fraud, en el que las llamadas se encaminan a números de tarifa especial de los que el estafador se beneficia; Twilio calcula las pérdidas de toda la industria en "$10 billion" (10 mil millones de dólares) al año.15

El control son los Voice Dialing Geographic Permissions, que se aplican a Programmable Voice y a Elastic SIP Trunking: usted habilita o deshabilita cada país y, por separado, los rangos de números de alto riesgo dentro de él.15 La recomendación de Twilio es "restrict calling only to countries you expect to call, if any, and block all others" (restringir las llamadas solo a los países a los que espera llamar, si los hay, y bloquear todos los demás).14 "Only Owner and Administrator roles can update Geographic Permissions" (solo los roles Owner y Administrator pueden actualizar los permisos geográficos), y una subcuenta nueva "inherits Geo Permissions from the Master Project" (hereda los permisos geográficos del proyecto principal) a menos que usted desactive la herencia para ella.15

Para un negocio de EE. UU. o Canadá que desvía a celulares del personal, eso suele significar Estados Unidos y Canadá habilitados, rangos de alto riesgo apagados y nada más. En las páginas que leímos no encontramos una indicación de qué países vienen habilitados por defecto en una cuenta nueva, así que revise la suya en lugar de suponerlo.

La regla de diseño que importa más que el ajuste

Nunca use <Dial> con un número que provenga del llamante (dígitos que ingresó, un campo "llámeme a este número", un número en un CRM que un cliente puede editar) sin compararlo con una lista de destinos permitidos a los que realmente desvía. Los permisos geográficos son la red de seguridad; la lista permitida en su código es el control.

Las reglas de callerId en <Dial> forman parte de la misma higiene: en una llamada normal puede ser el número del llamante o el número llamado de la solicitud de Twilio, un número de Twilio que usted compró, o un número verificado con Twilio.9 Pasar el número del llamante original es lo que permite al personal ver en su celular quién llama.

8. Triggers de uso: lo más parecido a un tope de gasto

En la documentación que leímos, Twilio no describe ningún límite de gasto estricto en una cuenta. El mecanismo más cercano de la guía antifraude son los triggers de uso,14 que avisan en lugar de bloquear: un UsageTrigger "is a webhook that notifies your application of usage thresholds" (es un webhook que notifica a su aplicación de umbrales de uso), evaluado "about once a minute" (aproximadamente una vez por minuto), que se activa según count, usage o price, con recurrencia diaria, mensual o anual.13 En el otro extremo, la guía de respuesta al fraude de Twilio dice "If your account balance becomes negative or you have overdue payments, your account will be automatically suspended" (si el saldo de su cuenta queda en negativo o tiene pagos vencidos, su cuenta se suspenderá automáticamente) y que Twilio "does not often suspend right at zero balance" (no suele suspender justo en saldo cero).16 Entre esos dos puntos, el medidor sigue corriendo.

Así que construya usted el tope. El ejemplo de Twilio es "suspend a subaccount in response to a usage trigger being fired for spending more than $30 per day" (suspender una subcuenta en respuesta a un trigger de uso activado por gastar más de $30 al día).14 Una cuenta suspendida "can’t make or receive phone calls" (no puede hacer ni recibir llamadas),20 lo cual es drástico para una línea comercial, así que fije el umbral bastante por encima de un mal día legítimo y avise a una persona con uno más bajo.

// Provisioning: two daily price triggers on a customer's subaccount.
const main = twilio(process.env.TWILIO_ACCOUNT_SID, process.env.TWILIO_AUTH_TOKEN);
const sub = main.api.v2010.account(customer.subaccountSid);

await sub.usage.triggers.create({
  usageCategory: 'totalprice', triggerBy: 'price', recurring: 'daily',
  triggerValue: '10', callbackUrl: 'https://ivr.example.com/usage-alarm?action=page',
});
await sub.usage.triggers.create({
  usageCategory: 'totalprice', triggerBy: 'price', recurring: 'daily',
  triggerValue: '40', callbackUrl: 'https://ivr.example.com/usage-alarm?action=suspend',
});

// Handler: validated like every other Twilio webhook.
app.post('/usage-alarm', twilioOnly, async (req, res) => {
  const { AccountSid, CurrentValue, TriggerValue, IdempotencyToken } = req.body;
  if (await seen(IdempotencyToken)) return res.sendStatus(200);
  await pager.send('Twilio spend ' + CurrentValue + ' passed ' + TriggerValue + ' on ' + AccountSid);
  if (req.query.action === 'suspend' && AccountSid !== process.env.TWILIO_ACCOUNT_SID) {
    await main.api.v2010.accounts(AccountSid).update({ status: 'suspended' });
  }
  res.sendStatus(200);
});

Notas sobre ese boceto. Los nombres de parámetros (usageCategory, triggerValue, callbackUrl, triggerBy, recurring) y los campos de la devolución (CurrentValue, TriggerValue, IdempotencyToken) provienen de la referencia de UsageTrigger de Twilio, cuyos ejemplos usan totalprice como categoría; "A trigger will only fire once during each period" (un trigger solo se activa una vez en cada período), y los períodos recurrentes se miden en GMT.13 La llamada de suspensión usa deliberadamente las credenciales de la cuenta principal: una API key Standard tiene acceso a todo "except for Accounts" (salvo Accounts) y Keys,17 por lo que no puede suspender nada. La protección evita que el controlador suspenda la cuenta principal, lo que dejaría fuera de servicio a todas las subcuentas.20 Y el retraso de evaluación es real: "It can take some amount of time for the data used by usage triggers to be reflected" (puede pasar un tiempo hasta que se reflejen los datos que usan los triggers de uso).13 Trate los triggers como si llegaran con minutos de retraso, no al instante.

Nuestra opinión sobre la recarga automática: evita que una línea ocupada se suspenda por saldo cero, lo cual conviene, pero durante un ataque también sigue financiándolo. Mantenga el monto de recarga modesto y asegúrese de que el correo de notificación de recarga llegue a una persona que lo lea.

9. API keys, el auth token y la rotación

Twilio advierte: "Anyone who has your account SID and your auth token can make an API request for your account" (cualquiera que tenga el SID de su cuenta y su auth token puede hacer una solicitud de API a nombre de su cuenta).14 Llama a las API keys "the preferred way to authenticate with Twilio’s REST APIs" (la forma preferida de autenticarse con las API REST de Twilio) y ofrece tres tipos: Main ("Full access to all Twilio API resources. Equivalent to using your Account SID and Auth Token", es decir, acceso total a todos los recursos de la API, equivalente a usar el Account SID y el Auth Token), Standard (todo salvo los recursos Accounts y Keys) y Restricted ("Customized, fine-grained access to specific Twilio API resources", acceso personalizado y detallado a recursos específicos).17 "If a key is compromised or no longer used, revoke it" (si una clave está comprometida o ya no se usa, revóquela).17

En twilio-node, autenticarse con una clave significa pasar el SID y el secreto de la clave más el SID de la cuenta: el cliente lanza un error si el primer argumento es un SID de clave SK sin la opción accountSid.18

const client = twilio(process.env.TWILIO_API_KEY_SID, process.env.TWILIO_API_KEY_SECRET, {
  accountSid: process.env.TWILIO_ACCOUNT_SID,
});

El detalle que define todo el diseño: las firmas de los webhooks se calculan con el auth token,1 de modo que los procesos que validan webhooks deben tener el auth token sin importar cómo autentique las llamadas REST. La división que recomendamos es dar a su capa web el auth token solo para validar, dar a todo lo que llame a la API REST una clave Standard o Restricted, y reservar una clave Main o el auth token para las pocas operaciones a nivel de cuenta (suspender subcuentas, crear claves).

Rotación. El auth token tiene uno principal y uno secundario; al promover el secundario "deletes the current primary Auth Token and promotes the secondary Auth Token to primary" (se elimina el auth token principal actual y el secundario pasa a ser el principal).19 Twilio también advierte que cuando el token está escrito directamente en Services o Functions (Classic) en lugar de en una variable, "you must wait for 1 minute for the update of your auth token to propagate" (debe esperar 1 minuto a que se propague la actualización de su auth token), o esas llamadas fallan con un 403.19 La documentación que leímos no dice cómo se comporta la firma durante una rotación. Nuestra inferencia a partir de la regla de firma es que, una vez que el token nuevo es el principal, las firmas se calculan con él, así que el orden seguro es: crear el secundario, hacer que sus validadores acepten cualquiera de los dos tokens durante el cambio, promover y luego retirar el viejo. Ensáyelo en una cuenta de prueba antes de necesitarlo a las 2 de la mañana después de una filtración, y recuerde que las claves creadas con un token comprometido "should be invalidated or deleted" (deben invalidarse o eliminarse) también.14

10. Una subcuenta por cliente

Si usted administra menús telefónicos para más de un negocio, las subcuentas son la unidad de aislamiento: "Using a subaccount, you can segment each of your customers’ use of Twilio and keep it separate from all the rest" (con una subcuenta puede segmentar el uso de Twilio de cada uno de sus clientes y mantenerlo separado del resto), y cada una puede tener sus propios números telefónicos, aplicaciones y dominios SIP.20 Una cuenta principal puede tener "up to 1000 subaccounts by default" (hasta 1,000 subcuentas por defecto); todo el uso se factura a la cuenta principal, y si la cuenta principal se suspende, sus subcuentas también.20

Lo que obtiene con la división: triggers de uso y suspensión por cliente (arriba), grabaciones por cliente que puede borrar en un solo lugar, permisos geográficos por cliente cuando se desactiva la herencia,15 y una salida limpia. Cerrar es definitivo: Twilio "will release all phone numbers assigned to it" (liberará todos los números telefónicos asignados), "you can’t reopen a closed account" (no se puede reabrir una cuenta cerrada), y cuando la opción de eliminación está activada (el valor predeterminado de las cuentas creadas después del 5 de julio de 2018), Twilio elimina "all subaccount data 30 days after closure" (todos los datos de la subcuenta 30 días después del cierre).20

Cerrar libera los números

Un cliente que se va con su número comercial debe portarlo antes de que usted cierre su subcuenta. Si cierra primero, el número se libera.20 Suspenda mientras espera; no cierre.

Los costos de la división son los ya mencionados: las alarmas no se consolidan,11 así que cada monitor debe crearse por subcuenta, y su script de aprovisionamiento se convierte en el código de operaciones más importante que usted tiene.

11–12. Grabaciones de buzón de voz: almacenamiento, retención, eliminación y cifrado

Un mensaje de voz es la grabación de una persona del público, a menudo con un nombre, un número de teléfono y el motivo de su llamada. Trátelo como información personal desde el principio.

Captura. <Record> tiene por defecto un maxLength de 3,600 segundos (una hora), un timeout de 5 segundos de silencio, cualquier tecla para terminar, un pitido y trim-silence.21 Una hora es demasiado para un mensaje de voz; de 120 a 180 segundos sobra y limita su almacenamiento. La transcripción integrada de Twilio "only supported in American English" (solo es compatible con inglés estadounidense), y una grabación transcrita tiene por defecto un maxLength de dos minutos,21 lo cual la descarta para llamantes francófonos en Québec; la página de precios de EE. UU. la lista a $0.05 por minuto.37

Almacenamiento y acceso. La grabación cuesta $0.0025 por minuto y el almacenamiento $0.0005 por minuto al mes en la página de precios de EE. UU.37 Ni la página de precios ni la referencia de Recording que leímos indican un período de retención predeterminado para las grabaciones comunes, y el almacenamiento se factura cada mes, así que planifique como si se quedaran hasta que usted las elimine. El acceso a los archivos está autenticado: "Twilio enforces HTTP Basic Authentication for all media URLs" (Twilio exige autenticación HTTP Basic en todas las URL de archivos), y Twilio sugiere como credenciales el SID y el secreto de una API key.22

Eliminación. DELETE sobre una grabación elimina el archivo ("The recording media cannot be recovered", el archivo de la grabación no se puede recuperar), detiene la facturación del almacenamiento y devuelve 204; solo se pueden eliminar grabaciones completed, y "The metadata is preserved for a period of 40 days" (los metadatos se conservan por 40 días), visibles en la Consola y la API.22 La Consola también permite eliminar en bloque.22 Un trabajo de retención mínimo:

# Python: copy voicemails older than N days to your own store (or not), then delete at Twilio.
import os, datetime as dt
from twilio.rest import Client

client = Client(os.environ["TWILIO_API_KEY_SID"], os.environ["TWILIO_API_KEY_SECRET"],
                os.environ["TWILIO_ACCOUNT_SID"])
cutoff = dt.datetime.now(dt.timezone.utc) - dt.timedelta(days=30)

for rec in client.recordings.list(date_created_before=cutoff, page_size=100):
    if rec.status != "completed":
        continue
    archive_if_required(rec)          # your decision: many businesses should keep nothing
    client.recordings(rec.sid).delete()

Nuestra opinión: decida el período de retención antes del lanzamiento, escríbalo en su aviso de privacidad y haga que el trabajo elimine por defecto. Un mensaje de voz cumplió su función cuando alguien lo escuchó y actuó; guardar tres años de ellos es un pasivo con una factura mensual. Si necesita grabar llamadas en vivo y no solo mensajes de voz, las reglas de consentimiento varían según el estado y la provincia; nuestra lista de verificación para grabar llamadas (en inglés) las cubre.

Cifrado. Twilio ofrece Voice Recording Encryption: para cada grabación genera una clave de contenido, cifra el audio "with the generated CEK using the AES256-GCM cipher" (con la CEK generada, usando el cifrado AES256-GCM), y envuelve esa clave con su clave pública RSA; "There is no one at Twilio, including Twilio support, that will be able to decrypt your recordings" (nadie en Twilio, incluido el soporte, podrá descifrar sus grabaciones).23 Se activa a nivel de proyecto o de subcuenta con una clave pública que usted carga.23 Las contrapartidas se enuncian con claridad en la misma guía: si pierde la clave privada, las grabaciones son irrecuperables; la clave pública cargada no se puede recuperar después; y si el cifrado falla, "The recording file is deleted and will not be available for access" (el archivo de la grabación se elimina y no estará disponible).23 Las grabaciones cifradas incluyen encryption_details, que describe cómo descifrarlas.22 Nuestra opinión: vale la pena donde las grabaciones son delicadas y ya se maneja una gestión de claves adecuada; no vale la pena si la clave privada terminaría en las mismas variables de entorno que todo lo demás.

13. Datos de llamantes canadienses almacenados en Estados Unidos

Las regiones de datos de Twilio son Estados Unidos (US1), Irlanda (IE1) y Australia (AU1); en esa lista no hay una región canadiense, no todos los productos están disponibles fuera de US1, y Twilio dice que durante el despliegue "does not guarantee that all data will remain within your selected Region" (no garantiza que todos los datos permanezcan dentro de la región seleccionada).24 Para un negocio canadiense con una cuenta predeterminada, suponga que los registros de llamadas y los mensajes de voz se almacenan en Estados Unidos.

Eso es legal, pero trae obligaciones. Bajo PIPEDA, la orientación del comisionado federal de privacidad es que la ley "does not prohibit organizations in Canada from transferring personal information" (no prohíbe a las organizaciones en Canadá transferir información personal) para su procesamiento; la organización sigue siendo responsable, debe usar medios contractuales para "provide a comparable level of protection" (ofrecer un nivel de protección comparable), y debe informar a las personas, en lenguaje claro, que su información puede procesarse en el extranjero y "may be accessible to law enforcement and national security authorities of that jurisdiction" (puede ser accesible a las autoridades policiales y de seguridad nacional de esa jurisdicción).25 (Esa orientación data de 2009; sigue siendo la posición publicada del comisionado en la página que leímos.)

Québec va más allá. Según el artículo 17 de su ley de privacidad del sector privado, "Before communicating personal information outside Québec, a person carrying on an enterprise must conduct a privacy impact assessment" (antes de comunicar información personal fuera de Québec, quien explota una empresa debe realizar una evaluación de impacto sobre la privacidad), que pondera la sensibilidad, los fines, las medidas de protección y el marco legal extranjero, y la comunicación "must be the subject of a written agreement" (debe ser objeto de un acuerdo escrito); lo mismo aplica cuando usted encarga a una entidad fuera de Québec conservar la información por su cuenta.26 El artículo 8 exige informar a las personas, cuando corresponda, de "the possibility that the information could be communicated outside Québec" (la posibilidad de que la información se comunique fuera de Québec).26

En la práctica: redacte una evaluación breve del flujo de mensajes de voz y registro de llamadas, conserve con ella los términos y los documentos de procesamiento de datos de Twilio, incluya en su aviso de privacidad la frase sobre el procesamiento fuera de Canadá y fuera de Québec, y mantenga una retención corta, lo que reduce todos los demás riesgos. Esto es un resumen de los textos, no asesoría legal. La página sobre Canadá del sitio trata con más amplitud las reglas telefónicas canadienses.

14. HIPAA y PCI, según la documentación de Twilio

HIPAA. La postura de Twilio es que los clientes sujetos a HIPAA que procesarán información de salud protegida deben firmar un Business Associate Addendum, y que firmarlo requiere la edición Security o Enterprise.27 Su lista de servicios elegibles (última actualización: 30 de junio de 2026) incluye lo básico de Programmable Voice con Call Recordings and Storage, Call Transcription, Voice Insights y otros, con los elementos marcados con asterisco que requieren el manejo especial descrito en su guía de arquitectura; y establece que las entidades cubiertas y los socios comerciales aceptan no usar los servicios elegibles con PHI "without first entering into a Twilio Business Associate Agreement" (sin celebrar antes un Twilio Business Associate Agreement).28 Esa guía de arquitectura (fechada 11.09.22) exige que los flujos de trabajo HIPAA verifiquen que las solicitudes "are indeed coming from Twilio" (provienen realmente de Twilio) comprobando la firma, y que se exija autenticación HTTP básica en los archivos de grabación.29 La referencia actual de Recording lo repite: "we require customers to enforce at least HTTP Authentication" (exigimos a los clientes aplicar al menos autenticación HTTP).22

El mensaje de voz de una clínica ("llamo por mis resultados") es PHI. Si su menú atiende a servicios de salud, el BAA va antes de la primera llamada real, no después.

PCI. Si los llamantes van a marcar números de tarjeta, la vía de Twilio es el sustantivo TwiML <Pay> con PCI Mode, que "redacts sensitive payment details captured using Twilio Programmable Voice and <Pay>" (oculta los datos de pago confidenciales capturados con Twilio Programmable Voice y <Pay>).30 Dos hechos que conviene saber antes de hacer clic: "Once PCI Mode is enabled, it cannot be disabled for that Account" (una vez activado PCI Mode, no se puede desactivar para esa cuenta), y las grabaciones de voz PCI se "retained for one (1) year from creation, by default" (conservan por un (1) año desde su creación, por defecto) y luego se eliminan.30 La página remite a la matriz de responsabilidades de Twilio para saber quién es responsable de qué.30 Nuestra opinión: ponga los flujos de pago en su propia subcuenta para que la irreversibilidad de PCI Mode no se extienda a líneas que nunca reciben una tarjeta, y nunca deje que un llamante dicte un número de tarjeta a un buzón de voz.

15. Límites de frecuencia y reintentos

Se aplican dos límites distintos, y se comportan de manera diferente.

Llamadas por segundo. "Calls are rate limited at the account level by Calls Per Second (CPS)" (las llamadas tienen un límite de frecuencia a nivel de cuenta por llamadas por segundo, CPS), "By default, each account is granted one CPS for calls created via POST requests to the /Calls endpoint" (por defecto, cada cuenta recibe un CPS para las llamadas creadas mediante solicitudes POST al endpoint /Calls), y las llamadas que lo exceden "will be queued and will execute at the CPS rate" (se pondrán en cola y se ejecutarán a la tasa de CPS).8 Un menú de entrada rara vez crea llamadas por la API, pero la sonda sintética que verá más abajo y cualquier función de devolución de llamada sí lo hacen, y un solo CPS se comparte entre todas.

Concurrencia REST. El error 20429 se devuelve "when your account exceeds allowed concurrency to Twilio’s REST API" (cuando su cuenta excede la concurrencia permitida a la API REST de Twilio); esas solicitudes "aren’t processed and are safe to retry after backing off" (no se procesan y es seguro reintentarlas tras esperar), y Twilio recomienda retroceso exponencial y vigilar el encabezado de respuesta Twilio-Concurrent-Requests.31 twilio-node puede hacer el retroceso por usted: autoRetry: true activa el "automatic retry with exponential backoff" (reintento automático con retroceso exponencial) ante un 429, desactivado por defecto, con maxRetries en 3 por defecto.18

const client = twilio(process.env.TWILIO_API_KEY_SID, process.env.TWILIO_API_KEY_SECRET, {
  accountSid: process.env.TWILIO_ACCOUNT_SID,
  autoRetry: true,
  maxRetries: 5,
});

Reintentos en la otra dirección. Twilio reintenta sus webhooks ante fallas de conexión por defecto, y en más casos si usted configura rp.5 Las devoluciones de alarmas y de triggers de uso incluyen un IdempotencyToken precisamente para que usted pueda eliminar duplicados.1113 Nuestra opinión: haga idempotente cada controlador que escribe (una clave única de SID de llamada más evento, como en el registrador de arriba), y mantenga los controladores que solo devuelven TwiML libres de efectos secundarios para que un reintento sea inofensivo.

16. Pruebas: credenciales de prueba, falsificaciones firmadas y la CLI

Las credenciales de prueba "exercise parts of the REST API without incurring charges" (ejercitan partes de la API REST sin generar cargos), y abarcan crear llamadas y mensajes, comprar números y Lookup, con números mágicos como +15005550006 como From válido.32 Sepa lo que no hacen: "Because no call is placed, Twilio doesn’t request the URL specified in the Url parameter and no TwiML is executed" (como no se realiza ninguna llamada, Twilio no solicita la URL indicada en el parámetro Url y no se ejecuta ningún TwiML), y las llamadas de prueba "don’t trigger status callbacks" (no activan devoluciones de estado).32 Prueban su integración REST (aprovisionamiento, manejo de errores por números inválidos o bloqueados), no su menú.

Sus controladores TwiML son HTTP simple y se prueban mejor como tales. El tutorial de Express de Twilio muestra cómo apagar la validación cuando NODE_ENV es test.4 Nosotros preferimos dejar la validación activa y firmar las solicitudes de prueba con el getExpectedTwilioSignature(authToken, url, params) que exporta la biblioteca,2 de modo que un validador roto haga fallar el CI y no la producción:

// test/voice.test.js (supertest + node:test)
const request = require('supertest');
const twilio = require('twilio');
process.env.TWILIO_AUTH_TOKEN = 'test-token-not-a-secret';
const app = require('../app');

test('menu option 1 forwards with a 20 s timeout', async () => {
  const params = { CallSid: 'CA00000000000000000000000000000000', Digits: '1' };
  const url = 'https://ivr.example.com/menu';
  const sig = twilio.getExpectedTwilioSignature(process.env.TWILIO_AUTH_TOKEN, url, params);
  const res = await request(app).post('/menu').set('X-Twilio-Signature', sig).type('form').send(params);
  assert.match(res.text, /<Dial[^>]*timeout="20"/);
});

test('unsigned requests are rejected', async () => {
  const res = await request(app).post('/menu').type('form').send({ Digits: '1' });
  assert.equal(res.status, 400);   // no header: 400; wrong signature: 403
});

La Twilio CLI se instala con brew tap twilio/brew && brew install twilio (o con npm, que Twilio desaconseja), y twilio login guarda las credenciales como un perfil con nombre, de modo que puede mantener separados el ambiente de ensayo y el de producción en una misma máquina.33 Un borde filoso: phone-numbers:update lanza "Localhost URLs are not allowed for this operation." (no se permiten URL localhost para esta operación) si le pasa una URL localhost o 127.0.0.1,34 así que el desarrollo local necesita la URL pública de un túnel. Nuestra opinión: tenga un número de ensayo aparte en una subcuenta aparte, conectado a su despliegue de ensayo, y nunca apunte un número de producción a una laptop.

17. Llamadas de prueba sintéticas: que un robot llame a su menú

Las comprobaciones de firma, las alarmas y los registros le avisan cuando algo da error. No le dicen que el archivo del saludo se reemplazó por silencio, que la opción 2 ahora va a un número desconectado, o que el menú funciona pero el audio dice que la oficina cierra a las 5 cuando ahora cierra a las 6. Una sonda sintética es una llamada real, hecha según un calendario, que recorre el menú y comprueba lo que oye.

Twilio tiene las piezas. Una llamada creada por la API puede llevar su propio Twiml en línea en lugar de obtener una URL, y una cadena SendDigits de hasta 32 teclas.8 En el tramo de la sonda, <Gather input="speech"> transcribe lo que oye en SpeechResult con una puntuación Confidence, y actionOnEmptyResult hace que envíe aunque no oiga nada.35 <Play digits> envía pulsaciones de teclas, con w para una pausa de medio segundo.36

// probe.js: run from cron, e.g. hourly during business hours.
// The probe calls FROM a separate number you own, used only for probes.
const MENU = '+15145550199', PROBE_FROM = '+15145550177', BASE = 'https://monitor.example.com';

await client.calls.create({
  to: MENU, from: PROBE_FROM, timeLimit: 90,
  statusCallback: BASE + '/probe/status',
  statusCallbackEvent: ['answered', 'completed'],
  twiml: '<Response><Gather input="speech" timeout="8" speechTimeout="2" ' +
         'actionOnEmptyResult="true" action="' + BASE + '/probe/greeting"/></Response>',
});

// Step 1: did we hear the greeting and the voicemail option? Then press 3.
app.post('/probe/greeting', twilioOnly, async (req, res) => {
  const heard = (req.body.SpeechResult || '').toLowerCase();
  const ok = /message|voicemail/.test(heard) && /press (3|three)/.test(heard);
  await probes.step(req.body.CallSid, 'greeting', ok, heard);
  const vr = new VoiceResponse();
  if (!ok) { vr.hangup(); return res.type('text/xml').send(vr.toString()); }
  vr.play({ digits: 'w3' });
  vr.gather({ input: 'speech', timeout: 8, speechTimeout: 2, actionOnEmptyResult: true,
              action: BASE + '/probe/voicemail-prompt' });
  res.type('text/xml').send(vr.toString());
});

// Step 2: did option 3 reach the voicemail prompt? Hang up before the beep.
app.post('/probe/voicemail-prompt', twilioOnly, async (req, res) => {
  const heard = (req.body.SpeechResult || '').toLowerCase();
  await probes.step(req.body.CallSid, 'voicemail', /after the tone|leave a message/.test(heard), heard);
  const vr = new VoiceResponse();
  vr.hangup();
  res.type('text/xml').send(vr.toString());
});

// Alert on: a failed step, a probe with no 'completed' status, or CallStatus busy/failed/no-answer.

Decisiones de diseño que vale la pena explicar. La sonda recorre la ruta del buzón de voz, no la del desvío, porque una sonda que desvía hace sonar a una persona real cada hora; verifique el desvío con su propio registro de /dial-result, donde una racha de failed o no-answer en un mismo destino es la señal.9 El reconocimiento de voz es difuso por naturaleza (un reconocedor puede escribir "three" o "3"), así que compare con flexibilidad y avise tras dos fallas consecutivas, no una. Y pruebe también el respaldo: una vez por semana, ejecute la misma sonda contra una copia de ensayo del número cuyo voice_url esté roto a propósito.

La sonda tiene un costo, calculado en la siguiente sección, y usa el único CPS predeterminado de la cuenta cuando arranca.8 Nuestra opinión: una vez por hora en horario laboral es el valor adecuado para una línea de un negocio pequeño; cada pocos minutos es para líneas donde perder una hora sale caro.

18. Modelo de costos, por minuto

El precio de voz de Twilio es por minuto y por tramo, y el tramo que sorprende a la gente es el desvío. Una llamada que entra por su número y se desvía con <Dial> se convierte en dos llamadas: la entrante y "the new call leg" (el nuevo tramo de llamada) que crea <Dial>.9 Nuestra lectura de la página de precios es que el segundo tramo se cobra como una llamada saliente al destino. Las cifras de abajo provienen de la página de precios de Programmable Voice de Twilio para EE. UU., que indica "Pricing current as of August 2026"; la página usa el signo de dólar sin nombrar la moneda, y la leemos como dólares estadounidenses.37

ConceptoPágina de precios de EE. UU. (agosto de 2026)
Número local$1.15 al mes
Número gratuito$2.15 al mes
Entrante, número local$0.0085 por minuto
Entrante, número gratuito$0.0220 por minuto
Saliente a números de EE. UU. (el tramo desviado)$0.0140 por minuto
Grabación de llamadas$0.0025 por minuto
Almacenamiento de grabaciones$0.0005 por minuto al mes
Transcripción$0.0500 por minuto
Reconocimiento de voz (proveedor predeterminado)$0.02 por uso
Texto a voz, voces básicasGratis
Texto a voz, Premium Neural$0.0032 por 100 caracteres
Voice Insights Advanced Features$0.0024 por minuto

Deslice la tabla hacia los lados para ver todas las columnas.

La consulta del nombre del llamante (CNAM) en el número cuesta "$0.01 per look up" (0.01 dólares por consulta) según la referencia de números telefónicos.6 La página de precios de Canadá muestra las mismas cifras para números locales y gratuitos, minutos entrantes, llamadas salientes a "United States & Canada" ($0.0140), grabación y almacenamiento, con Yukón como excepción a $0.1525 por minuto saliente; tampoco nombra la moneda.38 La página de EE. UU. dice que los descuentos por volumen se aplican automáticamente al superar un umbral de minutos mensuales y que "Volume pricing applies to U.S. and Canadian voice minutes" (los precios por volumen se aplican a los minutos de voz de EE. UU. y Canadá).37 La página no dice cómo se redondean las duraciones de las llamadas para la facturación, así que la aritmética de abajo, hecha con minutos exactos, es un piso y no una cotización.

Un mes de ejemplo. Un negocio pequeño con un número local, 600 llamadas entrantes, con un promedio de 3 minutos en el tramo entrante (1,800 minutos). De ellas, 480 se desvían y hablan 2.5 minutos en el tramo desviado (1,200 minutos); 120 dejan un mensaje de voz de un minuto.

LíneaAritméticaMensual
Número1 × $1.15$1.15
Minutos entrantes1,800 × $0.0085$15.30
Tramo desviado1,200 × $0.0140$16.80
Grabación de mensajes de voz120 × $0.0025$0.30
Almacenamiento de mensajes de voz (eliminados a los 30 días)unos 120 minutos almacenados × $0.0005$0.06
Saludo con TTS Premium Neural, 300 caracteres por llamada600 × 3 × $0.0032$5.76
Sonda sintética, cada hora durante 10 horas laborales en 22 días, de 1 minuto aproximadamente cada una220 × ($0.0140 + $0.0085 + 2 × $0.02)$13.75
Total$53.12

Deslice la tabla hacia los lados para ver todas las columnas.

Lo que muestra el modelo. El tramo desviado cuesta más que los minutos entrantes, así que el diseño del desvío (tiempo de timbre, quién recibe la llamada) es la palanca de costo, no el menú. Un saludo sintetizado se cobra en cada llamada, mientras que las mismas palabras grabadas una vez y servidas con <Play> no cuestan nada por llamada más allá del alojamiento; en nuestra opinión, un saludo grabado también es mejor para los llamantes. Conservar los mensajes de voz un año en lugar de 30 días cambia el almacenamiento de 6 centavos a unos 72 centavos al mes hacia fin de año (1,440 minutos almacenados), lo cual es trivial en dinero y no es trivial en privacidad. Y el monitoreo no es gratis: la sonda de arriba es aproximadamente la cuarta parte de esta factura, y sondear cada 15 minutos las 24 horas (2,880 sondas a unos $0.0625) costaría unos $180 al mes, más que el tráfico. Dimensiónela según lo que le cuesta una hora de menú roto; nuestra calculadora del costo de las llamadas perdidas (en inglés) es una forma de ponerle una cifra.

Dos exposiciones no están en la tabla porque se supone que no deben ocurrir: un desvío a un destino de costo alto y un ataque. Para eso sirven las secciones 7 y 8.

Si solo tiene un día

Nuestro orden, según cuánto daño puede causar cada brecha y qué tan barato es cerrarla:

  1. Validación de firmas en todas las rutas (una hora, y cierra el hueco más grande).
  2. Permisos geográficos reducidos a los países a los que desvía, más una lista permitida en el código (minutos).
  3. Un trigger de uso diario que avise y otro que suspenda (una hora).
  4. Un respaldo estático en un alojamiento aparte, probado rompiendo el principal (una hora).
  5. Alarmas para el 11200 y para cualquier error, por correo y webhook (minutos).
  6. Registro de estados y de <Dial> en su propia base de datos (una tarde).
  7. Un período de retención de grabaciones por escrito y el trabajo que lo aplica (una tarde).

El resto (la división de API keys, subcuentas, sondas, cifrado, la evaluación de Québec) es el segundo día. Todo es trabajo continuo; es el trabajo que un servicio telefónico administrado hace por usted, y la razón honesta para sopesar construir frente a comprar antes de empezar. El centro de guías de Twilio tiene las demás piezas de la construcción, y nuestras plantillas de flujo de llamadas son una buena especificación de lo que debe hacer el menú.

Lecturas recomendadas

Artículos de investigación más largos sobre este tema (en inglés), cada uno con sus fuentes y un PDF descargable.

Fuentes

Cada afirmación sobre normas o precios en esta página enlaza a su fuente primaria, a menudo en inglés. Las normas y los precios cambian: verifique antes de confiar en una cifra.

  1. Twilio Docs, "Webhooks security": firma HMAC-SHA1 sobre la URL y los parámetros ordenados con el auth token, uso del validador del SDK, URL exacta, sin rango fijo de IP, autenticación Basic/Digest, sin certificados autofirmados. Consultado el 26 de octubre de 2026
    https://www.twilio.com/docs/usage/webhooks/webhooks-security
  2. Código fuente de twilio-node, src/webhooks/webhooks.ts: opciones del middleware webhook() (validate, host, protocol, url), comportamiento 400/403/500, manejo de puertos, getExpectedTwilioSignature. rama main; versión npm 6.2.0; consultado el 26 de octubre de 2026
    https://github.com/twilio/twilio-node/blob/main/src/webhooks/webhooks.ts
  3. Código fuente de twilio-python, twilio/request_validator.py: RequestValidator.validate(uri, params, signature) y compatibilidad con MultiDict de Flask. rama main; versión PyPI 9.12.0; consultado el 26 de octubre de 2026
    https://github.com/twilio/twilio-python/blob/main/twilio/request_validator.py
  4. Twilio Docs, "Secure your Express app by validating incoming Twilio requests" (opción validate, fallo detrás de la terminación TLS). Consultado el 26 de octubre de 2026
    https://www.twilio.com/docs/usage/tutorials/how-to-secure-your-express-app-by-validating-incoming-twilio-requests
  5. Twilio Docs, "Webhooks connection overrides": tiempos de espera y política de reintentos predeterminados, sintaxis de fragmento, límite de 15 segundos en solicitudes de voz. Consultado el 26 de octubre de 2026
    https://www.twilio.com/docs/usage/webhooks/webhooks-connection-overrides
  6. Twilio Docs, recurso IncomingPhoneNumber: voice_url, voice_fallback_url, status_callback, precio de la consulta CNAM. Consultado el 26 de octubre de 2026
    https://www.twilio.com/docs/phone-numbers/api/incomingphonenumber-resource
  7. Twilio Docs, error 11200 "HTTP retrieval failure": causas y recomendación de la URL de respaldo. Consultado el 26 de octubre de 2026
    https://www.twilio.com/docs/api/errors/11200
  8. Twilio Docs, recurso Call: StatusCallbackEvent, evento completed predeterminado, parámetros de la devolución de llamada, SendDigits, Twiml, cola por CPS. Consultado el 26 de octubre de 2026
    https://www.twilio.com/docs/voice/api/call-resource
  9. Twilio Docs, TwiML <Dial>: nuevo tramo de llamada, URL action, valores de DialCallStatus, timeout predeterminado y margen de cinco segundos, reglas de callerId. Consultado el 26 de octubre de 2026
    https://www.twilio.com/docs/voice/twiml/dial
  10. Twilio Docs, "Debugging your application": campos del Debugger, webhook de errores, búsqueda de 30 días. Consultado el 26 de octubre de 2026
    https://www.twilio.com/docs/usage/troubleshooting/debugging-your-application
  11. Twilio Docs, Alarms: umbrales, ventanas de tiempo, entrega por correo y webhook, solo US1, sin agregación de subcuentas, campos de la carga. Consultado el 26 de octubre de 2026
    https://www.twilio.com/docs/usage/troubleshooting/alarms
  12. Twilio Docs, Voice Insights: paneles, Call Summary, Advanced Features con costo adicional, ventana de datos de 30 días. Consultado el 26 de octubre de 2026
    https://www.twilio.com/docs/voice/voice-insights
  13. Twilio Docs, recurso UsageTrigger: TriggerBy, Recurring, evaluación aproximadamente una vez por minuto, parámetros de la devolución de llamada. Consultado el 26 de octubre de 2026
    https://www.twilio.com/docs/usage/api/usage-trigger
  14. Twilio Docs, "Anti-Fraud Developer’s Guide": restringir países de destino, suspender una subcuenta con un trigger de $30 al día, reemplazo de credenciales, facturación del fraude telefónico. Consultado el 26 de octubre de 2026
    https://www.twilio.com/docs/usage/anti-fraud-developer-guide
  15. Twilio Docs, "Voice Dialing Geographic Permissions": controles por país y de alto riesgo, solo Owner/Administrator, herencia en subcuentas, IRSF. Consultado el 26 de octubre de 2026
    https://www.twilio.com/docs/voice/tutorials/voice-dialing-geographic-permissions
  16. Twilio Docs, guía de respuesta al fraude, "Engage: contact Twilio Support": suspensión por saldo negativo. Consultado el 26 de octubre de 2026
    https://www.twilio.com/docs/usage/fraud-response-guide/engage
  17. Twilio Docs, API keys: tipos de clave Main, Standard y Restricted, revocación. Consultado el 26 de octubre de 2026
    https://www.twilio.com/docs/iam/api-keys
  18. README de twilio-node: acceso a subcuentas, autoRetry con retroceso exponencial ante 429 (3 reintentos predeterminados); BaseTwilio.ts exige accountSid al autenticarse con una API key. rama main; consultado el 26 de octubre de 2026
    https://github.com/twilio/twilio-node/blob/main/README.md
  19. Twilio Docs, recurso AuthToken: al promover el token secundario se elimina el principal; advertencia de propagación de un minuto. Consultado el 26 de octubre de 2026
    https://www.twilio.com/docs/iam/api/authtoken
  20. Twilio Docs, Subaccounts: segmentación por cliente, límite predeterminado de 1,000, facturación a la cuenta principal, suspender frente a cerrar, eliminación de datos 30 días después del cierre. Consultado el 26 de octubre de 2026
    https://www.twilio.com/docs/iam/api/subaccounts
  21. Twilio Docs, TwiML <Record>: valores predeterminados de maxLength, timeout y trim, recordingStatusCallback, límites de transcripción, bucle sin action. Consultado el 26 de octubre de 2026
    https://www.twilio.com/docs/voice/twiml/record
  22. Twilio Docs, recurso Recording: autenticación HTTP Basic en las URL de los archivos, semántica de DELETE, retención de metadatos por 40 días, nota sobre HIPAA. Consultado el 26 de octubre de 2026
    https://www.twilio.com/docs/voice/api/recording
  23. Twilio Docs, "Voice Recording Encryption": clave de contenido AES256-GCM envuelta con su clave pública RSA; Twilio no puede descifrar. Consultado el 26 de octubre de 2026
    https://www.twilio.com/docs/voice/tutorials/voice-recording-encryption
  24. Twilio Docs, Global infrastructure: regiones US1, IE1 y AU1, y la salvedad sobre residencia de datos. Consultado el 26 de octubre de 2026
    https://www.twilio.com/docs/global-infrastructure
  25. Oficina del Comisionado de Privacidad de Canadá, "Guidelines for processing personal data across borders" (responsabilidad y aviso bajo PIPEDA). Publicado el 27 de enero de 2009; consultado el 26 de octubre de 2026
    https://www.priv.gc.ca/en/privacy-topics/airports-and-borders/gl_dab_090127/
  26. Québec, Act respecting the protection of personal information in the private sector, CQLR c P-39.1, arts. 8 y 17. Texto vigente al 15 de octubre de 2026; consultado el 26 de octubre de 2026
    https://www.legisquebec.gouv.qc.ca/en/document/cs/P-39.1
  27. Twilio, página de cumplimiento de HIPAA: se requiere un BAA para la PHI; hace falta la edición Security o Enterprise para firmarlo. Consultado el 26 de octubre de 2026
    https://www.twilio.com/en-us/hipaa
  28. Twilio, "HIPAA Eligible Services" (PDF): elementos de Programmable Voice, incluidos Call Recordings and Storage*, Call Transcription*, Voice Insights. Última actualización: 30 de junio de 2026
    https://www.twilio.com/content/dam/twilio-com/global/en/other/hipaa/pdf/HIPAA-Eligible-Services.pdf
  29. Twilio, "Architecting for HIPAA on Twilio" (PDF): la verificación de firma y la autenticación HTTP en las grabaciones son obligatorias en los flujos de trabajo HIPAA. Fechado 11.09.22
    https://docs-resources.prod.twilio.com/documents/architecting-for-HIPAA.pdf
  30. Twilio Docs, "PCI workflows": PCI Mode, irreversibilidad, <Pay>, retención predeterminada de un año de las grabaciones de voz PCI. Consultado el 26 de octubre de 2026
    https://www.twilio.com/docs/voice/pci-workflows
  31. Twilio Docs, error 20429 "Too many requests": concurrencia REST, se puede reintentar con retroceso exponencial, encabezado Twilio-Concurrent-Requests. Consultado el 26 de octubre de 2026
    https://www.twilio.com/docs/api/errors/20429
  32. Twilio Docs, Test credentials: recursos compatibles, números mágicos, sin TwiML ejecutado ni devoluciones de estado. Consultado el 26 de octubre de 2026
    https://www.twilio.com/docs/iam/test-credentials
  33. Twilio Docs, guía rápida de Twilio CLI: instalación con Homebrew y npm, twilio login, perfiles. Consultado el 26 de octubre de 2026
    https://www.twilio.com/docs/twilio-cli/quickstart
  34. Código fuente de twilio-cli, src/commands/phone-numbers/update.js: opciones voice-url y voice-fallback; se rechazan las URL localhost. rama main; versión npm 7.2.0; consultado el 26 de octubre de 2026
    https://github.com/twilio/twilio-cli/blob/main/src/commands/phone-numbers/update.js
  35. Twilio Docs, TwiML <Gather>: entrada de voz, SpeechResult, speechTimeout, actionOnEmptyResult. Consultado el 26 de octubre de 2026
    https://www.twilio.com/docs/voice/twiml/gather
  36. Twilio Changelog, compatibilidad DTMF con A-D y W: la w minúscula es una pausa de 0.5 segundos en SendDigits y <Play digits>. 5 de mayo de 2025
    https://www.twilio.com/en-us/changelog/dtmf-support-ABCD-W
  37. Twilio, precios de Programmable Voice, Estados Unidos (tarifas por minuto, números, grabación, almacenamiento, Voice Insights, reconocimiento de voz, TTS). La página indica "Pricing current as of August 2026"; consultado el 26 de octubre de 2026
    https://www.twilio.com/en-us/voice/pricing/us
  38. Twilio, precios de Programmable Voice, Canadá. La página indica "Pricing current as of August 2026"; consultado el 26 de octubre de 2026
    https://www.twilio.com/en-us/voice/pricing/ca