Eventos de Verify
Una verificación produce eventos para su sesión y cada intento de entrega. La sesión comienza cuando Bird crea la verificación y convierte cuando el destinatario introduce el código correcto. Cada envío de código de verificación crea un intento en un canal, que puede quedar entregado o no entregado. Los reenvíos y el failover de canal añaden intentos a la misma sesión.
| Evento | Eje | Se dispara cuando |
|---|---|---|
| verify.verification.created | Sesión | Se crea una verificación y el primer código de verificación se encola para envío |
| verify.attempt.sent | Entrega | Un código de verificación se entregó a un canal para su envío |
| verify.attempt.delivered | Entrega | El canal confirmó que el código de verificación llegó al destinatario |
| verify.attempt.undelivered | Entrega | El canal no pudo hacer llegar el código de verificación al destinatario |
| verify.verification.verified | Sesión | El destinatario envió el código correcto antes de que la verificación expirara |
| verify.verification.failed | Sesión | El plan de entrega terminó con fallos que indican que no se envió ningún código de verificación |
Una verificación que no convierte nunca emite verify.verification.verified, y su estado por sí solo no te dice por qué. failed es compartido: una verificación llega ahí tanto cuando se enviaron demasiados códigos de verificación incorrectos, con reason attempts_exhausted, como cuando el plan de entrega termina con fallos que indican que no se envió ningún código, con reason undeliverable. Solo el segundo caso emite verify.verification.failed, y ese evento siempre lleva reason undeliverable, así que el evento es lo que distingue ambos casos donde el estado no puede. Una ventana de validez que se agota se resuelve a expired. Ni expired ni un failed por intentos agotados emite un evento propio. Un canal de respaldo crea su propio verify.attempt.sent, por lo que una verificación puede tener múltiples secuencias de intentos.
La lista de tipos de evento es abierta: se pueden añadir nuevos tipos con el tiempo, así que trata un valor no reconocido como un evento futuro en lugar de un error.
El sobre del evento
Los eventos llegan a tu endpoint de webhook en el sobre anidado de Standard Webhooks descrito en la Guía de webhooks: un type, un timestamp y un objeto data específico del tipo. La identidad del evento no está en el cuerpo: viaja en el encabezado webhook-id HTTP, que es estable entre reintentos de la misma entrega y es tu clave de deduplicación.
El data de cada evento lleva esta base de identidad:
- verification_id: la verificación a la que pertenece este evento, que coincide con el id de POST /v1/verify/verifications
- workspace_id: el espacio de trabajo que creó la verificación
- to: la identidad del destinatario de la verificación, un objeto con email y/o phone_number que coincide con lo proporcionado en la solicitud de creación. Un intento individual de código de verificación informa la dirección a la que se envió en su propio campo address
- metadata: el objeto de forma libre de la solicitud de creación, devuelto sin cambios, o null cuando la solicitud no incluyó ninguno
Eventos de sesión
verify.verification.created
Se dispara en cuanto se crea una verificación y su primer código de verificación se encola. Añade channel (el canal por el que sale el primer intento), status: "pending" y created_at.
Ejemplo de código
{
"type": "verify.verification.created",
"timestamp": "2026-07-23T14:45:58Z",
"data": {
"verification_id": "vrf_01ky7q1fdze3695yvyz7z9nm3a",
"workspace_id": "ws_01ky7m235keycbnwyajabe1a6b",
"channel": "sms",
"to": { "phone_number": "+14155550100" },
"status": "pending",
"created_at": "2026-07-23T14:45:58Z",
"metadata": { "user_id": "usr_4821" }
}
}verify.verification.verified
Se dispara cuando POST /v1/verify/verifications/check confirma el código correcto. Añade status: "verified", channel (el canal que entregó el código enviado, o null cuando la verificación se resolvió sin atribuir un canal) y verified_at.
Ejemplo de código
{
"type": "verify.verification.verified",
"timestamp": "2026-07-23T14:46:38Z",
"data": {
"verification_id": "vrf_01ky7q1fdze3695yvyz7z9nm3a",
"workspace_id": "ws_01ky7m235keycbnwyajabe1a6b",
"to": { "phone_number": "+14155550100" },
"status": "verified",
"channel": "sms",
"verified_at": "2026-07-23T14:46:38Z",
"metadata": { "user_id": "usr_4821" }
}
}verify.verification.failed
Se dispara cuando el plan de entrega se agota y los fallos registrados indican que no se envió ningún código de verificación. El payload añade status: "failed", reason: "undeliverable", channel (el último canal intentado, o null cuando no se atribuyó ninguno), last_attempt_reason y failed_at.
channel_unavailable, channel_disabled, channel_restricted y not_billable indican que un intento no envió un código de verificación. Si un intento pudo haberlo enviado, un rebote posterior, un rechazo del operador o un tiempo de espera de entrega agotado deja la sesión pendiente y no emite verify.verification.failed. Un código anterior aún puede verificarse antes de expirar.
last_attempt_reason usa las mismas razones de fallo que verify.attempt.undelivered. Un fallo not_billable significa que el envío no se pudo cobrar; comprueba el saldo del espacio de trabajo y si hay precios disponibles para el destino.
Eventos de entrega
Cada código de verificación que envía Bird es un intento. Un reenvío o una conmutación de canal crea otro intento contra el mismo verification_id, con su propia secuencia de entrega. Ningún evento lleva un identificador de intento, y webhook-id no los agrupa: identifica una entrega de un evento, así que el sent y el delivered de un mismo intento llevan valores distintos. Relaciónales por verification_id, channel y address en orden cronológico. Un reenvío por el mismo canal es el caso que rompe esta regla, ya que sus eventos solo difieren en la marca de tiempo.
verify.attempt.sent
Se dispara cuando Bird entrega el código de verificación al canal. Añade channel, address (la dirección a la que se envió este intento, un número de teléfono E.164 o una dirección de correo electrónico), from (la dirección o número de envío, null cuando el canal no expone remitente) y sent_at.
Ejemplo de código
{
"type": "verify.attempt.sent",
"timestamp": "2026-07-23T14:45:59Z",
"data": {
"verification_id": "vrf_01ky7q1fdze3695yvyz7z9nm3a",
"workspace_id": "ws_01ky7m235keycbnwyajabe1a6b",
"to": { "phone_number": "+14155550100" },
"channel": "sms",
"address": "+14155550100",
"from": "29999",
"sent_at": "2026-07-23T14:45:59Z",
"metadata": { "user_id": "usr_4821" }
}
}verify.attempt.delivered
Se dispara cuando el canal confirma que el código de verificación llegó al destinatario. Añade channel, address, carrier, mcc_mnc (la red que lo gestionó y su código de país/red móvil) y delivered_at. Los campos carrier y mcc_mnc siempre son null para correo electrónico, WhatsApp y Telegram. Este evento omite from; consúltalo en verify.attempt.sent para el mismo intento.
Ejemplo de código
{
"type": "verify.attempt.delivered",
"timestamp": "2026-07-23T14:46:03Z",
"data": {
"verification_id": "vrf_01ky7q1fdze3695yvyz7z9nm3a",
"workspace_id": "ws_01ky7m235keycbnwyajabe1a6b",
"to": { "phone_number": "+14155550100" },
"channel": "sms",
"address": "+14155550100",
"carrier": "Example Wireless",
"mcc_mnc": "310260",
"delivered_at": "2026-07-23T14:46:03Z",
"metadata": { "user_id": "usr_4821" }
}
}verify.attempt.undelivered
Se dispara cuando el canal no pudo entregar el código de verificación. Añade channel, address, reason (un enum abierto que incluye carrier_rejected, hard_bounce, soft_bounce, undelivered, channel_unavailable, channel_restricted, channel_disabled, delivery_timeout y not_billable), error (detalle solo para visualización, o null) y failed_at. Como verify.attempt.delivered, este evento omite from.
Ejemplo de código
{
"type": "verify.attempt.undelivered",
"timestamp": "2026-07-23T14:46:04Z",
"data": {
"verification_id": "vrf_01ky7q1fdze3695yvyz7z9nm3a",
"workspace_id": "ws_01ky7m235keycbnwyajabe1a6b",
"to": { "phone_number": "+14155550100" },
"channel": "sms",
"address": "+14155550100",
"reason": "carrier_rejected",
"error": "Carrier rejected the message before delivery",
"failed_at": "2026-07-23T14:46:04Z",
"metadata": { "user_id": "usr_4821" }
}
}Un intento no entregado en un destinatario con más de un canal disponible no finaliza la verificación. Bird avanza al siguiente canal en el plan de entrega, que recibe su propio verify.attempt.sent. Un canal que falla antes de enviar emite verify.attempt.undelivered con reason: "channel_unavailable" y avanza de la misma manera, al igual que uno que no transporta códigos de verificación al país del destinatario, con reason: "channel_restricted" (consulta Configuración por país). Ese intento no tiene verify.attempt.sent ni informe de entrega posterior. Bird emite verify.attempt.undelivered por cada intento fallido. Si el plan se agota y los fallos registrados indican que no se envió ningún código de verificación, también emite verify.verification.failed para la sesión.
Los informes de entrega son indicativos, no garantizados. Los operadores y proveedores de correo varían en lo que confirman y en la rapidez con que lo hacen. En algunos mercados, los eventos de intento llegan minutos después o no distinguen entre entrega y aceptación. Trata verify.verification.verified como la señal definitiva de que el destinatario recibió y usó su código.
Webhooks
Suscribe un endpoint a cualquier tipo verify.* desde la página Webhooks en el dashboard o mediante la API de webhooks. La Guía de webhooks cubre la creación de endpoints, la verificación de la firma de Standard Webhooks, los reintentos y la reproducción de entregas fallidas.
Próximos pasos
| Página | Qué cubre |
|---|---|
| Enviar verificaciones | Las llamadas de envío y comprobación, estados, configuración y límites |
| Webhooks y eventos | Configuración de endpoints, verificación de firma, reintentos y reproducción |
| Referencia de API: crear una verificación | Esquema del endpoint de envío y detalles de errores |
Recursos relacionados
Continúa con la documentación, guías y ejemplos sobre este tema. Los recursos están en inglés.
Ver la guíaVerify phone numbers at signupComprender el conceptoWhat does OTP mean? One-time passwords explainedExplorar la funcionalidadCustomer verificationSeguir la ruta de aprendizajeBuild your first integration
Prueba el ejercicio y obtén un resumen de implementación