La API de OTP para desarrolladores que necesitan que los códigos lleguen.
SMS primero, respaldo por voz en un solo atributo, puntuación de fraude al iniciar, límites de frecuencia por destinatario. La misma autenticación, la misma idempotencia, los mismos webhooks que cualquier otro canal de Bird — porque el mismo equipo de ingeniería los construyó todos.
import { BirdClient } from "@bird/sdk";
const bird = new BirdClient({ apiKey: process.env.BIRD_API_KEY! });
// 1. Start the verification.
const { data: start, error: startErr } = await bird.verifications.start({
to: "+15005550006",
channel: "sms",
fallback: "voice",
expires: "10m",
}).safe();
if (startErr) throw startErr;
// → { id: "ver_8sQ91pZ4...", risk_score: 0.04, status: "pending" }
// 2. Check the code the user typed.
const { data: check, error: checkErr } = await bird.verifications.check({
id: start.id,
code: "482917",
}).safe();
if (checkErr) throw checkErr;
console.log(check.status);
// → "approved"5 minutos desde npm install hasta la primera verificación
Inicia una verificación desde el lenguaje que ya usas.
SDK en todos los runtimes principales. La primera verificación se envía al número de prueba autorizado (+15005550006), así puedes incluir un check en CI antes de hablar con un operador.
import { BirdClient } from "@bird/sdk";
const bird = new BirdClient({ apiKey: process.env.BIRD_API_KEY! });
const { data, error } = await bird.verifications.start({
to: "+15005550006",
channel: "sms",
fallback: "voice",
expires: "10m",
}).safe();Diez pasos entre la llamada de inicio y la siguiente pantalla del usuario.
Primitivas concretas, con nombre y auditables. Nada de "detección de fraude con IA" sin sustancia.
- 01
SMS primero, respaldo por voz en un solo atributo
Pasa fallback: "voice" en el inicio. Si el SMS no llega en N segundos, llamamos en su lugar. Sin una segunda integración.
- 02
Puntuación de fraude al iniciar
Cada inicio devuelve un risk_score de 0 a 1. Bloquea los de alto riesgo antes de gastar un centavo en entrega.
- 03
Límites de frecuencia por destinatario
Límites configurables por número de teléfono en intentos por hora y por día. Bloquea la fuerza bruta a tu costa.
- 04
Enrutamiento según operador
Elegimos la ruta por operador y por país en tiempo real. T-Mobile US no es la misma línea que Reliance Jio.
- 05
Códigos generados en el servidor
Tú nunca ves el código; nosotros nunca lo exponemos en la red al enviarlo. Una superficie de filtración menos en tu stack.
- 06
TTL configurable
10 minutos por defecto, rango de 30s a 1h. TTL más corto = menor superficie de fraude; más largo = mejor UX móvil.
- 07
Contador de intentos con bloqueo
Máximo de intentos por verificación (5 por defecto). Tras el bloqueo, check devuelve verification_locked para una UX clara.
- 08
OTP por voz en más de 40 idiomas
Sintetizado en el momento del envío, con acento correcto según la región. La misma interfaz bird.verifications.start — solo channel: "voice".
- 09
Webhook en cada cambio de estado
Eventos: verification.created, verification.delivered, verification.checked, verification.expired. El mismo sobre HMAC.
- 10
Paga solo cuando el código llega
Sin cargo por verification.failed. El filtro de puntuación de fraude y el reembolso por no entrega mantienen el gasto honesto.
Why we build Verifications
Porque los códigos tienen que llegar en el primer intento, y no podemos pedírselo amablemente a los operadores.
OTP es el canal donde cada punto porcentual de entrega te cuesta un registro. Hemos gestionado SMS durante diez años a través de 240 conexiones directas con operadores, así que cuando un código no llega sabemos si es la ruta, el operador, el dispositivo o el filtro de fraude — y lo redirigimos en tiempo real. Bird Verifications es esa lógica de selección de ruta, más la puntuación de fraude, más el respaldo por voz, más el contador de intentos, expuestos como dos endpoints con la misma autenticación y contrato de webhooks que cualquier otro canal de Bird.
import { BirdClient } from "@bird/sdk";
const bird = new BirdClient({ apiKey: process.env.BIRD_API_KEY! });
// 1. Start the verification.
const { data: start, error: startErr } = await bird.verifications.start({
to: "+15005550006",
channel: "sms",
fallback: "voice",
expires: "10m",
}).safe();
if (startErr) throw startErr;
// → { id: "ver_8sQ91pZ4...", risk_score: 0.04, status: "pending" }
// 2. Check the code the user typed.
const { data: check, error: checkErr } = await bird.verifications.check({
id: start.id,
code: "482917",
}).safe();
if (checkErr) throw checkErr;
console.log(check.status);
// → "approved"Cada cambio de estado es un webhook.
Payloads firmados con HMAC, protegidos contra replay, idempotentes. El mismo sobre en cada canal de Bird — aprende uno y los conoces todos.
{
"type": "verification.delivered",
"id": "evt_5kQ81y...",
"created_at": "2026-05-19T15:42:01.221Z",
"data": {
"verification_id": "ver_8sQ91pZ4",
"to": "+15005550006",
"channel": "sms",
"carrier": "T-Mobile USA",
"risk_score": 0.04,
"latency_ms": 1421
}
}Programación de reintentos: 5s, 30s, 5m, 30m, 2h, 6h, 12h. Dead-letter tras el último intento; cada evento en dead-letter se puede reenviar desde el dashboard o la API.
verification.createdAceptado por la API; a punto de despachar por el primer canal.verification.deliveredEl operador confirmó la recepción en el dispositivo del destinatario.verification.checkedEl destinatario envió un código; el payload incluye approved o denied.verification.fellbackEl SMS no llegó en el plazo; se despachó el respaldo por voz.verification.expiredEl TTL expiró sin una verificación exitosa.verification.lockedSe alcanzó el máximo de intentos; las llamadas posteriores a check devuelven verification_locked.verification.failedFallo permanente antes del envío (destinatario inválido, rechazo del operador).
Si ya integraste SMS, ya integraste Verifications.
La misma autenticación, la misma idempotencia, el mismo sobre de errores, la misma estructura de webhooks. La diferencia es que Verifications genera el código, elige la ruta, ejecuta el filtro de fraude y gestiona el respaldo — para que tú no tengas que hacerlo.
Verifications.
await bird.verifications.start({
to: "+15005550006",
channel: "sms",
fallback: "voice",
});Una llamada. Nosotros elegimos el canal, la ruta, generamos el código, ejecutamos la verificación de fraude y gestionamos el bloqueo.
SMS.
await bird.sms.send({
from: "Bird",
to: "+15005550006",
text: `Your code is ${code}.`,
});El envío directo, para cuando quieres controlar tú la generación del código y la política de reintentos.