Help Center Фласх позив

Фласх позив

Фласх позив је метода верификације телефона која користи пропуштени позив уместо СМС-а за верификацију телефонских бројева. То је брже, сигурније и исплативије.

Преглед

Верификација Фласх позива ради:

  1. Корисник захтева верификацију
  2. Систем покреће позив на телефон корисника
  3. Позив се аутоматски прекида након 1-2 звона
  4. Корисничка апликација снима ИД позиваоца
  5. ИД позиваоца је верификован у односу на очекивани образац
  6. Корисник је аутентификован

Предности

Исплативо

  • До 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

Ваша апликација треба да:

  1. Снимите ИД долазног позиваоца
  2. Извуците цифре из ИД-а позиваоца
  3. Поклапање са шаблоном (звездице = било која цифра)
  4. Потврдите подударање унутар ТТЛ периода

Повратак на СМС

Ако Фласх позив не успе, аутоматски се вратите на СМС:

{
  "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)
  • Проверите ограничења оператера
  • Пробајте резервни СМС

Узорак се не подудара

  • Уверите се да сте ухватили тачан ИД позиваоца
  • Скините нецифрене знакове
  • Проверите формат шаблона
  • Потврдите у ТТЛ периоду

Дозвола одбијена

  • Правилно затражите дозволе
  • Објасните зашто су потребне дозволе
  • Наведите алтернативу (СМС)
  • Рукуј грациозно

Следећи кораци