Referência

Gestão de erros

Todas as respostas de erro seguem uma única estrutura JSON. Use os códigos de estado HTTP para encaminhar a sua lógica de tratamento de erros e o campo error para contexto legível por humanos.

Formato da resposta de erro
json
// Every non-2xx response returns:
{
  "error": "human-readable description of what went wrong"
}

Códigos de erro

A tabela abaixo cobre todos os códigos de estado devolvidos pelo Connect Hub. A coluna Repetir indica se a repetição automática é segura.

CódigoNomeRepetirDescrição
400Bad RequestNOCampos em falta ou inválidos (p. ex. telefone fora do E.164, parâmetro obrigatório em falta no corpo). Corrija o seu payload.
401UnauthorizedNOCabeçalho x-api-key em falta ou inválido. Verifique a sua chave de API — não repita automaticamente.
402Payment RequiredNOSaldo da conta insuficiente. Carregue a sua conta Novauth antes de repetir.
403ForbiddenNOA chave de API não tem permissão para executar esta ação.
404Not FoundNOO recurso não existe (p. ex. UUID desconhecido em /call/flash/{uuid}/cdr). Não repita.
409ConflictNOFoi detetada uma operação duplicada ou em conflito (p. ex. comunicar o webhook duas vezes para o mesmo UUID).
422Unprocessable EntityNOEspecífico do Telegram: pedido semanticamente inválido (p. ex. request_id expirado em check-verification-status).
429Too Many RequestsYESLimite de taxa excedido. Respeite o cabeçalho Retry-After e implemente backoff exponencial.
480Temporarily UnavailableYESDestinatário temporariamente inacessível (derivado de SIP). Seguro repetir após um curto atraso.
482Loop DetectedNOCiclo de encaminhamento do pedido detetado. Não repita — investigue a sua integração.
486Busy HereYESO destinatário está ocupado. Repita após um atraso ou recorra a outro canal.
488Not Acceptable HereNOParâmetros do pedido não aceitáveis (p. ex. codec ou formato não suportado). Corrija o pedido.
500Internal Server ErrorYESFalha inesperada do lado do servidor. Repita com backoff exponencial (máx. 3 tentativas).
502Bad GatewayYESO serviço a montante (operadora, gateway) devolveu uma resposta inválida. Repita após uma breve espera.
503Service UnavailableYESServiço temporariamente sobrecarregado ou em manutenção. Respeite o Retry-After, se presente.
603DeclineNOO destinatário recusou explicitamente (derivado de SIP). Não repita — o utilizador rejeitou ativamente a chamada.

Lógica de repetição

Repita apenas nos códigos 429, 480, 486, 500, 502, 503. Use backoff exponencial a começar em 500 ms (duplicando a cada tentativa). Nunca repita automaticamente erros de cliente 4xx — corrija primeiro a causa raiz.

javascript
async function callWithRetry(fn, { maxAttempts = 3, baseDelay = 500 } = {}) {
  // Safe codes to retry: 429, 500, 502, 503
  const RETRYABLE = new Set([429, 500, 502, 503]);

  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    const res = await fn();

    if (res.ok) return res;

    const { status } = res;

    // Non-retryable — surface error immediately
    if (!RETRYABLE.has(status)) {
      const body = await res.json().catch(() => ({}));
      throw Object.assign(new Error(body.error ?? 'API error'), { status, body });
    }

    if (attempt === maxAttempts) {
      throw Object.assign(new Error('Max retries reached'), { status });
    }

    // Exponential backoff: 500ms, 1000ms, 2000ms …
    const delay = baseDelay * 2 ** (attempt - 1);
    await new Promise(r => setTimeout(r, delay));
  }
}

// Usage
const res = await callWithRetry(() =>
  fetch('https://api.novauth.com/api/v1/connect-hub/call/flash', {
    method: 'POST',
    headers: {
      'x-api-key':    process.env.BETATEL_API_KEY,
      'x-account-id': process.env.BETATEL_ACCOUNT_ID,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ callee: '+14155552671' })
  })
);

As operações idempotentes (consultas de estado GET) podem ser repetidas livremente. Nas operações POST que criam recursos, verifique sempre se o recurso já foi criado antes de repetir — use o UUID devolvido para consultar o estado primeiro.

