WappSync
A

WappSync Phone Verify - Documentación de la API

Verificación telefónica en la que su usuario envía un código a nosotros por WhatsApp - sin escribir OTP, un toque, totalmente verificado.

Cómo Funciona

1

Usted solicita un código

Su backend llama a nuestra API con el número de teléfono del usuario. Devolvemos un código único y el número de WhatsApp al que enviarlo.

2

El usuario lo envía por WhatsApp

Su usuario toca un enlace de WhatsApp - el código está predefinido. Sin escribir, sin copiar y pegar. Solo pulsa enviar.

3

Verificado al instante

Recibimos el mensaje, vemos desde qué número de WhatsApp se envió y su consulta devuelve auth=1 con el teléfono certificado. ¡Listo!

Obtenga sus credenciales

Regístrese en wappsync.com/mybusiness para recibir:

CredencialDescripción
businessidSu ID de negocio numérico
businesskeySu clave secreta - nunca la comparta, nunca la ponga en el código del lado del cliente
Importante: Todas las llamadas a la API deben provenir de su backend. La businesskey se usa para la firma HMAC y nunca debe aparecer en JavaScript del navegador, en el código fuente HTML ni en el código de la aplicación móvil.

Dos modos de verificación

Phone Verify funciona en dos modos, elegidos por solicitud. En ambos, su usuario envía el código a nosotros por WhatsApp - la única diferencia es qué número de teléfono se certifica.

confirm_phone (default)verify_sender
Usted envíaun número de teléfono Nnada (sin número)
Qué se certificaque el llamante controla N específicamentecualquier número que realmente devuelva el código
Uso típicoinicio de sesión / recuperación en un número registrado, protección contra el cambio de SIMregistro nuevo - «dame un teléfono real y demostrado para este cliente»
Entrega del códigoEnviado por WhatsApp a N y mostrado en su interfaz (delivery: pushed_to_phone)solo a través de usted (delivery: relay_by_business) - usted entrega el código a su cliente
Resultado de la consultasender_matches_intended le indica si el remitente es NphoneEnc es el número certificado; sender_matches_intended se omite
Seguridad: confirm_phone demuestra el control de un número declarado específico; verify_sender demuestra el control de algún número e informa cuál. Si su flujo necesita que «el número de esta cuenta realmente pertenece al usuario», quédese en confirm_phone con on_mismatch: reject.

Teléfono corregido (on_mismatch): un caso común es que el cliente declare A pero envíe el código desde B (error de escritura / dual-SIM). En confirm_phone, reject (predeterminado) lo trata como un intento fallido; accept_sender certifica en su lugar al remitente real B (sender_matches_intended: false, phoneEnc = B), y su backend decide si acepta el número corregido B o solicita un OTP nuevo para A.

Solicitar un OTP inverso

Llame a esto desde su backend cuando necesite verificar a un usuario:

POSThttps://wappsync.com/phone-verify/api/getReverseOTP

Cuerpo de la solicitud (JSON)

CampoTipoDescripción
businessidintSu ID de negocio
businessrefstringUna referencia única que usted genera para esta solicitud de autenticación (por ej. bin2hex(random_bytes(4)))
phonestringEl número de teléfono del usuario en formato internacional (+40755123456). Obligatorio en el modo confirm_phone; omitir o dejar vacío para verify_sender.
modestringOpcional - confirm_phone (predeterminado cuando se proporciona un teléfono) o verify_sender (predeterminado cuando se omite el teléfono)
on_mismatchstringOpcional (solo confirm_phone) - reject (predeterminado) o accept_sender (certifica al remitente real si el código llega desde un número diferente)
tsintMarca de tiempo Unix actual
hmacstringFirma HMAC-SHA256

Firma HMAC

Firme esta cadena con su businesskey:

{businessid}|{businessref}|{phone}|{ts}

En el modo verify_sender no hay teléfono, por lo que la cadena firmada es {businessid}|{businessref}||{ts} (casilla central vacía).

Ejemplo:

$hmac = hash_hmac('sha256', "{$businessid}|{$businessref}|{$phone}|{$ts}", $businesskey);

Respuesta

CampoTipoDescripción
statusstring"ok" or "error"
reverseotp_displaystringEl código que envía su usuario, por ej. "2FA-828161"
waphonestringEl número de WhatsApp AL QUE su usuario envía el código
logincodestringCódigo interno para usar al consultar
in_tsintMarca de tiempo para la solicitud de consulta
out_tsintMarca de tiempo de la respuesta
otp_valid_minutesintCuánto tiempo es válido el código (predeterminado 10)
modestringEl modo activo: confirm_phone o verify_sender
deliverystringpushed_to_phone (confirm_phone: el código también se envía por WhatsApp al teléfono declarado) o relay_by_business (verify_sender: usted debe entregar el código a su cliente)
hmacstringHMAC de la respuesta - verifique con su businesskey

