Sari la conținut

Apel flash

Flash Call este o metodă de verificare a telefonului care utilizează un apel pierdut în loc de SMS pentru a verifica numerele de telefon. Este mai rapid, mai sigur și mai rentabil.

Prezentare generală

Verificarea Flash Call funcționează prin:

  1. Utilizatorul solicită verificarea
  2. Sistemul inițiază un apel către telefonul utilizatorului
  3. Apelul este terminat automat după 1-2 sunete
  4. Aplicația utilizatorului captează ID-ul apelantului
  5. ID-ul apelantului este verificat în funcție de modelul așteptat
  6. Utilizatorul este autentificat

Beneficii

Cost-eficient

  • De până la 10 ori mai ieftin decât SMS-urile
  • Fără taxe de livrare a mesajelor
  • Costuri reduse pentru verificarea de volum mare

Mai repede

  • Verificare instantanee (1-3 secunde)
  • Fără așteptare pentru livrarea SMS-urilor
  • Experiență de utilizator mai bună

Mai sigur

  • Mai greu de interceptat decât SMS-urile
  • Niciun OTP vizibil în notificări
  • Rezistent la atacurile de schimb SIM

Acoperire globală

  • Funcționează în țări cu restricții SMS
  • Nu există probleme cu filtrarea SMS-urilor
  • Compatibilitate universală cu telefonul

Apel flash de bază

Solicitare

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

Parametri

Parametru Tip Necesar Descriere
din șir Da Identificatorul expeditorului dvs.
la șir Da Număr de telefon al destinatarului (E.164)
tip șir Da Setați la "flashcall"
callerId șir Da Număr de telefon care va apela utilizatorul
ttl întreg Nu Timp de viață în secunde (implicit: 60)

Cum funcționează

1. Utilizatorul introduce numărul de telefon

Utilizatorul oferă numărul de telefon în aplicația dvs.:

Phone: +380XXXXXXXXX

2. Solicitați un apel flash

Serverul dvs. solicită verificarea apelurilor flash:

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. Răspuns API

API returnează modelul așteptat de ID apelant:

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

4. Inițiați apelul

Sistemul inițiază un apel către telefonul utilizatorului și se încheie după 1-2 sunete.

5. Capturați ID apelant

Aplicația utilizatorului captează ID-ul apelantului apelului primit:

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

6. Verificați modelul

Comparați ID-ul apelantului capturat cu modelul așteptat:

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

Exemple de implementare

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 (partea server)

// 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 de răspuns

Răspuns de succes

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

Câmpuri de răspuns

Câmp Tip Descriere
messageId șir ID unic de verificare
starea șir Stare: acceptat, respins
callerId șir Număr complet de identificare a apelantului
model șir Model pentru a se potrivi (cifre + asteriscuri)
la șir Numărul de telefon al destinatarului
ttl întreg Perioada de valabilitate în secunde

Potrivirea modelului

API-ul returnează un model cu asteriscuri care maschează unele cifre:

Full number: +380123456789
Pattern:     ***456789

Aplicația dvs. ar trebui să:

  1. Capturați ID-ul apelantului primit
  2. Extrageți cifre din ID-ul apelantului
  3. Potriviți cu model (asteriscuri = orice cifră)
  4. Verificați potrivirea în perioada TTL

Revenire la SMS

Dacă apelul flash nu reușește, reveniți automat la SMS:

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

Cazuri de utilizare

Înregistrarea contului

Verificați numerele de telefon în timpul înscrierii fără costuri prin SMS.

Verificare autentificare

Autentificare cu doi factori folosind apel flash.

Actualizare număr de telefon

Verificați noul număr de telefon când utilizatorul actualizează profilul.

Confirmarea tranzacției

Confirmați tranzacțiile de mare valoare cu apelul flash.

Cele mai bune practici

TTL

  • ✅ Setați TTL la 60-90 de secunde
  • ✅ Permiteți utilizatorului să reîncerce după expirare
  • ❌ Nu utilizați TTL mai mult de 120 de secunde

Experiența utilizatorului

  • Afișați mesajul „Se așteaptă apelul...”.
  • Afișează cronometrul cu numărătoare inversă (60 de secunde)
  • Oferiți opțiunea „Folosiți SMS-ul în schimb”
  • Detectați și verificați automat ID-ul apelantului

Gestionarea erorilor

  • Gestionați permisiunile telefonului lipsă
  • Timeout după expirarea TTL
  • Furnizați opțiunea de rezervă pentru SMS
  • Afișați mesaje de eroare clare

Permisiuni

Solicitați permisiuni telefonice înainte de apelul flash:

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>

Testare

  • Testați pe diferite dispozitive
  • Testați cu diferiți transportatori
  • Testați scenariile de refuzare a permisiunii
  • Testați scenariile de expirare a rețelei

Limitări

Suport platformă

  • Funcționează pe toate dispozitivele mobile
  • Necesită capacitatea de apel telefonic
  • Are nevoie de permisiunea READ_PHONE_STATE
  • Este posibil să nu funcționeze pe tablete fără telefon

Rețea

  • Necesită conexiune telefonică activă
  • Poate eșua în condiții proaste de rețea
  • Se pot aplica restricții de transportator
  • Tarifele internaționale pot varia

Confidențialitate

  • Utilizatorii pot bloca numere necunoscute
  • Unele dispozitive au blocarea apelurilor
  • Necesită permisiuni explicite
  • Luați în considerare preocupările privind confidențialitatea utilizatorilor

Depanare

Apel neprimit

  • Verificați că telefonul are semnal
  • Verificați formatul numărului (E.164)
  • Verificați restricțiile operatorului
  • Încercați SMS-uri de rezervă

Modelul nu se potrivește

  • Asigurați-vă că capturați ID-ul apelantului corect
  • Eliminați caracterele fără cifre
  • Verificați formatul modelului
  • Verificați în perioada TTL

Permisiune refuzată

  • Solicitați permisiunile în mod corespunzător
  • Explicați de ce sunt necesare permisiunile
  • Oferiți alternative (SMS)
  • Manevrează-te cu grație

Următorii pași