Sign inGet Started

Buenas prácticas de Verify

Verify incluye valores predeterminados adecuados para la mayoría de flujos de códigos de verificación de un solo uso. Esta guía cubre las decisiones que los valores predeterminados no toman por ti: cuánto tiempo debe vivir un código, cuántos dígitos necesita, qué canal es apropiado para lo que realmente estás verificando, y cómo distinguir un problema de entrega de un problema de verificación.

Cuando un estándar público tiene una posición, esta guía lo cita. El estándar para autenticación con códigos de verificación es NIST SP 800-63B, Digital Identity Guidelines: Authentication and Authenticator Management, consultado el 3 de septiembre de 2026. Las citas corresponden a la revisión vigente. La anterior Revision 3, que gran parte del material de OTP aún referencia, lleva el propio aviso de NIST: reemplazada por SP 800-63-4 a partir del 1 de agosto de 2025.

Usa un código de seis dígitos o más

La longitud predeterminada del código en Bird cumple NIST SP 800-63B, aunque options.code_length también acepta códigos más cortos (Opciones). Para autenticación, mantén el valor predeterminado o uno mayor:

The verifier SHALL generate random authentication secrets that are at least six decimal digits (or equivalent) in length using an approved random bit generator

Un código de 4 o 5 dígitos está dentro de lo que API acepta y fuera de lo que el estándar permite. Acorta un código solo en un flujo en el que hayas decidido que la entropía del código de verificación no es la que aporta la seguridad.

Mantén la vida útil en diez minutos o menos

El valor predeterminado de Duration coincide con el tope del estándar, aunque la configuración del espacio de trabajo acepta ventanas más largas (Configuración de verificación):

In all cases, the authentication SHALL be considered invalid unless completed within 10 minutes.

Subir Duration por encima de 10 minutos para reducir las consultas de soporte por códigos expirados es el único cambio de configuración que saca silenciosamente un flujo de 800-63B. Si los códigos expiran antes de que los usuarios lleguen a ellos, la solución suele estar en la ruta de envío, no en la ventana de tiempo.

Espera dos capas de limitación de solicitudes

Un intento de comprobación está acotado dos veces, y los dos límites responden a amenazas distintas.

Tu configuración. Maximum Retries limita cuántas comprobaciones incorrectas acepta una verificación antes de fallar con attempts_exhausted (Configuración de verificación). El estándar exige que este límite exista para un código tan corto, y añade una regla que conviene conocer:

Generating a new authentication secret SHALL NOT reset the failed authentication count.

El límite tiene un tope, y este es el único punto en el que todos los valores que ofrece Verify están cómodamente dentro del estándar:

the verifier SHALL limit consecutive failed authentication attempts using a specific authenticator on a single subscriber account to no more than 100 by disabling that authenticator

Como Maximum Retries tiene un tope muy por debajo de 100, ninguna configuración que puedas elegir supera el tope del estándar. Es la imagen inversa de las dos secciones anteriores: la longitud del código y la duración tienen cada una un valor admitido que sale de 800-63B, y el límite de intentos no tiene ninguno.

Los topes de plataforma de Bird, que se aplican independientemente de tu configuración: los topes de envío por hora y destinatario (entre inicios y reenvíos) y los topes de comprobaciones por minuto devuelven 429 con un encabezado Retry-After (Medidas contra abuso). Existen para evitar que el tráfico de OTP se use como arma contra tu presupuesto o el teléfono de un desconocido, así que trata un 429 aquí como el sistema funcionando correctamente, no como un límite que debas sortear.

Elige el canal según lo que estés verificando

Verify entrega por email, SMS, WhatsApp, Telegram y voz (Canales). El estándar trata dos de ellos de forma muy distinta, y la distinción tiene que ver con para qué es el código, no con qué canal lo transporta.

El email no es un factor de autenticación. 800-63B es categórico:

Email SHALL NOT be used for out-of-band authentication because it may be vulnerable to:

  • Access using only a password
  • Interception in transit or at intermediate mail servers
  • Rerouting attacks, such as those caused by Domain Name System (DNS) spoofing

El mismo pasaje contempla el caso para el que está construido el canal de email de Verify:

Confirmation codes that are sent to validate email addresses or are issued as recovery codes (see Sec. 4.2.1.2) are not authentication processes and not affected by the above prohibition.

Un código por email que demuestra que alguien controla una dirección entra dentro de la excepción del estándar y es válido. Un código por email usado como segundo factor en el inicio de sesión no lo es. Si tu flujo es el segundo caso, no recurras al canal de email.

SMS y voz están permitidos pero restringidos. La entrega por la red telefónica conlleva tres obligaciones, en dos oraciones consecutivas:

Accordingly, verifiers SHALL ensure that alternative authenticator types are available to all subscribers and SHOULD remind subscribers of this limitation of PSTN out-of-band authenticators before binding one or more devices controlled by the subscriber. Verifiers SHOULD consider risk indicators (e.g., device swap, SIM change, number porting, other abnormal behavior) before using the PSTN to deliver an out-of-band authentication secret.

El SHALL es un requisito de producto, no una configuración de Verify: si SMS es tu único factor, no lo cumples. El orden de canales por país de Verify ayuda con la entrega, porque WhatsApp se intenta primero en la mayoría de países con SMS como respaldo (Canales), pero SMS, WhatsApp, Telegram y las llamadas de voz son todas rutas de entrega para un mismo tipo de autenticador, fuera de banda, así que alternar entre ellas no es ofrecer un tipo alternativo. Los dos SHOULD son los que implementa un equipo de producto: un aviso en el momento en que el usuario vincula un número de teléfono, y una revisión de señales de portabilidad y cambio de SIM antes de enviar a ese número.

Lee el fallo antes de reenviar

Un código que no llega y un código que llega y se teclea mal necesitan tratamientos distintos, y los eventos los diferencian (Eventos).

verify.attempt.undelivered incluye un reason, y lo que ocurre después depende del plan de canales del destinatario. En un destinatario con más de un canal disponible, no termina la verificación: Bird avanza al siguiente canal, que recibe su propio verify.attempt.sent, así que un único intento no entregado no es una verificación muerta y no necesita un reenvío de tu parte. En un destinatario con un solo canal no hay a dónde avanzar, y la verificación termina.

Ese final necesita su propio tratamiento, y un evento lo identifica. El estado failed es compartido: una verificación llega a él tanto cuando se enviaron demasiados códigos de verificación incorrectos, con reason attempts_exhausted, como cuando ningún canal previsto pudo entregar uno, con reason undeliverable. Solo el segundo emite verify.verification.failed. Así que en un destinatario con un solo canal es ese evento, no el estado, lo que te indica que nadie recibió un código.

Una propiedad para tener en cuenta desde el diseño en lugar de descubrirla después, y esta es propia de Bird y no del estándar: Eventos indica que los informes de entrega son orientativos, no garantizados, porque los operadores y proveedores de correo varían en lo que confirman y en la rapidez con que lo hacen. En algunos mercados un evento de intento llega minutos tarde o no distingue entre entrega y aceptación. Construye la ruta de "I didn't get a code" sobre POST /v1/verify/verifications/next-channel, que avanza la verificación, en lugar de esperar un evento de entrega que puede no llegar.

Reintenta la solicitud, no la verificación

Los tres endpoints de Verify aceptan Idempotency-Key (Reintentar de forma segura). Tras un timeout o una conexión interrumpida, reintentar con la misma clave reproduce la respuesta original: no se envía un segundo código ni se consume un intento de comprobación. Sin clave, un reintento tras una respuesta perdida envía otro código y gasta otro envío contra el tope por hora.

Conoce el coste de cada envío

La facturación se aplica a cada código enviado, a la tarifa del canal para el destino, y un reenvío o un respaldo añade un cargo por envío (Coste y facturación). Dos consecuencias condicionan una política de reintentos:

  • Una verificación que pasa por varios canales cuesta varios envíos, así que un plan de canales amplio es tanto una decisión de coste como de entrega.
  • Telegram cobra cuando acepta para entrega un número alcanzable, no cuando hay un recibo de entrega (Coste y facturación). Por eso, un intento por Telegram que luego no se entrega sigue facturado cuando la sesión pasa al siguiente canal. Retira Telegram del orden de canales en la página Destinations para los destinos en los que quieras evitar ese coste de respaldo.

Próximos pasos