Pereiti prie turinio

Flash skambutis

„Flash Call“ yra telefono patvirtinimo būdas, kai telefono numeriams patvirtinti naudojamas praleistas skambutis, o ne SMS. Tai greitesnė, saugesnė ir ekonomiškesnė.

Apžvalga

„Flash Call“ patvirtinimas veikia:

  1. Vartotojas prašo patvirtinimo
  2. Sistema inicijuoja skambutį į vartotojo telefoną
  3. Skambutis automatiškai nutraukiamas po 1-2 skambučių
  4. Vartotojo programa užfiksuoja skambintojo ID
  5. Skambintojo ID patikrinamas pagal numatytą modelį
  6. Vartotojas patvirtintas

Privalumai

Ekonomiškai efektyvu

  • Iki 10 kartų pigiau nei SMS
  • Jokių pranešimų pristatymo mokesčių
  • Sumažėjusios didelės apimties tikrinimo išlaidos

Greičiau

  • Momentinis patvirtinimas (1–3 sekundės)
  • Nereikia laukti SMS pristatymo
  • Geresnė vartotojo patirtis

Saugesnis

  • Sunkiau perimti nei SMS
  • Pranešimuose nematomas vienkartinis slaptažodis
  • Atsparus SIM keitimo atakoms

Pasaulinis pasiekiamumas

  • Veikia šalyse, kuriose taikomi SMS apribojimai
  • Nėra problemų su SMS filtravimu
  • Universalus telefono suderinamumas

Pagrindinis Flash skambutis

Prašymas

{
  "from": "YourApp",
  "to": "+380XXXXXXXXX",
  "type": "flashcall",
  "messageData": {
    "callerId": "+380123456789"
  }
}

Parametrai

Parametras Tipas Reikalingas Aprašymas
"nuo" styga Taip Jūsų siuntėjo identifikatorius
"į" styga Taip Gavėjo telefono numeris (E.164)
"tipas" styga Taip Nustatyti į "flashcall"
"skambintojo ID" styga Taip Telefono numeris, kuriuo bus skambinama vartotojui
ttl sveikasis skaičius Ne Gyvenimo laikas sekundėmis (numatytasis: 60)

Kaip tai veikia

1. Vartotojas įveda telefono numerį

Naudotojas jūsų programoje pateikia savo telefono numerį:

Phone: +380XXXXXXXXX

2. Pateikite „Flash“ skambučio užklausą

Jūsų serveris prašo „flash“ skambučio patvirtinimo:

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. API atsakymas

API grąžina numatomą skambintojo ID šabloną:

{
  "messagelistId": 123456,
  "messages": [
    {
      "messageId": "abc123def456",
      "status": "accepted",
      "callerId": "+380123456789",
      "pattern": "***456789",
      "to": "+380XXXXXXXXX"
    }
  ]
}

4. Pradėkite skambutį

Sistema inicijuoja skambutį vartotojo telefonu ir baigia po 1-2 skambučių.

5. Užfiksuokite skambintojo ID

Vartotojo programa užfiksuoja gaunamo skambučio skambintojo ID:

// Android example
val cursor = contentResolver.query(
    CallLog.Calls.CONTENT_URI,
    arrayOf(CallLog.Calls.NUMBER),
    null, null,
    CallLog.Calls.DATE + " DESC"
)

6. Patvirtinkite šabloną

Palyginkite užfiksuotą skambintojo ID su numatomu šablonu:

// 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);
}

Įgyvendinimo pavyzdžiai

Android

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)
    }
}

iOS

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
    }
}

Žiniatinklis (serverio pusė)

// 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' });
  }
});

Atsakymo formatas

Sėkmės atsakas

{
  "messagelistId": 123456,
  "messages": [
    {
      "messageId": "abc123def456",
      "status": "accepted",
      "callerId": "+380123456789",
      "pattern": "***456789",
      "to": "+380XXXXXXXXX",
      "ttl": 60
    }
  ]
}

Atsakymo laukai

Laukas Tipas Aprašymas
messageId styga Unikalus patvirtinimo ID
"būsena" styga Būsena: „priimta“, „atmesta“
"skambintojo ID" styga Visas skambintojo ID numeris
modelis styga Atitinkamas šablonas (skaitmenys + žvaigždutės)
"į" styga Gavėjo telefono numeris
ttl sveikasis skaičius Galiojimo laikas sekundėmis