Verificar el HMAC de la respuesta against {businessid}|{businessref}|{logincode}|{reverseotp_display}|{waphone}|{out_ts}.

Qué mostrar a su usuario

Muestre el código y el número de teléfono. Use un enlace whatsapp://send para que el usuario pueda enviarlo con un solo toque:

<a href="whatsapp://send?phone=40725296320&text=2FA-828161">
  💬 Send Code via WhatsApp
</a>

Consultar la verificación

Consultar cada 2-3 segundos hasta que el usuario esté verificado:

POSThttps://wappsync.com/phone-verify/api/getReverseOTPStatus

Cuerpo de la solicitud (JSON)

CampoTipoDescripción
businessidintSu ID de negocio
businessrefstringLa misma referencia de la llamada anterior
logincodestringEl logincode de la respuesta de getReverseOTP
in_tsintEl ts original de la solicitud getReverseOTP
hmacstringHMAC-SHA256 de {businessid}|{businessref}|{logincode}|{in_ts}

Respuesta

CampoTipoSignificado
used0⏳ Aún esperando - vuelva a consultar
used1✅ Recién verificado - la primera consulta que ve esto lo consume
used2🔒 Ya consumido por una consulta anterior
auth1¡El usuario está verificado - inicie su sesión!
phoneEncstringTeléfono certificado cifrado con AES-256-CBC (solo cuando auth=1) - el remitente cuando se recibió un código (idéntico a su número declarado en confirm_phone estricto)
triesintSe cuentan los intentos fallidos (código incorrecto o teléfono incorrecto)
expiredbooltrue cuando hay demasiados intentos fallidos (intentos ≥ 4) - solicite un OTP nuevo
modestringEl modo de esta solicitud: confirm_phone o verify_sender
sender_matches_intendedboolconfirm_phone solamente, una vez recibido un código - true = el remitente es el número que pidió verificar; false = se certificó un remitente corregido. Se omite en verify_sender.
out_tsintMarca de tiempo de la respuesta
hmacstringHMAC - verifique con {businessid}|{businessref}|{logincode}|{used}|{phoneEnc}|{out_ts}

Cuando auth === 1, se recibió un código válido. Descifre phoneEnc para obtener el teléfono certificado (compruebe sender_matches_intended en el modo confirm_phone) y luego inicie la sesión del usuario.

Descifrar el número de teléfono

Cuando auth=1, phoneEnc contiene el teléfono certificado (el remitente que se demostró) cifrado con AES-256-CBC usando su businesskey:

function decryptPhoneAES($encryptedData, $businesskey) {
    $method = 'AES-256-CBC';
    $key = hash('sha256', $businesskey, true);
    $enc = str_replace(['-', '_'], ['+', '/'], $encryptedData);
    $enc = str_pad($enc, strlen($enc) % 4 === 0
        ? strlen($enc) : strlen($enc) + 4 - strlen($enc) % 4,
        '=', STR_PAD_RIGHT);
    $decoded = base64_decode($enc);
    $iv = substr($decoded, 0, 16);
    $ciphertext = substr($decoded, 16);
    return openssl_decrypt($ciphertext, $method, $key, OPENSSL_RAW_DATA, $iv);
}

$phone = decryptPhoneAES($response['phoneEnc'], $businesskey);
// Store this phone - it's the user's verified identity

Ejemplo de frontend

La única interfaz que necesita - muéstrela después de que su backend llame a getReverseOTP:

<div style="text-align:center; max-width:400px; margin:auto;">
  <p>Send this exact code via WhatsApp from your phone:</p>

  <div style="font-size:28px; font-weight:bold; color:#25D366;
              letter-spacing:3px;">
    2FA-828161
  </div>

  <p>to <strong>+40 725 296 320</strong></p>

  <a href="whatsapp://send?phone=40725296320&text=2FA-828161"
     style="display:inline-block; padding:14px 30px; background:#25D366;
            color:white; font-size:18px; font-weight:bold; border-radius:8px;
            text-decoration:none; margin-top:12px;">
    💬 Send via WhatsApp
  </a>

  <p style="color:#888; font-size:13px; margin-top:12px;">
    ⏱ Code expires in 10 minutes - no typing required!
  </p>
</div>

Ejemplo completo en PHP

