Verificação por Voz (OTP)

Modelo "Ligamos-lhe e lemos o código": indica o número, a central liga e lê o código de verificação dígito a dígito a quem atender (prima 1 para repetir) e desliga. Pode enviar o código ou deixar que a Buluthat o gere e o devolva uma única vez na resposta. O código fica na base de dados apenas hash é guardado como; status não aparece na resposta.

Endpoint: https://api.buluthat.com/api/voice_otp.php — Chave de integração (bt_…, âmbito voice_otp / autocall / voicebot / *). Na conta voice_otp o módulo tem de estar ativo.

POSTsend

{
  "action": "send",
  "phone": "05551112233",
  "code": "482913",
  "length": 6,
  "reference": "CARI-451",
  "caller_id": "02124119610",
  "trunk_slug": "hat-1",
  "repeat": 2,
  "ttl_minutes": 5,
  "company_name": "Byfix",
  "webhook_url": "https://crm.example.com/otp-sonuc.php",
  "webhook_secret": "gizli"
}
CampoObrigatórioDescrição
phonesimNúmero a chamar
codenãoO seu próprio código; se vazio, a Buluthat gera-o
lengthnãoNúmero de dígitos do código a gerar (4-8, por defeito 6)
referencenãoO seu próprio registo; status/list para encontrar com
caller_id, trunk_slugnãoNúmero de origem e linha
repeatnãoQuantas vezes se lê o código (1-5, por defeito 2)
ttl_minutesnãoValidade do código (no máximo 60, por defeito 5)
company_namenãoNome da empresa no anúncio de abertura; se vazio, o nome da conta
webhook_url, webhook_secretnãoNotificação de estado

Resposta:

{ "ok": true, "code": "482913", "data": { "id": 17, "status": "calling", "expires_at": "2026-09-18 10:17:03" } }

code só é devolvido quando a Buluthat o gera; se o enviou você null.

Erros (422): número inválido, mais de 3 chamadas para o mesmo número em 10 minutos (rate_limited), limite diário (daily_limit), chamada em curso (in_progress), sem linha, sem chave de síntese de voz, a central não conseguiu estabelecer a chamada (o motivo consta na mensagem).

POSTverify

{ "action": "verify", "id": 17, "code": "482913" }

id em vez de phone (+ reference) também pode ser indicado; é usado o último registo aberto para esse número.

  • Correto: { "ok": true, "verified": true }
  • Errado: 422 e error: wrong_code (restantes mensagens de teste), expired, too_many_attempts (5), not_delivered (a chamada não foi iniciada), not_found

Código, se a chamada foi atendida (answered/delivered) pode ser validado — mesmo que a pessoa desligue depois de ouvir o código.

GETstatus

GET https://api.buluthat.com/api/voice_otp.php?action=status&id=17

Estados: pending → calling → answered → delivered → verified; as falhadas no_answer, busy, failed, expired. final: true se for, a chamada terminou. Consulte a cada 2-3 segundos ou utilize webhook.

GETlist

GET ?action=list&phone=0555…&reference=CARI-451&limit=20

GETcaller_ids · trunks

Opções de número de origem e linha (iguais às da API de chamadas automáticas).

Webhook

webhook_url se for indicado, nas mudanças de estado (delivered, verified, no_answer, busy, failed, expired) é enviado um POST:

{ "event": "voice_otp.delivered", "request": { "id": 17, "status": "delivered", "reference": "CARI-451", "phone": "05551112233" } }

Cabeçalhos X-Buluthat-Event, X-Buluthat-Delivery, webhook_secret se for indicado X-Buluthat-Signature: sha256=<hmac>. Numa resposta fora de 2xx volta a tentar após 1 min, 5 min, 15 min, 1 h, 3 h, 6 h.

Cliente PHP

Descarregado do painel buluthat-voice-otp-client.php:

require 'buluthat-voice-otp-client.php';
$otp = new BuluthatVoiceOtp('https://api.buluthat.com', 'bt_xxx');

$r = $otp->send('05551112233', ['reference' => 'CARI-451']);   // $r['code'], $r['data']['id']
// ... kullanıcı kodu girer ...
$v = $otp->verify($r['data']['id'], $girilenKod);               // $v['ok'] === true

Porquê em vez de SMS?

  • Não exige consentimento İYS nem cabeçalho de SMS e funciona também em linha fixa.
  • Sem problema de SMS não entregue: sabe-se se a chamada foi atendida e se o código foi lido.
  • Para utilizadores idosos ou com deficiência visual, ouvir o código é mais fácil do que lê-lo.
  • A tarifação aplica-se apenas às chamadas atendidas, segundo as regras do seu pacote.