Фласх позив
Фласх позив је метода верификације телефона која користи пропуштени позив уместо СМС-а за верификацију телефонских бројева. То је брже, сигурније и исплативије.
Преглед
Верификација Фласх позива ради:
- Корисник захтева верификацију
- Систем покреће позив на телефон корисника
- Позив се аутоматски прекида након 1-2 звона
- Корисничка апликација снима ИД позиваоца
- ИД позиваоца је верификован у односу на очекивани образац
- Корисник је аутентификован
Предности
Исплативо
- До 10 пута јефтиније од СМС-а
- Нема накнада за испоруку порука
- Смањени трошкови за верификацију великог обима
Брже
- Тренутна верификација (1-3 секунде)
- Нема чекања на испоруку СМС-а
- Боље корисничко искуство
Безбедније
- Теже је пресрести него СМС
- Нема ОТП видљивог у обавештењима
- Отпоран на нападе замене СИМ картице
Глобални досег
- Ради у земљама са ограничењима СМС-а
- Нема проблема са филтрирањем СМС-а
- Универзална компатибилност телефона
Основни Фласх позив
Захтев
{
"from": "YourApp",
"to": "+380XXXXXXXXX",
"type": "flashcall",
"messageData": {
"callerId": "+380123456789"
}
}
Параметерс
| Параметар | Тип | Обавезно | Опис |
|---|---|---|---|
од | стринг | Да | Ваш идентификатор пошиљаоца |
то | стринг | Да | Број телефона примаоца (Е.164) |
тип | стринг | Да | Подесите на "фласхцалл" |
цаллерИд | стринг | Да | Број телефона који ће позвати корисника |
ттл | цео број | Не | Време живота у секундама (подразумевано: 60) |
Како то функционише
1. Корисник уноси број телефона
Корисник даје свој број телефона у вашој апликацији:
Phone: +380XXXXXXXXX
2. Захтевајте Фласх позив
Ваш сервер захтева верификацију флеш позива:
curl -X POST https://restapi.smsbat.com/bat/messagelist \
-H "X-Authorization-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{
"messages": [{
"from": "YourApp",
"to": "+380XXXXXXXXX",
"type": "flashcall",
"messageData": {
"callerId": "+380123456789"
},
"ttl": 60
}]
}'
3. АПИ одговор
АПИ враћа очекивани образац ИД позиваоца:
{
"messagelistId": 123456,
"messages": [
{
"messageId": "abc123def456",
"status": "accepted",
"callerId": "+380123456789",
"pattern": "***456789",
"to": "+380XXXXXXXXX"
}
]
}
4. Покрени позив
Систем покреће позив на телефон корисника и прекида након 1-2 звона.
5. Снимите ИД позиваоца
Корисничка апликација снима ИД позиваоца долазног позива:
// Android example
val cursor = contentResolver.query(
CallLog.Calls.CONTENT_URI,
arrayOf(CallLog.Calls.NUMBER),
null, null,
CallLog.Calls.DATE + " DESC"
)
6. Верифи Паттерн
Упоредите снимљени ИД позиваоца са очекиваним шаблоном:
// JavaScript example
function verifyFlashCall(callerId, pattern) {
// Remove non-digits
const callerDigits = callerId.replace(/\D/g, '');
const patternDigits = pattern.replace(/\*/g, '.');
// Check if matches pattern
const regex = new RegExp(patternDigits);
return regex.test(callerDigits);
}
Примери имплементације
Андроид
class FlashCallVerification {
fun requestFlashCall(phoneNumber: String) {
// 1. Request flash call from API
val response = api.requestFlashCall(phoneNumber)
val pattern = response.pattern
// 2. Wait for incoming call
val callReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == TelephonyManager.ACTION_PHONE_STATE_CHANGED) {
val state = intent.getStringExtra(TelephonyManager.EXTRA_STATE)
if (state == TelephonyManager.EXTRA_STATE_RINGING) {
val callerId = intent.getStringExtra(
TelephonyManager.EXTRA_INCOMING_NUMBER
)
// 3. Verify caller ID against pattern
if (verifyPattern(callerId, pattern)) {
onVerificationSuccess()
}
}
}
}
}
// Register receiver
context.registerReceiver(
callReceiver,
IntentFilter(TelephonyManager.ACTION_PHONE_STATE_CHANGED)
)
}
private fun verifyPattern(callerId: String?, pattern: String): Boolean {
if (callerId == null) return false
val regex = pattern.replace("*", "\\d").toRegex()
return regex.matches(callerId)
}
}
иОС
class FlashCallVerification {
func requestFlashCall(phoneNumber: String) {
// 1. Request flash call from API
api.requestFlashCall(phoneNumber) { response in
let pattern = response.pattern
// 2. Use CallKit to detect incoming call
let provider = CXProvider(configuration: providerConfiguration)
provider.setDelegate(self, queue: nil)
// Store pattern for verification
self.expectedPattern = pattern
}
}
// CallKit delegate
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
// Capture caller ID
let callerId = action.callUUID.uuidString
// Verify against pattern
if verifyPattern(callerId: callerId, pattern: expectedPattern) {
onVerificationSuccess()
}
action.fulfill()
}
private func verifyPattern(callerId: String, pattern: String) -> Bool {
let regex = try! NSRegularExpression(
pattern: pattern.replacingOccurrences(of: "*", with: "\\d")
)
let range = NSRange(location: 0, length: callerId.count)
return regex.firstMatch(in: callerId, range: range) != nil
}
}
Веб (на страни сервера)
// Node.js example
const express = require('express');
const app = express();
app.post('/request-verification', async (req, res) => {
const { phoneNumber } = req.body;
// 1. Request flash call
const response = await fetch('https://restapi.smsbat.com/bat/messagelist', {
method: 'POST',
headers: {
'X-Authorization-Key': process.env.SMSBAT_API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
messages: [{
from: 'YourApp',
to: phoneNumber,
type: 'flashcall',
messageData: {
callerId: process.env.FLASH_CALL_NUMBER
},
ttl: 60
}]
})
});
const data = await response.json();
const { messageId, pattern } = data.messages[0];
// 2. Store pattern for verification
await redis.setex(`flashcall:${messageId}`, 60, pattern);
// 3. Return pattern to client
res.json({ messageId, pattern });
});
app.post('/verify-flashcall', async (req, res) => {
const { messageId, callerId } = req.body;
// 1. Get expected pattern
const pattern = await redis.get(`flashcall:${messageId}`);
if (!pattern) {
return res.status(400).json({ error: 'Verification expired' });
}
// 2. Verify caller ID
const regex = new RegExp(pattern.replace(/\*/g, '\\d'));
const isValid = regex.test(callerId);
if (isValid) {
// Mark phone as verified
await markPhoneVerified(callerId);
res.json({ verified: true });
} else {
res.status(400).json({ error: 'Invalid caller ID' });
}
});
Формат одговора
Успешан одговор
{
"messagelistId": 123456,
"messages": [
{
"messageId": "abc123def456",
"status": "accepted",
"callerId": "+380123456789",
"pattern": "***456789",
"to": "+380XXXXXXXXX",
"ttl": 60
}
]
}
Поља одговора
| Поље | Тип | Опис |
|---|---|---|
мессагеИд | стринг | Јединствени ИД за верификацију |
статус | стринг | Статус: прихваћен, одбијен |
цаллерИд | стринг | Потпуни ИД број позиваоца |
паттерн | стринг | Узорак за подударање (цифре + звездице) |
то | стринг | Број телефона примаоца |
ттл | цео број | Период важења у секундама |
Паттерн Матцхинг
АПИ враћа образац са звездицама које маскирају неке цифре:
Full number: +380123456789
Pattern: ***456789
Ваша апликација треба да:
- Снимите ИД долазног позиваоца
- Извуците цифре из ИД-а позиваоца
- Поклапање са шаблоном (звездице = било која цифра)
- Потврдите подударање унутар ТТЛ периода
Повратак на СМС
Ако Фласх позив не успе, аутоматски се вратите на СМС:
{
"messages": [
{
"from": "ALPHANAME",
"to": "380936670003",
"type": "flashcall",
"text": 321,
"ttl": 30,
"fallbacks": [
{
"from": "ALPHANAME",
"to": "380936670003",
"type": "viber_otp",
"text": "",
"ttl": 90,
"messageData": {
"templateId": "6c929cef-29b4-4349-bc9d-2a07bdbb6e43",
"templateLang": "uk",
"templateParams": {
"pin": 321,
"business_platform_name": "SMSBAT",
"code_validity_time": 7
}
}
},
{
"from": "ALPHANAME",
"to": "380936670003",
"type": "sms",
"text": "Your SMS code: 321"
}
]
}
]
}
Случајеви употребе
Регистрација налога
Проверите бројеве телефона током регистрације без трошкова СМС-а.
Верификација пријаве
Двофакторска аутентификација помоћу флеш позива.
Ажурирање телефонског броја
Верификујте нови број телефона када корисник ажурира профил.
Потврда трансакције
Потврдите трансакције велике вредности помоћу флеш позива.
Најбоље праксе
ТТЛ
- ✅ Подесите ТТЛ на 60-90 секунди
- ✅ Дозволите кориснику да покуша поново након истека
- ❌ Не користите ТТЛ дуже од 120 секунди
Корисничко искуство
- Прикажи поруку „Чека се позив…“.
- Прикажи тајмер за одбројавање (60 секунди)
- Омогућите опцију „Уместо тога користите СМС“
- Аутоматско откривање и провера ИД-а позиваоца
Обрада грешака
- Руковати недостајућим дозволама за телефон
- Временско ограничење након истека ТТЛ-а
- Обезбедите СМС резервну опцију
- Прикажи јасне поруке о грешци
Дозволе
Затражите дозволе за телефон пре флеш позива:
Андроид:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
иОС:
<key>NSPhoneCallUsageDescription</key>
<string>We need phone access to verify your number</string>
Тестирање
- Тестирајте на различитим уређајима
- Тестирајте са различитим носачима
- Тестирајте сценарије одбијања дозволе
- Тестирајте сценарије временског ограничења мреже
Ограничења
Подршка платформи
- Ради на свим мобилним уређајима
- Захтева могућност телефонског позива
- Потребна је РЕАД_ПХОНЕ_СТАТЕ дозвола
- Можда неће радити на таблетима без телефона
Мрежа
- Захтева активну телефонску везу
- Може отказати у лошим мрежним условима – Могућа су ограничења оператера
- Међународне стопе могу да варирају
Приватност
- Корисници могу блокирати непознате бројеве
- Неки уређаји имају блокирање позива
- Захтева изричите дозволе
- Узмите у обзир бриге о приватности корисника
Решавање проблема
Позив није примљен
- Проверите да ли телефон има сигнал
- Провери формат броја (Е.164)
- Проверите ограничења оператера
- Пробајте резервни СМС
Узорак се не подудара
- Уверите се да сте ухватили тачан ИД позиваоца
- Скините нецифрене знакове
- Проверите формат шаблона
- Потврдите у ТТЛ периоду
Дозвола одбијена
- Правилно затражите дозволе
- Објасните зашто су потребне дозволе
- Наведите алтернативу (СМС)
- Рукуј грациозно
Следећи кораци
- Вибер ОТП - Алтернативна ОТП испорука
- СМС поруке - резервни СМС
- Провери статус - Пратите статус флеш позива