Bleskový hovor
Flash Call je metoda telefonického ověření, která k ověření telefonních čísel používá místo SMS zmeškaný hovor. Je to rychlejší, bezpečnější a cenově výhodnější.
Přehled
Ověření Flash Call funguje takto:
- Uživatel požaduje ověření
- Systém zahájí hovor na telefon uživatele
- Hovor je automaticky ukončen po 1-2 zazvoněních
- Aplikace uživatele zachytí ID volajícího
- ID volajícího je ověřeno podle očekávaného vzoru
- Uživatel je ověřen
Výhody
Nákladově efektivní
- Až 10x levnější než SMS
- Žádné poplatky za doručení zpráv
- Snížené náklady na velkoobjemové ověřování
Rychlejší
- Okamžité ověření (1-3 sekundy)
- Žádné čekání na doručení SMS
- Lepší uživatelský zážitek
Bezpečnější
- Je těžší zachytit než SMS
- Žádné OTP viditelné v oznámeních
- Odolné vůči útokům s výměnou SIM
Globální dosah
- Funguje v zemích s omezeními SMS
- Žádné problémy s filtrováním SMS
- Univerzální kompatibilita s telefony
Základní Flash Call
Žádost
{
"from": "YourApp",
"to": "+380XXXXXXXXX",
"type": "flashcall",
"messageData": {
"callerId": "+380123456789"
}
}
Parametry
| Parametr | Typ | Povinné | Popis |
|---|---|---|---|
| "od" | řetězec | Ano | Váš identifikátor odesílatele |
do |
řetězec | Ano | Telefonní číslo příjemce (E.164) |
| "typ" | řetězec | Ano | Nastavit na "flashcall" |
| "ID volajícího" | řetězec | Ano | Telefonní číslo, které bude volat uživateli |
ttl |
celé číslo | Ne | Doba životnosti v sekundách (výchozí: 60) |
Jak to funguje
1. Uživatel zadá telefonní číslo
Uživatel poskytne své telefonní číslo ve vaší aplikaci:
2. Vyžádejte si Flash Call
Váš server požaduje ověření bleskovým voláním:
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. Odpověď API
API vrací očekávaný vzor ID volajícího:
{
"messagelistId": 123456,
"messages": [
{
"messageId": "abc123def456",
"status": "accepted",
"callerId": "+380123456789",
"pattern": "***456789",
"to": "+380XXXXXXXXX"
}
]
}
4. Zahajte hovor
Systém zahájí hovor na telefon uživatele a ukončí jej po 1-2 zazvoněních.
5. Zachyťte ID volajícího
Uživatelská aplikace zachytí ID volajícího příchozího hovoru:
// Android example
val cursor = contentResolver.query(
CallLog.Calls.CONTENT_URI,
arrayOf(CallLog.Calls.NUMBER),
null, null,
CallLog.Calls.DATE + " DESC"
)
6. Ověřte vzor
Porovnejte zachycené ID volajícího s očekávaným vzorem:
// 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);
}
Příklady implementace
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 straně serveru)
// 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' });
}
});
Formát odpovědi
Úspěšná odpověď
{
"messagelistId": 123456,
"messages": [
{
"messageId": "abc123def456",
"status": "accepted",
"callerId": "+380123456789",
"pattern": "***456789",
"to": "+380XXXXXXXXX",
"ttl": 60
}
]
}
Pole odpovědí
| Pole | Typ | Popis |
|---|---|---|
ID zprávy |
řetězec | Jedinečné ověřovací ID |
| "stav" | řetězec | Stav: přijato, zamítnuto |
| "ID volajícího" | řetězec | Celé číslo volajícího |
| "vzor" | řetězec | Vzor, který se má shodovat (číslice + hvězdičky) |
do |
řetězec | Telefonní číslo příjemce |
ttl |
celé číslo | Doba platnosti v sekundách |
Shoda vzorů
API vrací vzor s hvězdičkami maskujícími některé číslice:
Vaše aplikace by měla:
- Zachyťte ID příchozího volajícího
- Extrahujte číslice z ID volajícího
- Porovnejte se vzorem (hvězdičky = libovolná číslice)
- Ověřte shodu v období TTL
Záloha na SMS
Pokud selže Flash Call, automaticky se vraťte k SMS:
{
"from": "YourApp",
"to": "+380XXXXXXXXX",
"type": "flashcall",
"messageData": {
"callerId": "+380123456789"
},
"fallback": {
"type": "sms",
"text": "Your verification code is: 123456"
},
"ttl": 60
}
Případy použití
Registrace účtu
Ověřte telefonní čísla během registrace bez poplatků za SMS.
Ověření přihlášení
Dvoufaktorová autentizace pomocí bleskového volání.
Aktualizace telefonního čísla
Ověřte nové telefonní číslo, když uživatel aktualizuje profil.
Potvrzení transakce
Potvrďte transakce s vysokou hodnotou pomocí bleskového volání.
Nejlepší postupy
TTL
- ✅ Nastavte TTL na 60-90 sekund
- ✅ Umožněte uživateli opakovat po vypršení platnosti
- ❌ Nepoužívejte TTL déle než 120 sekund
Uživatelská zkušenost
- Zobrazit zprávu "Čekání na hovor..."
- Displej odpočítávacího časovače (60 sekund)
- Poskytněte možnost "Použít místo toho SMS"
- Automatická detekce a ověření ID volajícího
Zpracování chyb
- Řešit chybějící oprávnění telefonu
- Časový limit po vypršení TTL
- Poskytněte možnost záložní SMS
- Zobrazit jasné chybové zprávy
Oprávnění
Před bleskovým hovorem si vyžádejte oprávnění k telefonu:
Android:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
iOS:
Testování
- Test na různých zařízeních
- Test s různými dopravci
- Testovat scénáře zamítnutí povolení
- Testujte scénáře časového limitu sítě
Omezení
Podpora platformy
- Funguje na všech mobilních zařízeních
- Vyžaduje schopnost telefonovat – Vyžaduje oprávnění READ_PHONE_STATE
- Nemusí fungovat na tabletech bez telefonu
Síť
- Vyžaduje aktivní telefonní připojení
- Může selhat ve špatných podmínkách sítě
- Mohou platit omezení dopravce
- Mezinárodní sazby se mohou lišit
Soukromí
- Uživatelé mohou blokovat neznámá čísla
- Některá zařízení mají blokování hovorů
- Vyžaduje explicitní oprávnění
- Zvažte obavy o soukromí uživatelů
Odstraňování problémů
Hovor nepřijat
- Zkontrolujte, zda má telefon signál
- Ověřte formát čísla (E.164)
- Zkontrolujte omezení operátora
- Zkuste záložní SMS
Vzor neodpovídá
- Zajistěte zachycení správného ID volajícího
- Odstraňte nečíselné znaky
- Zkontrolujte formát vzoru
- Ověřte během období TTL
Oprávnění odepřeno
- Řádně vyžádejte oprávnění
- Vysvětlete, proč jsou potřebná oprávnění
- Poskytněte alternativu (SMS)
- Zacházejte elegantně
Další kroky
- Viber OTP - Alternativní doručování OTP – Zprávy SMS – Záložní SMS
- Kontrola stavu - Sledujte stav flashového hovoru