Flash Call
Flash Call on puhelimen vahvistusmenetelmä, joka vahvistaa puhelinnumerot tekstiviestien sijaan vastaamatta jääneen puhelun avulla. Se on nopeampi, turvallisempi ja kustannustehokkaampi.
Yleiskatsaus
Flash Call -vahvistus toimii:
- Käyttäjä pyytää vahvistusta
- Järjestelmä aloittaa puhelun käyttäjän puhelimeen
- Puhelu katkeaa automaattisesti 1-2 soiton jälkeen
- Käyttäjän sovellus tallentaa soittajan tunnuksen
- Soittajan tunnus tarkistetaan odotetun kaavan mukaan
- Käyttäjä on todennettu
Edut
Kustannustehokas
- Jopa 10x halvempi kuin tekstiviesti
- Ei viestien toimitusmaksuja
- Pienemmät suuren volyymin tarkastuksen kustannukset
Nopeammin
- Välitön vahvistus (1-3 sekuntia)
- Ei odottelua tekstiviestien toimitusta
- Parempi käyttökokemus
Turvallisempi
- Vaikeampi siepata kuin tekstiviesti
- OTP:tä ei näy ilmoituksissa
- Kestää SIM-swap-hyökkäyksiä
Globaali kattavuus
- Toimii maissa, joissa on tekstiviestirajoituksia
- Ei ongelmia tekstiviestisuodatuksen kanssa
- Universaali puhelinyhteensopivuus
Flash-peruspuhelu
Pyyntö
{
"from": "YourApp",
"to": "+380XXXXXXXXX",
"type": "flashcall",
"messageData": {
"callerId": "+380123456789"
}
}
Parametrit
| Parametri | Tyyppi | Pakollinen | Kuvaus |
|---|---|---|---|
| "alkaen" | merkkijono | Kyllä | Lähettäjän tunniste |
| "to" | merkkijono | Kyllä | Vastaanottajan puhelinnumero (E.164) |
| "tyyppi" | merkkijono | Kyllä | Aseta "flashcall" |
| "soittajan tunnus" | merkkijono | Kyllä | Puhelinnumero, joka soittaa käyttäjälle |
ttl |
kokonaisluku | Ei | Elinaika sekunneissa (oletus: 60) |
Kuinka se toimii
1. Käyttäjä syöttää puhelinnumeron
Käyttäjä antaa puhelinnumeronsa sovelluksessasi:
2. Pyydä Flash Call
Palvelimesi pyytää flash-puhelun vahvistusta:
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-vastaus
API palauttaa odotetun soittajan tunnuskuvion:
{
"messagelistId": 123456,
"messages": [
{
"messageId": "abc123def456",
"status": "accepted",
"callerId": "+380123456789",
"pattern": "***456789",
"to": "+380XXXXXXXXX"
}
]
}
4. Aloita puhelu
Järjestelmä aloittaa puhelun käyttäjän puhelimeen ja lopettaa 1-2 soiton jälkeen.
5. Tallenna soittajan tunnus
Käyttäjän sovellus tallentaa saapuvan puhelun soittajan tunnuksen:
// Android example
val cursor = contentResolver.query(
CallLog.Calls.CONTENT_URI,
arrayOf(CallLog.Calls.NUMBER),
null, null,
CallLog.Calls.DATE + " DESC"
)
6. Vahvista kuvio
Vertaa tallennettua soittajan tunnusta odotettuun kuvioon:
// 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);
}
Toteutusesimerkkejä
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 (palvelinpuoli)
// 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' });
}
});
Vastausmuoto
Menestysvastaus
{
"messagelistId": 123456,
"messages": [
{
"messageId": "abc123def456",
"status": "accepted",
"callerId": "+380123456789",
"pattern": "***456789",
"to": "+380XXXXXXXXX",
"ttl": 60
}
]
}
Vastauskentät
| Kenttä | Tyyppi | Kuvaus |
|---|---|---|
| "messageId" | merkkijono | Yksilöllinen vahvistustunnus |
| "tila" | merkkijono | Tila: "hyväksytty", "hylätty" |
| "soittajan tunnus" | merkkijono | Täydellinen soittajan numero |
| "kuvio" | merkkijono | Vastaava kuvio (numerot + tähdet) |
| "to" | merkkijono | Vastaanottajan puhelinnumero |
ttl |
kokonaisluku | Voimassaoloaika sekunneissa |
Kuvioiden yhteensopivuus
API palauttaa kuvion, jossa tähdet peittävät joitain numeroita:
Sovelluksesi pitäisi:
- Tallenna saapuvan soittajan tunnus
- Poimi numerot soittajan tunnuksesta
- Vastaa kuvioon (tähdet = mikä tahansa numero)
- Tarkista vastaavuus TTL-jakson sisällä
Takaisin tekstiviestiin
Jos Flash Call epäonnistuu, palaa automaattisesti tekstiviestiin:
{
"from": "YourApp",
"to": "+380XXXXXXXXX",
"type": "flashcall",
"messageData": {
"callerId": "+380123456789"
},
"fallback": {
"type": "sms",
"text": "Your verification code is: 123456"
},
"ttl": 60
}
Käyttötapaukset
Tilin rekisteröinti
Vahvista puhelinnumerot rekisteröitymisen yhteydessä ilman tekstiviestikuluja.
Kirjautumisen vahvistus
Kaksivaiheinen todennus flash-puhelulla.
Puhelinnumeron päivitys
Vahvista uusi puhelinnumero, kun käyttäjä päivittää profiilia.
Tapahtuman vahvistus
Vahvista arvokkaat tapahtumat flash-puhelulla.
Parhaat käytännöt
TTL
- ✅ Aseta TTL 60-90 sekuntiin
- ✅ Anna käyttäjän yrittää uudelleen vanhenemisen jälkeen
- ❌ Älä käytä TTL:ää yli 120 sekuntia
Käyttökokemus
- Näytä "Odotetaan puhelua..." -viesti
- Näytön ajastin (60 sekuntia)
- Anna vaihtoehto "Käytä tekstiviestejä"
- Tunnista ja vahvista soittajan tunnus automaattisesti
Virheiden käsittely
- Käsittele puuttuvat puhelimen käyttöoikeudet
- Aikakatkaisu TTL:n päättymisen jälkeen
- Tarjoa tekstiviestien varavaihtoehto
- Näytä selkeät virheilmoitukset
Käyttöoikeudet
Pyydä puhelimen käyttöoikeuksia ennen flash-puhelua:
Android:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
iOS:
Testaus
- Testaa eri laitteilla
- Testaa eri operaattoreiden kanssa
- Testaa lupien epäämisskenaarioita
- Testaa verkon aikakatkaisutilanteita
Rajoitukset
Alustan tuki
- Toimii kaikilla mobiililaitteilla
- Edellyttää puhelukykyä
- Tarvitsee READ_PHONE_STATE-luvan
- Ei ehkä toimi tableteilla ilman puhelinta
Verkko
- Vaatii aktiivisen puhelinyhteyden
- Voi epäonnistua huonoissa verkko-olosuhteissa
- Operaattorin rajoitukset voivat olla voimassa
- Kansainväliset hinnat voivat vaihdella
Yksityisyys
- Käyttäjät voivat estää tuntemattomia numeroita
- Joissakin laitteissa on puhelun esto
- Edellyttää nimenomaisia käyttöoikeuksia
- Harkitse käyttäjien yksityisyyttä koskevia huolenaiheita
Vianetsintä
Puhelua ei vastaanotettu
- Tarkista, että puhelimessa on signaali
- Tarkista numeromuoto (E.164)
- Tarkista operaattorin rajoitukset
- Kokeile SMS-varaustoimintoa
Kuvio ei täsmää
- Varmista, että otat oikean soittajan tunnuksen
- Poista ei-numeroiset merkit
- Tarkista kuvion muoto
- Tarkista TTL-ajan kuluessa
Lupa evätty
- Pyydä käyttöoikeuksia oikein
- Selitä, miksi lupia tarvitaan
- Tarjoa vaihtoehto (SMS)
- Käsittele kauniisti
Seuraavat vaiheet
- Viber OTP - Vaihtoehtoinen OTP-toimitus
- Tekstiviestit - Varatekstiviestit
- Tarkista tila - Seuraa flash-puhelun tilaa