Gå till innehållet

Flash Call

Flash Call är en telefonverifieringsmetod som använder ett missat samtal istället för SMS för att verifiera telefonnummer. Det är snabbare, säkrare och kostnadseffektivt.

Översikt

Flash Call-verifiering fungerar av:

  1. Användaren begär verifiering
  2. Systemet initierar ett samtal till användarens telefon
  3. Samtalet avslutas automatiskt efter 1-2 ringsignaler
  4. Användarens app fångar nummerpresentationen
  5. Nummerpresentation verifieras mot förväntat mönster
  6. Användaren är autentiserad

Fördelar

Kostnadseffektiv

  • Upp till 10 gånger billigare än SMS
  • Inga meddelandeleveransavgifter
  • Minskade kostnader för verifiering i hög volym

Snabbare

  • Omedelbar verifiering (1-3 sekunder)
  • Ingen väntan på SMS-leverans
  • Bättre användarupplevelse

Säkrare

  • Svårare att avlyssna än SMS
  • Ingen OTP synlig i aviseringar
  • Motståndskraftig mot SIM-bytesattacker

Global räckvidd

  • Fungerar i länder med SMS-begränsningar
  • Inga problem med SMS-filtrering
  • Universell telefonkompatibilitet

Basic Flash Call

Begäran

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

Parametrar

Parameter Skriv Krävs Beskrivning
från sträng Ja Din avsändaridentifierare
till sträng Ja Mottagarens telefonnummer (E.164)
typ sträng Ja Ställ in på "flashcall"
callerId sträng Ja Telefonnummer som ringer användaren
ttl heltal Nej Tid att leva i sekunder (standard: 60)

Hur det fungerar

1. Användare anger telefonnummer

Användaren anger sitt telefonnummer i din app:

Phone: +380XXXXXXXXX

2. Begär Flash Call

Din server begär snabbsamtalsverifiering:

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

API returnerar det förväntade anrops-ID-mönstret:

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

4. Initiera samtal

Systemet initierar ett samtal till användarens telefon och avslutas efter 1-2 ringsignaler.

5. Fånga nummerpresentation

Användarens app fångar det inkommande samtalets nummerpresentation:

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

6. Verifiera mönster

Jämför fångad nummerpresentation med förväntat mönster:

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

Implementeringsexempel

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

Webb (serversidan)

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

Svarsformat

Framgångssvar

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

Svarsfält

Fält Skriv Beskrivning
meddelande-ID sträng Unikt verifierings-ID
status sträng Status: accepterad, avvisad
callerId sträng Fullständigt nummer för nummerpresentation
mönster sträng Mönster att matcha (siffror + asterisker)
till sträng Mottagarens telefonnummer
ttl heltal Giltighetsperiod i sekunder

Mönstermatchning

API:et returnerar ett mönster med asterisker som maskerar några siffror:

Full number: +380123456789
Pattern:     ***456789

Din app bör:

  1. Fånga inkommande nummerpresentation
  2. Extrahera siffror från nummerpresentation
  3. Matcha mot mönster (asterisker = valfri siffra)
  4. Verifiera matchningen inom TTL-perioden

Alternativ till SMS

Om Flash Call misslyckas, faller du automatiskt tillbaka till SMS:

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

Användningsfall

Kontoregistrering

Verifiera telefonnummer under registreringen utan SMS-kostnader.

Inloggningsverifiering

Tvåfaktorsautentisering med flashsamtal.

Uppdatering av telefonnummer

Verifiera nytt telefonnummer när användaren uppdaterar profilen.

Transaktionsbekräftelse

Bekräfta transaktioner med högt värde med flash-samtal.

Bästa metoder

TTL

  • ✅ Ställ in TTL på 60-90 sekunder
  • ✅ Tillåt användaren att försöka igen efter utgången
  • ❌ Använd inte TTL längre än 120 sekunder

Användarupplevelse

  • Visa meddelandet "Väntar på samtal...".
  • Visa nedräkningstimer (60 sekunder)
  • Ge alternativet "Använd SMS istället"
  • Upptäck och verifiera nummerpresentation automatiskt

Felhantering

  • Hantera saknade telefonbehörigheter
  • Timeout efter att TTL löper ut
  • Tillhandahålla alternativ för SMS
  • Visa tydliga felmeddelanden

Behörigheter

Begär telefonbehörigheter innan flashsamtal:

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>

Testning

  • Testa på olika enheter
  • Testa med olika bärare
  • Testa scenarier för nekande av tillstånd
  • Testa scenarier för nätverkstimeout

Begränsningar

Plattformsstöd

  • Fungerar på alla mobila enheter
  • Kräver telefonsamtalskapacitet
  • Behöver READ_PHONE_STATE-tillstånd – Fungerar kanske inte på surfplattor utan telefon

Nätverk

  • Kräver aktiv telefonanslutning
  • Kan misslyckas under dåliga nätverksförhållanden
  • Operatörsbegränsningar kan gälla
  • Internationella priser kan variera

Sekretess

  • Användare kan blockera okända nummer
  • Vissa enheter har samtalsblockering
  • Kräver uttryckliga tillstånd
  • Tänk på användarnas integritetsproblem

Felsökning

Samtal ej mottaget

  • Kontrollera att telefonen har signal
  • Verifiera nummerformat (E.164)
  • Kontrollera operatörens begränsningar
  • Testa att använda SMS

Mönster matchar inte

  • Se till att fånga korrekt nummerpresentation
  • Ta bort icke-siffriga tecken
  • Kontrollera mönsterformatet
  • Verifiera inom TTL-perioden

Tillstånd nekad

  • Begär behörigheter korrekt
  • Förklara varför behörigheter behövs
  • Tillhandahålla alternativ (SMS)
  • Hantera graciöst

Nästa steg