Skip to content

Flash poziv

Flash poziv je metoda potvrde telefona koja koristi propušteni poziv umjesto SMS-a za provjeru telefonskih brojeva. Brži je, sigurniji i isplativiji.

Pregled

Provjera Flash poziva radi:

  1. Korisnik zahtjeva verifikaciju
  2. Sistem pokreće poziv na telefon korisnika
  3. Poziv se automatski prekida nakon 1-2 zvona
  4. Korisnička aplikacija snima ID pozivaoca
  5. ID pozivaoca je verifikovan u odnosu na očekivani obrazac
  6. Korisnik je autentificiran

Prednosti

Isplativo

  • Do 10x jeftinije od SMS-a
  • Bez naknade za dostavu poruka
  • Smanjeni troškovi za verifikaciju velikog obima

Brže

  • Trenutna verifikacija (1-3 sekunde)
  • Nema čekanja na isporuku SMS-a
  • Bolje korisničko iskustvo

Sigurnije

  • Teže presresti nego SMS
  • Nema OTP vidljivog u obavještenjima
  • Otporan na napade zamjene SIM kartice

Globalni doseg

  • Radi u zemljama sa ograničenjima SMS-a
  • Nema problema sa filtriranjem SMS-a
  • Univerzalna kompatibilnost telefona

Osnovni Flash poziv

Zahtjev

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

Parametri

Parametar Vrsta Obavezno Opis
od string Da Vaš identifikator pošiljaoca
to string Da Broj telefona primaoca (E.164)
tip string Da Postavite na "flashcall"
callerId string Da Broj telefona koji će pozvati korisnika
ttl cijeli broj Ne Vrijeme života u sekundama (zadano: 60)

Kako radi

1. Korisnik unosi broj telefona

Korisnik daje svoj broj telefona u vašoj aplikaciji:

Phone: +380XXXXXXXXX

2. Zatražite Flash poziv

Vaš server traži provjeru flash poziva:

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 odgovor

API vraća očekivani obrazac ID pozivatelja:

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

4. Pokreni poziv

Sistem pokreće poziv na telefon korisnika i prekida nakon 1-2 zvona.

5. Capture Caller ID

Korisnička aplikacija snima ID pozivaoca dolaznog poziva:

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

6. Potvrdite uzorak

Uporedite snimljeni ID pozivaoca sa očekivanim uzorkom:

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

Primjeri implementacije

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

Web (na strani servera)

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

Format odgovora

Uspješan odgovor

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

Polja odgovora

Polje Vrsta Opis
messageId string Jedinstveni ID potvrde
status string Status: prihvaćen, odbijen
callerId string Full caller ID number
uzorak string Uzorak za podudaranje (cifre + zvjezdice)
to string Broj telefona primaoca
ttl cijeli broj Period važenja u sekundama

Pattern Matching

API vraća uzorak sa zvjezdicama koje maskiraju neke cifre:

Full number: +380123456789
Pattern:     ***456789

Vaša aplikacija bi trebala:

  1. Snimite ID dolaznog pozivaoca
  2. Izdvojite cifre iz ID-a pozivaoca
  3. Usporedite s uzorkom (zvjezdice = bilo koja cifra)
  4. Provjerite podudaranje unutar TTL perioda

Povratak na SMS

Ako Flash poziv ne uspije, automatski se vratite na SMS:

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

Slučajevi upotrebe

Registracija računa

Potvrdite brojeve telefona tokom registracije bez troškova SMS-a.

Potvrda prijave

Dvofaktorska autentifikacija pomoću flash poziva.

Ažuriranje telefonskog broja

Potvrdite novi broj telefona kada korisnik ažurira profil.

Potvrda transakcije

Potvrdite transakcije velike vrijednosti pomoću flash poziva.

Najbolje prakse

TTL

  • ✅ Postavite TTL na 60-90 sekundi
  • ✅ Dozvolite korisniku da pokuša ponovo nakon isteka
  • ❌ Ne koristite TTL duže od 120 sekundi

Korisničko iskustvo

  • Prikaži poruku "Čeka se poziv...".
  • Prikaz tajmera za odbrojavanje (60 sekundi)
  • Omogućite opciju "Umjesto toga koristite SMS"
  • Automatsko otkrivanje i provjera ID-a pozivatelja

Rukovanje greškama

  • Rukovati nedostajućim dozvolama za telefon
  • Vremensko ograničenje nakon isteka TTL-a
  • Omogućite zamjensku opciju za SMS
  • Prikaži jasne poruke o grešci

Dozvole

Zatražite dozvole za telefon prije flash poziva:

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>

Testiranje

  • Testirajte na različitim uređajima
  • Testirajte sa različitim nosačima
  • Testirajte scenarije odbijanja dozvole
  • Testirajte scenarije vremenskog ograničenja mreže

Ograničenja

Podrška platformi

  • Radi na svim mobilnim uređajima
  • Zahtijeva mogućnost telefonskog poziva
  • Potrebna je dozvola READ_PHONE_STATE
  • Možda neće raditi na tabletima bez telefona

Mreža

  • Zahtijeva aktivnu telefonsku vezu
  • Može otkazati u lošim mrežnim uvjetima
  • Moguća su ograničenja operatera
  • Međunarodne stope mogu varirati

Privatnost

  • Korisnici mogu blokirati nepoznate brojeve
  • Neki uređaji imaju blokadu poziva
  • Zahtijeva izričite dozvole
  • Uzmite u obzir brige o privatnosti korisnika

Rješavanje problema

Poziv nije primljen

  • Provjerite ima li telefon signal
  • Potvrdite format broja (E.164)
  • Provjerite ograničenja operatera
  • Pokušajte zamjenski SMS

Uzorak se ne podudara

  • Osigurajte snimanje ispravnog ID-a pozivaoca
  • Skinite necifrene znakove
  • Provjerite format uzorka
  • Potvrdite unutar TTL perioda

Dozvola odbijena

  • Pravilno zatražite dozvole
  • Objasnite zašto su potrebne dozvole
  • Dajte alternativu (SMS)
  • Rukuj graciozno

Sljedeći koraci