Sign inGet Started

Enviar verificaciones

Verificar a un usuario requiere dos llamadas. POST /v1/verify/verifications envía un código de verificación a una dirección de correo electrónico o un número de teléfono. POST /v1/verify/verifications/check envía el valor que introdujo el usuario e informa si coincidió. Bird genera el código, no lo devuelve en una respuesta API, y aplica los límites de expiración e intentos.

Enviar un código

La solicitud válida más pequeña es un destinatario to:

const verification = await bird.verify.verifications.create({
  to: { phone_number: "+15551234567" },
});
console.log(verification.id, verification.status);

Usa tu host regional (https://us1.platform.bird.com o https://eu1.platform.bird.com) con una clave bk_{region}_... correspondiente.

Destinatario

to identifica al destinatario con un email, un phone_number en formato E.164, o ambos. Una dirección de correo electrónico habilita la entrega por correo electrónico. Un número de teléfono se resuelve en los canales disponibles en su país de destino, en el orden definido por la configuración por país. La mayoría de los países intentan WhatsApp antes que SMS, mientras que algunos intentan SMS primero; Telegram va después de ambos en el orden de respaldo de la plataforma. Solo se usa una llamada de voz en los países donde activaste la voz. Cuando proporcionas ambas direcciones, un intento fallido puede pasar a otro canal disponible.

Opciones

options sobrescribe la configuración solo para esta solicitud:

  • code_length: longitud del código de verificación para esta verificación, de 4 a 8 dígitos, sobrescribiendo el valor predeterminado.
  • channels: reordena o reduce los canales de entrega para esta solicitud. Indica los nombres de canal (sms, whatsapp, email, telegram, voice) en el orden en que deben intentarse; un canal que omitas no se usa, y un nombre que no esté en el plan resuelto del destinatario se ignora. No puedes añadir un canal de esta forma, solo recortar o reordenar lo que el destinatario y la configuración por país ya permiten. Si la lista no deja ningún canal utilizable, la solicitud falla con 422.
  • language: una etiqueta BCP 47 como fr o pt-BR que selecciona qué traducción integrada usa el mensaje con el código. Si la omites, el idioma sigue el número de teléfono del destinatario; consulta Idioma del mensaje.
  • autofill_origin: el sitio web donde tu usuario introduce el código, como https://login.example.com, para que los navegadores, y las apps de correo que lo admiten, puedan ofrecer el código en ese sitio. Sustituye el Website configurado para esta verificación.
  • autofill_top_level_origin: si el código se introduce en un iframe de otro origen, como un formulario de pago incrustado en el checkout de una tienda, es el sitio web de la página que aparece en la pestaña del navegador. En ese caso, autofill_origin indica el sitio web del iframe y debe ser distinto de este.
  • android_app_hash: el hash de app de 11 caracteres de la app Android que lee el código de SMS, como FA+9qCX9VSu. Sustituye el Android app hash configurado para esta verificación, y el SMS pasa a ser un mensaje corto que termina con el hash.

Autocompletado explica el formato del sitio web, qué añade Verify a SMS y al correo electrónico, cómo configurar el iframe y cómo calcular un hash de app.

Metadatos

metadata es un objeto de forma libre que se devuelve en cada lectura; úsalo para llevar tu propio ID de usuario o referencia de sesión. Las opciones de remitente y la configuración de verificación no van en la solicitud: provienen de la configuración de tu espacio de trabajo, gestionada en el dashboard (consulta Configuración de verificación).

La respuesta

Ejemplo de código
{
  "id": "vrf_01ky7q1fdze3695yvyz7z9nm3a",
  "status": "pending",
  "reason": null,
  "to": { "phone_number": "+15551234567" },
  "channels": [{ "channel": "whatsapp" }, { "channel": "sms" }],
  "last_channel": "whatsapp",
  "expires_at": "2026-07-23T14:55:58Z",
  "verified_at": null,
  "created_at": "2026-07-23T14:45:58Z",
  "updated_at": "2026-07-23T14:45:58Z"
}

channels es el plan de entrega ordenado al que resolvió esta verificación (un destinatario telefónico lista sus canales telefónicos en orden de intento), y last_channel es adónde fue el código más reciente. expires_at es cuándo la verificación caduca si no llega un código correcto; los reenvíos no lo extienden.

Idioma del mensaje

Los mensajes de SMS, correo electrónico y WhatsApp compartido de Bird incluyen 40 traducciones integradas. Un remitente WhatsApp personalizado usa los idiomas aprobados de su plantilla de autenticación seleccionada. Telegram redacta su propio mensaje y una llamada de voz lee el código en inglés, por lo que esta configuración no tiene efecto en ninguno de los dos.

Sin options.language, el idioma proviene del número de teléfono del destinatario. Un número francés recibe francés y un número japonés recibe japonés, sin que lo solicites. Una verificación sin número de teléfono envía en inglés, al igual que una cuyo país no tiene traducción.

Establece options.language para elegir tú mismo, por ejemplo para coincidir con el idioma que tu usuario seleccionó en tu app en lugar del país de su número:

Ejemplo de código
{
  "to": { "phone_number": "+15551234567" },
  "options": { "language": "es" }
}

Una etiqueta sin traducción integrada propia recurre a su idioma base y luego al inglés: en-GB envía en inglés, pt-BR envía en portugués. Solo se rechaza una etiqueta con formato incorrecto, con 422. Estas son las traducciones integradas que puedes solicitar, todas disponibles en SMS y correo electrónico, y todas excepto mongol en el remitente WhatsApp compartido de Bird:

IdiomaEtiqueta
Árabear
Búlgarobg
Chino (simplificado)zh
Chino (tradicional)zh-TW
Croatahr
Checocs
Danésda
Neerlandésnl
Inglésen
Finésfi
Francésfr
Alemánde
Griegoel
Hebreohe
Hindihi
Húngarohu
Indonesioid
Italianoit
Japonésja
Coreanoko
Letónlv
Lituanolt
Macedoniomk
Malayoms
Mongolmn
Noruegono
Noruego bokmålnb-NO
Polacopl
Portuguéspt
Rumanoro
Rusoru
Serbiosr
Eslovacosk
Eslovenosl
Españoles
Suecosv
Tailandésth
Turcotr
Ucranianouk
Vietnamitavi

La referencia de create-verification es la lista oficial.

El idioma queda fijo cuando se crea la verificación, así que un reenvío o un cambio a otro canal llega en el mismo idioma que el primer mensaje. Llamar a create de nuevo para el mismo destinatario con un language diferente reutiliza la verificación en curso y no la modifica.

La traducción que usó un envío puede diferir de la etiqueta que enviaste si se recurrió a un idioma alternativo. Abre la verificación en la página Verifications para confirmarlo: cada intento muestra el idioma renderizado como una etiqueta Template. El remitente WhatsApp compartido de Bird no tiene plantilla de mongol (mn), así que envía en inglés para ese idioma mientras que SMS y el correo electrónico mantienen el mongol. Tu propia plantilla de WhatsApp sigue sus idiomas aprobados y su política de idioma; un idioma que no puede enviar puede hacer fallar el intento de WhatsApp.

Puedes seleccionar un idioma por solicitud, pero no puedes enviar el texto del mensaje con esa solicitud. Un remitente WhatsApp personalizado usa el texto de la plantilla de autenticación seleccionada. Remitentes y marca muestra las opciones de remitente y el texto del mensaje de Bird.

Comprobar el código

Envía lo que el usuario escribió a POST /v1/verify/verifications/check, identificado por el mismo destinatario; no necesitas un ID de verificación. Proporciona exactamente el conjunto de to con el que creaste la verificación: una creada con ambas direcciones no se encuentra con una sola.

const result = await bird.verify.verifications.check({
  to: { phone_number: "+15551234567" },
  code: "123456",
});
console.log(result.success);

La respuesta indica si coincidió:

Ejemplo de código
{
  "success": false,
  "reason": "incorrect_code",
  "attempts_remaining": 4,
  "verification": {
    "id": "vrf_01ky7q1fdze3695yvyz7z9nm3a",
    "status": "pending",
    "reason": null,
    "to": { "phone_number": "+15551234567" },
    "channels": [{ "channel": "whatsapp" }, { "channel": "sms" }],
    "last_channel": "whatsapp",
    "expires_at": "2026-07-23T14:55:58Z",
    "verified_at": null,
    "created_at": "2026-07-23T14:45:58Z",
    "updated_at": "2026-07-23T14:46:38Z"
  }
}

Maneja estos dos comportamientos de respuesta:

  • Un código incorrecto devuelve 200. Trata success: false con un reason (incorrect_code, expired, attempts_exhausted) como una respuesta normal. attempts_remaining te indica cuántos intentos quedan. Reserva el manejo de errores para fallos de la solicitud.
  • Una verificación final no se puede comprobar de nuevo. Después de que una verificación alcanza cualquier estado final, las comprobaciones posteriores devuelven 404. Almacena el primer resultado definitivo en lugar de comprobar otra vez.

Si el usuario pidió un código nuevo, llama al endpoint de creación otra vez con el mismo destinatario: la verificación en curso se reutiliza en lugar de reemplazarse. Una vez que ha pasado el tiempo de espera de reenvío, se envía un código nuevo; dentro del tiempo de espera, la llamada devuelve la verificación activa sin enviar de nuevo. Cada código enviado para la verificación activa sigue siendo válido hasta que se resuelve o expira, así que el usuario puede introducir cualquiera que haya llegado.

Enviar el código por otro canal

Cuando el usuario informa que no llegó ningún código, POST /v1/verify/verifications/next-channel avanza la verificación al siguiente canal en su plan y envía un código nuevo allí. Este es el endpoint detrás de un botón "I didn't receive my code": tu app decide cambiar de canal en lugar de esperar una señal de estado de entrega.

Identifícalo con el mismo destinatario con el que creaste la verificación, igual que en una comprobación:

const verification = await bird.verify.verifications.nextChannel({
  to: { phone_number: "+15551234567" },
});
console.log(verification.last_channel);

La respuesta es la verificación, con last_channel indicando el canal al que fue el nuevo código. Cada código ya enviado sigue siendo válido, así que un mensaje que llegue tarde aún puede comprobarse.

Dos cosas lo diferencian de un reenvío:

  • El tiempo de espera de reenvío no aplica. Un cambio de canal deliberado es un acto diferente a pedir el mismo canal otra vez, así que el envío sale de inmediato.
  • Solo el canal avanza. La expiración, el presupuesto de intentos y el ID de verificación permanecen como estaban.

Usa un reenvío cuando el usuario quiera otro intento en un canal que funciona, y este endpoint cuando el canal en sí parece ser el problema. Un número de teléfono cuyo plan es WhatsApp y luego SMS avanza a SMS; un destinatario con un solo canal utilizable no tiene adónde avanzar.

Cuatro respuestas requieren manejo en lugar de un simple reintento:

EstadoQué ocurrióQué hacer
404No hay verificación en curso para ese destinatarioCrea una
422 NoNextChannelEl plan no tiene más canales a los que avanzarReenvía en el canal actual llamando a create de nuevo
422 NoAvailableChannelTodos los canales restantes fallaron al enviarMuestra el fallo al usuario; la verificación no se puede entregar
429Los envíos de la cuenta se están solicitando demasiado rápidoEspera el período indicado en el encabezado Retry-After

Cada código que envía este endpoint se factura como cualquier otro envío de Verify; consulta Costo y facturación.

Estados

Una verificación está en pending hasta que se resuelve en un estado final, con reason indicando el motivo:

EstadoSignificadoRazón
verifiedUn código correcto llegó a tiemponinguna
failedDemasiados intentos incorrectos, o el plan de entrega terminó con fallos que indican que no se envió ningún código de verificaciónattempts_exhausted, undeliverable
expiredLa ventana expiró antes de recibir un código correctottl_elapsed

reason es un enum abierto. Conserva un valor no reconocido en lugar de tratar la respuesta como inválida.

Un rebote, rechazo del operador o tiempo de espera de entrega agotado pueden dejar la sesión pendiente porque el destinatario aún puede tener un código válido. El agotamiento del plan de entrega por sí solo no significa que la sesión haya fallado. Consulta Eventos de Verify para conocer las condiciones de fallo.

Seguimiento de verificaciones en el dashboard

La página Verifications lista todas las verificaciones que creó el espacio de trabajo, filtrable por estado. Cada fila muestra el destinatario, el plan de canales, el último canal, los tiempos de expiración y verificación, y los metadatos. El código generado no se muestra.

La página Verifications listando verificaciones con columnas de estado, destinatario, canal y fecha de creación

Configuración de verificación

La pestaña General de la página Configure define cuánto tiempo permanece abierta una verificación, cuántos códigos incorrectos acepta, el tiempo de espera de reenvío y el sitio web o la app Android en los que se autocompletan los códigos. Configuración de verificación indica el valor predeterminado, el rango y el efecto de cada ajuste.

Protecciones contra abuso

Independientemente de tus ajustes, Verify aplica límites de plataforma para evitar que el tráfico de OTP se use como arma, ya sea contra tu saldo (bombeo de SMS) o contra la bandeja de entrada de una víctima:

  • 5 envíos por dirección por hora continua, contando tanto verificaciones nuevas como reenvíos. Cuando to contiene ambas direcciones, cada una tiene su propio presupuesto.
  • 10 comprobaciones por conjunto de direcciones del destinatario por minuto, además del límite de intentos de la verificación.

El plan de canales, no el límite por hora, determina los cambios de canal. Cada llamada avanza estrictamente hacia adelante, por lo que una verificación envía como máximo una vez por cada canal restante.

Alcanzar un límite devuelve 429; espera y reintenta después del período indicado en el encabezado Retry-After. Los límites generales de solicitudes de tu cuenta son independientes y se escalan según tu plan; consulta Límites de solicitudes.

Reintentar de forma segura

Los tres endpoints aceptan el encabezado Idempotency-Key. Envía un valor único por cada solicitud lógica. Después de un tiempo de espera agotado o una conexión interrumpida, reintentar con la misma clave reproduce la respuesta original. Una reproducción no envía otro código ni consume otro intento de comprobación, e incluye un encabezado Idempotency-Replay. Consulta idempotencia para el formato de clave y su retención.

Costes y facturación

Se factura cada código enviado. Cada código enviado se cobra a tu saldo según la tarifa del canal para el destino. Un reenvío o un respaldo a otro canal añade un cargo por envío. La tarifa propia de Bird se cobra mientras se procesa el envío y se mantiene tanto si el código llega como si no; en SMS y WhatsApp se añade una tarifa de terceros cuando el mensaje se entrega. Las rutas gratuitas y las comprobaciones no tienen coste; un envío rechazado antes de la facturación no se cobra. Métodos de pago y saldo explica el saldo y las recargas.

Telegram factura en un punto diferente del envío. Antes de que salga un mensaje, se consulta a Telegram si el número puede recibirlo; el cargo se aplica cuando la respuesta es sí, a una tarifa fija mundial, y un número al que no se puede llegar es gratuito y pasa al siguiente canal sin cobro. Por tanto, un cargo de Telegram significa que el mensaje fue aceptado para su entrega, no que llegó: un código que luego no se entrega sigue cobrado, y la verificación paga de nuevo por el canal al que pasa. Si no quieres ese segundo cargo, retira Telegram del orden de canales para esos países en la página Destinations.

La voz se factura como una llamada telefónica, no por código, y no lleva tarifa de Verify. Una llamada que no se contesta no tiene coste. Una llamada contestada se cobra desde que se contesta hasta que se cuelga, según la tarifa de voz saliente del destino, con el tiempo mínimo facturable y los incrementos de esa tarifa, más la tarifa de gestión de llamadas de Bird. Ambas aparecen en la página de precios de voz; consulta Costes y facturación de voz para saber cómo se calcula el tiempo facturable. Una llamada que termina antes de que se lea el código completo se cobra igualmente por el tiempo que estuvo conectada, aunque el intento se notifique como undelivered.

Próximos pasos

PáginaQué trata
Remitentes y marcaCómo se ven los mensajes con el código y cómo enviar desde tu propio dominio
Destinos de VerifyOrden de canales por país, habilitación y anulaciones de remitente
EventosEl ciclo de vida de la verificación y los eventos de entrega, y sus payloads de webhook
IdempotenciaReintentos seguros con el encabezado Idempotency-Key
Referencia de API: crear una verificaciónEsquema del endpoint de envío y detalles de errores
Referencia de API: comprobar un códigoEsquema del endpoint de comprobación y detalles de errores
Referencia de API: avanzar al siguiente canalEsquema del endpoint de siguiente canal y detalles de errores