Šablonų atitikimas

API grąžina šabloną su žvaigždutėmis, maskuojančiomis kai kuriuos skaitmenis:

Full number: +380123456789
Pattern:     ***456789

Jūsų programa turėtų:

  1. Užfiksuokite gaunamo skambintojo ID
  2. Išskleiskite skaitmenis iš skambintojo ID
  3. Suderinti su šablonu (žvaigždutės = bet koks skaitmuo)
  4. Patikrinkite atitiktį per TTL laikotarpį

Atsarginė SMS žinutė

Jei „Flash Call“ nepavyksta, automatiškai grįžkite į SMS:

{
  "from": "YourApp",
  "to": "+380XXXXXXXXX",
  "type": "flashcall",
  "messageData": {
    "callerId": "+380123456789"
  },
  "fallback": {
    "type": "sms",
    "text": "Your verification code is: 123456"
  },
  "ttl": 60
}

Naudojimo atvejai

Paskyros registracija

Registruodamiesi patvirtinkite telefono numerius be SMS mokesčių.

Prisijungimo patvirtinimas

Dviejų veiksnių autentifikavimas naudojant „flash“ skambutį.

Telefono numerio atnaujinimas

Patvirtinkite naują telefono numerį, kai vartotojas atnaujina profilį.

Operacijos patvirtinimas

Patvirtinkite didelės vertės operacijas naudodami „flash“ skambutį.

Geriausia praktika

TTL

  • ✅ Nustatyti TTL į 60-90 sekundžių
  • ✅ Leiskite vartotojui pabandyti dar kartą pasibaigus galiojimo laikui
  • ❌ Nenaudokite TTL ilgiau nei 120 sekundžių

Vartotojo patirtis

  • Rodyti pranešimą „Laukiama skambučio...“.
  • Ekrano atgalinės atskaitos laikmatis (60 sekundžių)
  • Pateikite parinktį „Naudoti SMS“
  • Automatiškai aptikti ir patikrinti skambintojo ID

Klaidų tvarkymas

  • Tvarkykite trūkstamus telefono leidimus
  • Skirtasis laikas pasibaigus TTL galiojimo laikui
  • Pateikite SMS atsarginę parinktį
  • Rodyti aiškius klaidų pranešimus

Leidimai

Prieš skambindami paprašykite telefono leidimo:

Android:

<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />

iOS:

<key>NSPhoneCallUsageDescription</key>
<string>We need phone access to verify your number</string>

Testavimas

  • Išbandykite skirtinguose įrenginiuose
  • Išbandykite su skirtingais nešėjais
  • Išbandykite leidimo atsisakymo scenarijus
  • Išbandykite tinklo skirtojo laiko scenarijus

Apribojimai

Platformos palaikymas

  • Veikia visuose mobiliuosiuose įrenginiuose
  • Reikalinga galimybė skambinti telefonu – Reikia READ_PHONE_STATE leidimo
  • Gali neveikti planšetiniuose kompiuteriuose be telefono

Tinklas

  • Reikia aktyvaus telefono ryšio
  • Gali sugesti esant blogoms tinklo sąlygoms – Gali būti taikomi operatoriaus apribojimai
  • Tarptautiniai tarifai gali skirtis

Privatumas

  • Vartotojai gali blokuoti nežinomus numerius
  • Kai kuriuose įrenginiuose yra skambučių blokavimas
  • Reikalingi aiškūs leidimai – Atsižvelkite į vartotojų privatumo problemas

Trikčių šalinimas

Skambutis nepriimtas

  • Patikrinkite, ar telefone yra signalas – Patvirtinkite numerio formatą (E.164)
  • Patikrinkite operatoriaus apribojimus
  • Išbandykite atsarginę SMS žinutę

Neatitinka raštas

  • Užtikrinkite teisingą skambintojo ID
  • Nuimkite neskaitmenis
  • Patikrinkite modelio formatą
  • Patvirtinkite per TTL laikotarpį

Leidimas atmestas

  • Teisingai prašykite leidimų
  • Paaiškinkite, kodėl reikalingi leidimai
  • Pateikite alternatyvą (SMS)
  • Elkis grakščiai

Kiti žingsniai

Viber OTP – Alternatyvus OTP pristatymas – SMS žinutės – atsarginės SMS žinutės – Patikrinti būseną – Stebėkite „Flash“ skambučio būseną