Listo para copiar y pegar. Reemplace YOUR_BUSINESS_ID y 'your-secret-key' con los valores de wappsync.com/mybusiness.

<?php
$businessid  = YOUR_BUSINESS_ID;       // from wappsync.com/mybusiness
$businesskey = 'your-secret-key';       // from wappsync.com/mybusiness - keep server-side

// ── Step 1: Request reverse OTP ──
$businessref = bin2hex(random_bytes(4));
$phone       = $_POST['phone'];         // user's phone from your form
$ts          = time();

$hmac = hash_hmac('sha256',
    "{$businessid}|{$businessref}|{$phone}|{$ts}",
    $businesskey
);

$response = callAPI('https://wappsync.com/phone-verify/api/getReverseOTP', [
    'businessid'  => $businessid,
    'businessref' => $businessref,
    'phone'       => $phone,
    'ts'          => $ts,
    'hmac'        => $hmac,
]);

$data = json_decode($response, true);
$code      = $data['reverseotp_display'];  // "2FA-828161"
$waphone   = $data['waphone'];             // "+40725296320"
$logincode = $data['logincode'];
$in_ts     = $data['in_ts'];

// ── Show the code to your user (render frontend example above) ──

// ── Step 2: Poll until verified ──
$maxAttempts = 40;  // ~2 minutes at 3s intervals
$attempt = 0;

do {
    sleep(3);
    $attempt++;

    $hmac = hash_hmac('sha256',
        "{$businessid}|{$businessref}|{$logincode}|{$in_ts}",
        $businesskey
    );

    $response = callAPI(
        'https://wappsync.com/phone-verify/api/getReverseOTPStatus',
        [
            'businessid'  => $businessid,
            'businessref' => $businessref,
            'logincode'   => $logincode,
            'in_ts'       => $in_ts,
            'hmac'        => $hmac,
        ]
    );

    $data = json_decode($response, true);

} while (($data['auth'] ?? 0) !== 1 && $attempt < $maxAttempts);

if (($data['auth'] ?? 0) === 1) {
    // ✅ Verified - log the user in!
    $phone = decryptPhoneAES($data['phoneEnc'], $businesskey);
    $_SESSION['user_phone'] = $phone;
    header('Location: /dashboard');
    exit;
} else {
    echo "Verification timed out. Please try again.";
}

// ── Helper ──
function callAPI($url, $payload) {
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
    curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $response = curl_exec($ch);
    curl_close($ch);
    return $response;
}

verify_sender: envíe phone => '' (y opcionalmente mode => 'verify_sender') - no se envía nada por WhatsApp, así que usted mismo debe transmitir el reverseotp_display a su cliente. Con auth=1, phoneEnc se descifra al número certificado del remitente; no hay sender_matches_intended que comprobar.

accept_sender: para confirm_phone, añada 'on_mismatch' => 'accept_sender'. Si auth=1 y sender_matches_intended es false, el número certificado difiere del solicitado - acéptelo como número corregido o solicite un OTP nuevo para el número que realmente necesita.

Gestión de errores

La API devuelve "status": "error" con un message legible:

HTTPmessageCuándo
400Missing required parametersOlvidó un campo obligatorio
400A phone is required in confirm_phone modeconfirm_phone solicitado sin un teléfono
400Invalid mode / Invalid on_mismatchValor de enum desconocido
400The phone number is invalid or not a mobile number.Formato de teléfono incorrecto
403Unknown or invalid business IDbusinessid incorrecto
403Invalid HMACLa firma no coincide - compruebe la cadena de firma
409This request was already used.businessref+in_ts duplicado

Seguridad

🔐 HMAC-signedCada solicitud y respuesta se verifica con su businesskey
📱 Coincidencia de teléfono según el modoconfirm_phone verifica que el remitente coincide con el número solicitado; verify_sender / accept_sender solo certifican al remitente real - nunca un número que no envió nada
🎯 Códigos en vivo únicosDos códigos pendientes no comparten valor, por lo que un código entrante se asigna de forma determinista a una sola solicitud
🔂 Single-useLos códigos pasan por 0→1→2, nunca reutilizables
⏱ Time-limitedLos códigos expiran después de 10 minutos, máximo 4 intentos de entrega
🔒 Sin secretos de clienteSu businesskey permanece en su servidor; nunca en el código del navegador
🛡 Cifrado AES-256Los números de teléfono en las respuestas se cifran con su businesskey

Pruébelo en vivo

🎮 Flujo de inicio de sesión de la demo - una demo funcional que muestra la experiencia completa del usuario.

🧪 Herramienta de prueba de API - requiere su propio businessid y businesskey de wappsync.com/mybusiness.