Webhooks
Comunique os resultados das verificações à Novauth para que os registos de sessão se mantenham exatos. Cada canal expõe um endpoint de webhook dedicado que o seu servidor chama depois de observar o resultado.
Como funciona
A Novauth não envia eventos por push para o seu servidor. Em vez disso, o seu backend observa o resultado da verificação (através do SDK móvel, da lógica da sua própria aplicação ou de uma consulta de estado) e depois faz POST do resultado para o endpoint de webhook do Connect Hub.
Todos os endpoints de webhook requerem o mesmo cabeçalho x-api-key usado nos pedidos normais à API. Devolva HTTP 200 para confirmar.
Verify Call
Depois de o seu SDK móvel ler o ID de chamada recebido, comunique se os dígitos corresponderam ao autor da chamada 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
Assim que o seu servidor confirmar que o utilizador introduziu o código OTP correto, comunique o estado de entrega à 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"
}'Comunique o resultado da entrega do OTP do WhatsApp. Só há dois estados possíveis.
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 do Telegram
Comunique a entrega da mensagem do Telegram. Use POST /check-verification-status para a validação do código do lado do servidor — consulte o início rápido do OTP do Telegram para o fluxo 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"
}'Receção do Telegram Gateway
Quando passa um callback_url no seu pedido de envio do Telegram, o Gateway do Telegram fará POST dos eventos de estado da verificação diretamente para esse URL. Ao contrário dos outros canais, o recetor é você — e o Telegram assina cada pedido com HMAC-SHA256.
X-Request-TimestampSegundos de época Unix (inteiro). Rejeite se |agora − timestamp| > 300.X-Request-SignatureHMAC-SHA256 codificado em hexadecimal. Verifique com comparação em tempo 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 });
});Faça sempre o parse do corpo depois da verificação da assinatura, e faça-o a partir do buffer de bytes original — não de um objeto JSON já processado. A re-serialização do JSON pode alterar a ordem dos bytes e quebrar o HMAC.