Saltar a contenido

Llamada rápida

Flash Call es un método de verificación telefónica que utiliza una llamada perdida en lugar de SMS para verificar números de teléfono. Es más rápido, más seguro y rentable.

Descripción general

La verificación de llamadas flash funciona mediante:

  1. El usuario solicita verificación
  2. El sistema inicia una llamada al teléfono del usuario.
  3. La llamada finaliza automáticamente después de 1 o 2 timbres.
  4. La aplicación del usuario captura el identificador de llamadas.
  5. El identificador de llamadas se verifica con el patrón esperado
  6. El usuario está autenticado

Beneficios

Rentable

  • Hasta 10 veces más barato que los SMS
  • Sin tarifas de envío de mensajes
  • Costos reducidos para la verificación de gran volumen

Más rápido

  • Verificación instantánea (1-3 segundos)
  • Sin esperas para la entrega de SMS
  • Mejor experiencia de usuario

Más seguro

  • Más difícil de interceptar que los SMS
  • No hay OTP visible en las notificaciones.
  • Resistente a ataques de intercambio de SIM

Alcance global

  • Funciona en países con restricciones de SMS
  • No hay problemas con el filtrado de SMS
  • Compatibilidad universal con teléfonos

Llamada flash básica

Solicitud

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

Parámetros

Parámetro Tipo Requerido Descripción
de cadena Su identificador de remitente
a cadena Número de teléfono del destinatario (E.164)
tipo cadena Establecer en "flashcall"
Id. de llamada cadena Número de teléfono que llamará al usuario
ttl entero No Tiempo de vida en segundos (predeterminado: 60)

Cómo funciona

1. El usuario ingresa el número de teléfono

El usuario proporciona su número de teléfono en su aplicación:

Phone: +380XXXXXXXXX

2. Solicitar llamada flash

Su servidor solicita verificación de llamada 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. Respuesta de la API

La API devuelve el patrón de identificación de llamadas esperado:

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

4. Iniciar llamada

El sistema inicia una llamada al teléfono del usuario y finaliza después de 1 o 2 timbres.

5. Capturar el identificador de llamadas

La aplicación del usuario captura el identificador de llamadas de la llamada entrante:

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

6. Verificar patrón

Compare el identificador de llamadas capturado con el patrón esperado:

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

Ejemplos de implementación

androide

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 (del lado del servidor)

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

Formato de respuesta

Respuesta exitosa

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

Campos de respuesta

Campo Tipo Descripción
Id del mensaje cadena ID de verificación única
estado cadena Estado: aceptado, rechazado
Id. de llamada cadena Número completo de identificación de llamadas
patrón cadena Patrón a coincidir (dígitos + asteriscos)
a cadena Número de teléfono del destinatario
ttl entero Periodo de validez en segundos

Coincidencia de patrones

La API devuelve un patrón con asteriscos que enmascaran algunos dígitos:

Full number: +380123456789
Pattern:     ***456789

Tu aplicación debería:

  1. Capture el identificador de llamadas entrantes
  2. Extraer dígitos del identificador de llamadas
  3. Coincidir con el patrón (asteriscos = cualquier dígito)
  4. Verificar la coincidencia dentro del período TTL

Recurrir a SMS

Si falla la llamada Flash, recurra automáticamente a SMS:

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

Casos de uso

Registro de cuenta

Verifique los números de teléfono durante el registro sin costos de SMS.

Verificación de inicio de sesión

Autenticación de dos factores mediante llamada flash.

Actualización del número de teléfono

Verificar el nuevo número de teléfono cuando el usuario actualice el perfil.

Confirmación de transacción

Confirme transacciones de alto valor con una llamada flash.

Mejores prácticas

TTL

  • ✅ Configure TTL en 60-90 segundos
  • ✅ Permitir al usuario volver a intentarlo después del vencimiento
  • ❌ No uses TTL por más de 120 segundos

Experiencia de usuario

  • Mostrar mensaje "Esperando llamada..."
  • Mostrar temporizador de cuenta regresiva (60 segundos)
  • Proporcionar la opción de "Usar SMS en su lugar"
  • Detectar y verificar automáticamente el identificador de llamadas

Manejo de errores

  • Manejar los permisos telefónicos faltantes
  • Tiempo de espera después de que expire TTL
  • Proporcionar opción de respaldo de SMS
  • Mostrar mensajes de error claros

Permisos

Solicite permisos telefónicos antes de la llamada flash:

Androide:

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

Pruebas

  • Prueba en diferentes dispositivos
  • Prueba con diferentes transportistas.
  • Pruebe escenarios de denegación de permiso
  • Probar escenarios de tiempo de espera de red

Limitaciones

Soporte de plataforma

  • Funciona en todos los dispositivos móviles
  • Requiere capacidad de llamada telefónica
  • Necesita permiso READ_PHONE_STATE
  • Puede que no funcione en tabletas sin teléfono

Red

  • Requiere conexión telefónica activa
  • Puede fallar en malas condiciones de red
  • Pueden aplicarse restricciones del transportista
  • Las tarifas internacionales pueden variar.

Privacidad

  • Los usuarios pueden bloquear números desconocidos.
  • Algunos dispositivos tienen bloqueo de llamadas.
  • Requiere permisos explícitos
  • Considere las preocupaciones de privacidad del usuario.

Solución de problemas

Llamada no recibida

  • Verificar que el teléfono tenga señal.
  • Verificar formato de número (E.164)
  • Verifique las restricciones del operador
  • Pruebe el respaldo de SMS

Patrón que no coincide

  • Asegúrese de capturar el identificador de llamadas correcto
  • Tirar caracteres que no sean dígitos
  • Verificar formato de patrón
  • Verificar dentro del período TTL

Permiso denegado

  • Solicitar permisos correctamente
  • Explicar por qué se necesitan permisos.
  • Proporcionar alternativa (SMS)
  • Manejar con gracia

Próximos pasos