Webhooks
Reporta los resultados de verificación a Novauth para que los registros de sesión se mantengan actualizados. Cada canal expone un endpoint de webhook dedicado al que tu servidor llama después de observar el resultado.
Cómo funciona
Novauth no envía eventos a tu servidor. En cambio, tu backend observa el resultado de la verificación (a través del SDK móvil, tu propia lógica de aplicación o una encuesta de comprobación de estado) y luego envía el resultado al endpoint de webhook de Connect Hub mediante POST.
Todos los endpoints de webhook requieren el mismo encabezado x-api-key utilizado para las solicitudes de API habituales. Devuelve HTTP 200 para confirmar la recepción.
Verify Call
Después de que tu SDK móvil lea el ID de llamada entrante, reporta si los dígitos coincidieron con el llamante esperado.
uuidstringstatus"Success" | "Failed" | "Incomplete" | "WrongNumber"{
"uuid": "01J8K2M3N4P5Q6R7S8T9U0V1W2",
"status": "Success"
}
// Possible status values:
// "Success" — caller ID matched, user verified
// "Failed" — call was not answered or no match
// "Incomplete" — call dropped before matching
// "WrongNumber" — mismatch detected# After initiating a flash call, POST the result back to Novauth:
curl -X POST https://api.novauth.com/api/v1/connect-hub/call/flash/webhook \
-H "x-api-key: YOUR_API_KEY" \
-H "x-account-id: YOUR_ACCOUNT_ID" \
-H "Content-Type: application/json" \
-d '{
"uuid": "01J8K2M3N4P5Q6R7S8T9U0V1W2",
"status": "Success"
}'SMS
Una vez que tu servidor confirma que el usuario introdujo el código OTP correcto, reporta el estado de entrega de vuelta a Novauth.
idstringstatus"delivered" | "sent" | "failed" | "undelivered"{
"id": "msg_01J8K2M3N4P5Q6R7S8T9",
"status": "delivered"
}
// Possible status values (from carrier):
// "delivered" — confirmed delivery to handset
// "sent" — dispatched to carrier, awaiting DLR
// "failed" — delivery failed (invalid number, blocked, etc.)
// "undelivered" — carrier accepted but delivery not confirmedcurl -X POST https://api.novauth.com/api/v1/connect-hub/sms/webhook \
-H "x-api-key: YOUR_API_KEY" \
-H "x-account-id: YOUR_ACCOUNT_ID" \
-H "Content-Type: application/json" \
-d '{
"id": "msg_01J8K2M3N4P5Q6R7S8T9",
"status": "delivered"
}'Reporta el resultado de entrega del OTP de WhatsApp. Solo son posibles dos estados.
uuidstringstatus"Success" | "Failed"{
"uuid": "01J8K2M3N4P5Q6R7S8T9U0V1W2",
"status": "Success"
}
// Only two status values:
// "Success" — WhatsApp OTP delivered to user
// "Failed" — delivery failed (user not on WhatsApp, etc.)curl -X POST https://api.novauth.com/api/v1/connect-hub/whatsapp/webhook \
-H "x-api-key: YOUR_API_KEY" \
-H "x-account-id: YOUR_ACCOUNT_ID" \
-H "Content-Type: application/json" \
-d '{
"uuid": "01J8K2M3N4P5Q6R7S8T9U0V1W2",
"status": "Success"
}'OTP de Telegram
Reporta la entrega del mensaje de Telegram. Usa POST /check-verification-status para la validación del código del lado del servidor; consulta el inicio rápido de OTP de Telegram para el flujo completo.
idstringstatus"Success" | "Failed"{
"id": "01J8K2M3N4P5Q6R7S8T9U0V1W2",
"status": "Success"
}
// Only two status values:
// "Success" — Telegram message delivered
// "Failed" — delivery failed (user blocked bot, etc.)curl -X POST https://api.novauth.com/api/v1/connect-hub/telegram/webhook \
-H "x-api-key: YOUR_API_KEY" \
-H "x-account-id: YOUR_ACCOUNT_ID" \
-H "Content-Type: application/json" \
-d '{
"id": "01J8K2M3N4P5Q6R7S8T9U0V1W2",
"status": "Success"
}'Entrada de Telegram Gateway
Cuando pasas un callback_url en tu solicitud de envío de Telegram, Telegram Gateway enviará eventos de estado de verificación directamente a esa URL mediante POST. A diferencia de los otros canales, tú eres el receptor, y Telegram firma cada solicitud con HMAC-SHA256.
X-Request-TimestampSegundos de época Unix (entero). Rechaza si |ahora − timestamp| > 300.X-Request-SignatureHMAC-SHA256 codificado en hexadecimal. Verifica con comparación de tiempo constante.secret = SHA256(access_token) · data = "{timestamp}\n{rawBody}" · sig = HMAC-SHA256(secret, data)// Telegram Gateway sends status updates to your callback_url
// when you provided it in the original send request.
// Payload (example):
{
"request_id": "tg_req_abc123",
"phone_number": "+14155552671",
"status": "code_valid",
"verification_status": {
"status": "code_valid",
"updated_at": 1713350400
}
}
// status values:
// "code_valid" — user entered correct code
// "code_invalid" — wrong code entered
// "code_max_attempts_exceeded" — too many attempts
// "expired" — TTL elapsed before entryimport { createHmac, timingSafeEqual } from 'node:crypto';
app.post('/telegram/gateway-callback', express.raw({ type: '*/*' }), (req, res) => {
const timestamp = req.headers['x-request-timestamp'];
const signature = req.headers['x-request-signature'];
const rawBody = req.body; // must be raw Buffer
// 1. Replay-attack guard — reject requests older than 5 minutes
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) {
return res.status(401).json({ error: 'Request expired' });
}
// 2. Derive signing secret: SHA256 of your Telegram Gateway access token
const secret = createHmac('sha256', '')
.update(process.env.TELEGRAM_GATEWAY_TOKEN)
.digest();
// 3. Compute expected signature
const data = `${timestamp}\n${rawBody}`;
const expected = createHmac('sha256', secret).update(data).digest('hex');
// 4. Timing-safe comparison
const sigBuf = Buffer.from(signature ?? '', 'hex');
const expBuf = Buffer.from(expected, 'hex');
if (sigBuf.length !== expBuf.length || !timingSafeEqual(sigBuf, expBuf)) {
return res.status(401).json({ error: 'Invalid signature' });
}
const payload = JSON.parse(rawBody.toString());
console.log('Telegram Gateway event:', payload.status);
res.status(200).json({ ok: true });
});Analiza siempre el cuerpo después de verificar la firma, y hazlo desde el búfer de bytes en bruto, no desde un objeto JSON ya analizado. La re-serialización de JSON puede alterar el orden de los bytes y romper el HMAC.