Cascata de fallback

O Verify Call funciona na maioria das regiões, mas não é universal. Implemente uma cascata para que os utilizadores recebam sempre o seu OTP, mesmo quando o canal principal falha.

Ordem de fallback recomendada
Verify Call
mais rápido
Telegram OTP
se o utilizador tiver TG
SMS
universal
Condições de acionamento: recorra ao fallback quando o canal principal devolver um erro não repetível (400, 402, 488, 603) ou quando a sessão de verificação não for comunicada como Success dentro de uma janela de tempo configurável (recomendado: 15 s para o Verify Call).
javascript
async function sendWithFallback(phone, otp) {
  // 1. Try Verify Call first
  try {
    const flash = await fetch('.../call/flash', {
      method: 'POST',
      headers,
      body: JSON.stringify({ callee: phone })
    });
    if (flash.ok) return { channel: 'flash', ...(await flash.json()) };
  } catch {}

  // 2. Flash failed — fall back to Telegram if user has it
  try {
    const tg = await fetch('.../telegram', {
      method: 'POST',
      headers,
      body: JSON.stringify({ to: phone, code: otp, ttl: 120 })
    });
    if (tg.ok) return { channel: 'telegram', ...(await tg.json()) };
  } catch {}

  // 3. Final fallback: SMS (widest global reach)
  const sms = await fetch('.../sms', {
    method: 'POST',
    headers,
    body: JSON.stringify({ to: phone, text: `Your code: ${otp}` })
  });
  if (!sms.ok) throw new Error('All channels failed');
  return { channel: 'sms', ...(await sms.json()) };
}

Para desativar a cascata num fluxo específico, basta omitir os blocos try/catch de fallback e apresentar o erro diretamente ao utilizador. Não existe qualquer definição de cascata do lado do servidor — a lógica vive inteiramente no seu código de integração.

Limitação de taxa

Os limites de taxa são aplicados na camada do gateway da API. Quando um limite é atingido, recebe uma resposta 429 Too Many Requests. Consulte o cabeçalho Retry-After para saber o tempo de espera exato.

Retry-After
Segundos a aguardar até o próximo pedido ser permitido.
X-RateLimit-Limit
Máximo de pedidos permitidos na janela atual.
X-RateLimit-Remaining
Pedidos restantes na janela atual.
X-RateLimit-Reset
Época Unix em que a janela atual é reposta.
javascript
const res = await fetch(url, { method: 'POST', headers, body });

if (res.status === 429) {
  const retryAfter = Number(res.headers.get('Retry-After') ?? 1);
  console.warn(`Rate limited — waiting ${retryAfter}s`);
  await new Promise(r => setTimeout(r, retryAfter * 1000));
  // retry the request
}

Erros de integração comuns

Estes são os problemas mais frequentemente comunicados durante a integração. Consulte esta lista antes de abrir um pedido de suporte.

1
Enviar números de telefone sem indicativo de país
Use o formato E.164. "+14155552671", não "4155552671" nem "014155552671".
2
Chamar a API a partir do navegador
A sua chave de API ficará exposta no código do lado do cliente. Faça sempre proxy através do seu servidor backend.
3
Não tratar o 402 Payment Required
O saldo esgota-se silenciosamente em produção. Monitorize o saldo da sua conta Novauth e configure alertas.
4
Repetir erros 400 e 401
São erros de cliente — repetir desperdiça orçamento e aumenta a latência. Corrija primeiro a causa raiz.
5
Ignorar o TTL do Telegram
Os códigos expiram após o ttl especificado. Se chamar check-verification-status após a expiração, recebe um 422.
6
Fazer parse do corpo do Telegram Gateway antes de verificar a assinatura
Verifique sempre o HMAC sobre os bytes originais antes do JSON.parse(). A re-serialização altera a ordem dos bytes.
7
Não revogar os códigos do Telegram após o sucesso
Chame POST /revoke-verification após uma resposta code_valid bem-sucedida para prevenir ataques de repetição.
8
Usar o Verify Call como único canal sem fallback
O Verify Call falha nalgumas redes. Implemente sempre um fallback para SMS ou Telegram nos fluxos críticos.