تأیید صوتی (OTP)

مدل «ما به شما زنگ می‌زنیم، کد را می‌خوانیم»: شماره را می‌دهید، سانترال تماس می‌گیرد و کد تأیید را رقم‌به‌رقم برای پاسخ‌دهنده می‌خواند (با فشردن 1 تکرار می‌شود) و قطع می‌کند. کد را می‌توانید خودتان بفرستید یا Buluthat تولید کند و یک‌بار در پاسخ برگرداند. کد در پایگاه داده فقط hash ذخیره می‌شود؛ status در پاسخ دیده نمی‌شود.

نقطه: https://api.buluthat.com/api/voice_otp.php — کلید یکپارچه‌سازی (bt_…، دامنه voice_otp / autocall / voicebot / *). در حساب voice_otp ماژول باید باز باشد.

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"
}
حوزهالزامیتوضیح
phoneبلهشماره مورد تماس
codeخیرکد خودتان؛ اگر خالی باشد Buluthat تولید می‌کند
lengthخیرتعداد ارقام کد تولیدشده (4-8، پیش‌فرض 6)
referenceخیرضبط خودتان؛ status/list برای پیدا کردن با
caller_id, trunk_slugخیرشماره تماس‌گیرنده و خط
repeatخیرکد چند بار خوانده شود (1-5، پیش‌فرض 2)
ttl_minutesخیراعتبار کد (حداکثر 60، پیش‌فرض 5)
company_nameخیرنام شرکت در اعلان ورودی؛ اگر خالی باشد نام حساب
webhook_url, webhook_secretخیراطلاع‌رسانی وضعیت

پاسخ:

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

code فقط وقتی Buluthat تولید کرده برمی‌گردد؛ اگر شما فرستاده‌اید null.

خطاها (422): شماره نامعتبر، بیش از 3 تماس در 10 دقیقه به یک شماره (rate_limited)، سقف روزانه (daily_limit)، تماس در جریان (in_progress)، خط وجود ندارد، کلید صداگذاری وجود ندارد، سانترال نتوانست تماس را برقرار کند (دلیل در پیام).

POSTverify

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

id به‌جای phone (+ reference) نیز می‌توان داد؛ آخرین رکوردی که برای آن شماره باز شده استفاده می‌شود.

  • درست: { "ok": true, "verified": true }
  • نادرست: 422 و error: wrong_code (پیام‌های آزمایشی باقی‌مانده)، expired, too_many_attempts (5), not_delivered (تماس برقرار نشد)، not_found

اگر تماس برقرار شد کد (answered/delivered) قابل تأیید است — حتی اگر شخص پس از شنیدن کد تلفن را قطع کند.

GETstatus

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

وضعیت‌ها: pending → calling → answered → delivered → verified؛ ناموفق‌ها no_answer, busy, failed, expired. final: true اگر باشد تماس تمام شده است. هر 2-3 ثانیه پرس‌وجو کنید یا از Webhook استفاده کنید.

GETlist

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

GETcaller_ids · trunks

گزینه‌های شماره تماس‌گیرنده و خط (مانند API تماس خودکار).

Webhook

webhook_url اگر داده شود در تغییر وضعیت‌ها (delivered, verified, no_answer, busy, failed, expired) ارسال می‌شود:

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

سرشناسه‌ها X-Buluthat-Event, X-Buluthat-Delivery, webhook_secret اگر داده شود X-Buluthat-Signature: sha256=<hmac>. در پاسخ غیر از 2xx پس از 1 دقیقه، 5 دقیقه، 15 دقیقه، 1 ساعت، 3 ساعت و 6 ساعت دوباره تلاش می‌شود.

کلاینت PHP

دانلود شده از پنل 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

چرا به‌جای SMS؟

  • نیازی به اجازه İYS و سرشناسه SMS ندارد، روی خط ثابت هم کار می‌کند.
  • مشکل SMS تحویل‌نشده نیست: معلوم است تماس پاسخ داده شد یا کد خوانده شد.
  • برای کاربر سالمند یا نابینا شنیدن کد از خواندن نوشته آسان‌تر است.
  • هزینه‌گیری فقط برای تماس‌های پاسخ‌داده‌شده، طبق قوانین بسته شما.