Aller au contenu

Appel Flash

Flash Call est une méthode de vérification téléphonique qui utilise un appel manqué au lieu de SMS pour vérifier les numéros de téléphone. C'est plus rapide, plus sécurisé et plus rentable.

Aperçu

La vérification des appels Flash fonctionne comme suit :

  1. L'utilisateur demande une vérification
  2. Le système lance un appel vers le téléphone de l'utilisateur
  3. L'appel est automatiquement terminé après 1 à 2 sonneries
  4. L'application de l'utilisateur capture l'identification de l'appelant
  5. L'identification de l'appelant est vérifiée par rapport au modèle attendu
  6. L'utilisateur est authentifié

Avantages

Rentable

  • Jusqu'à 10 fois moins cher que les SMS
  • Aucun frais de livraison de message
  • Coûts réduits pour la vérification de gros volumes

Plus vite

  • Vérification instantanée (1-3 secondes)
  • Pas d'attente pour la livraison des SMS
  • Meilleure expérience utilisateur

Plus sécurisé

  • Plus difficile à intercepter que les SMS
  • Aucun OTP visible dans les notifications
  • Résistant aux attaques d'échange de carte SIM

Portée mondiale

  • Fonctionne dans les pays avec des restrictions SMS
  • Aucun problème avec le filtrage des SMS
  • Compatibilité téléphonique universelle

Appel Flash de base

Demande

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

Paramètres

Paramètre Tapez Obligatoire Descriptif
de chaîne Oui Votre identifiant d'expéditeur
à chaîne Oui Numéro de téléphone du destinataire (E.164)
type chaîne Oui Réglé sur "flashcall"
ID de l'appelant chaîne Oui Numéro de téléphone qui appellera l'utilisateur
ttl entier Non Durée de vie en secondes (par défaut : 60)

Comment ça marche

1. L'utilisateur saisit son numéro de téléphone

L'utilisateur fournit son numéro de téléphone dans votre application :

Phone: +380XXXXXXXXX

2. Demander un appel flash

Votre serveur demande une vérification flash des appels :

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éponse de l'API

L'API renvoie le modèle d'identification de l'appelant attendu :

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

4. Lancer un appel

Le système lance un appel vers le téléphone de l'utilisateur et se termine après 1 à 2 sonneries.

5. Capturer l'identification de l'appelant

L'application de l'utilisateur capture l'identifiant de l'appelant de l'appel entrant :

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

6. Vérifier le modèle

Comparez l'ID de l'appelant capturé avec le modèle attendu :

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

Exemples de mise en œuvre

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 (côté serveur)

// 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éponse

Réponse réussie

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

Champs de réponse

Champ Tapez Descriptif
messageId chaîne ID de vérification unique
statut chaîne Statut : accepté, rejeté
ID de l'appelant chaîne Numéro d'identification complet de l'appelant
modèle chaîne Modèle correspondant (chiffres + astérisques)
à chaîne Numéro de téléphone du destinataire
ttl entier Période de validité en secondes

Correspondance de modèles

L'API renvoie un modèle avec des astérisques masquant certains chiffres :

Full number: +380123456789
Pattern:     ***456789

Votre application doit :

  1. Capturez l'identification de l'appelant entrant
  2. Extraire les chiffres de l'identification de l'appelant
  3. Correspondance avec un modèle (astérisques = n'importe quel chiffre)
  4. Vérifiez la correspondance dans la période TTL

Revenir aux SMS

Si Flash Call échoue, revenez automatiquement aux SMS :

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

Cas d'utilisation

Enregistrement du compte

Vérifiez les numéros de téléphone lors de l'inscription sans frais SMS.

Vérification de connexion

Authentification à deux facteurs par appel flash.

Mise à jour du numéro de téléphone

Vérifiez le nouveau numéro de téléphone lorsque l'utilisateur met à jour son profil.

Confirmation de transaction

Confirmez les transactions de grande valeur avec un appel flash.

meilleures pratiques

TTL

  • ✅ Réglez TTL sur 60-90 secondes
  • ✅ Autoriser l'utilisateur à réessayer après l'expiration
  • ❌ N'utilisez pas TTL plus de 120 secondes

Expérience utilisateur

  • Afficher le message "En attente d'un appel..."
  • Afficher le compte à rebours (60 secondes)
  • Fournir l'option "Utiliser SMS à la place"
  • Détecter et vérifier automatiquement l'identification de l'appelant

Gestion des erreurs

  • Gérer les autorisations téléphoniques manquantes
  • Délai d'expiration après l'expiration du TTL
  • Fournir une option de secours SMS
  • Afficher des messages d'erreur clairs

Autorisations

Demander des autorisations téléphoniques avant un appel 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>

Tests

  • Tester sur différents appareils
  • Test avec différents transporteurs
  • Tester les scénarios de refus d'autorisation
  • Tester les scénarios d'expiration du réseau

Limites

Prise en charge de la plateforme

  • Fonctionne sur tous les appareils mobiles
  • Nécessite une capacité d'appel téléphonique
  • Nécessite l'autorisation READ_PHONE_STATE
  • Peut ne pas fonctionner sur les tablettes sans téléphone

Réseau

  • Nécessite une connexion téléphonique active
  • Peut échouer dans de mauvaises conditions de réseau
  • Des restrictions de transporteur peuvent s'appliquer
  • Les tarifs internationaux peuvent varier

Confidentialité

  • Les utilisateurs peuvent bloquer les numéros inconnus
  • Certains appareils disposent d'un blocage d'appels
  • Nécessite des autorisations explicites
  • Tenir compte des problèmes de confidentialité des utilisateurs

Dépannage

Appel non reçu

  • Vérifiez que le téléphone a un signal
  • Vérifier le format du numéro (E.164)
  • Vérifier les restrictions du transporteur
  • Essayez la solution de secours SMS

Le modèle ne correspond pas

  • Assurez-vous de capturer l'identification correcte de l'appelant
  • Supprimer les caractères non numériques
  • Vérifier le format du motif
  • Vérifier dans la période TTL

Autorisation refusée

  • Demander les autorisations correctement
  • Expliquez pourquoi les autorisations sont nécessaires
  • Fournir une alternative (SMS)
  • Manipuler avec grâce

Prochaines étapes