WappSync
A

WappSync Phone Verify - Documentação da API

Verificação por telefone em que seu usuário envia um código para nós via WhatsApp - sem digitar OTP, um toque, totalmente verificado.

Como funciona

1

Você solicita um código

Seu backend chama nossa API com o número de telefone do usuário. Retornamos um código exclusivo e o número do WhatsApp para o qual enviá-lo.

2

O usuário o envia pelo WhatsApp

Seu usuário toca em um link do WhatsApp - o código está pré-preenchido. Sem digitar, sem copiar e colar. Ele apenas toca em enviar.

3

Verificado instantaneamente

Recebemos a mensagem, vemos de qual número do WhatsApp ela foi enviada e sua consulta retorna auth=1 com o telefone certificado. Pronto!

Obtenha suas credenciais

Cadastre-se em wappsync.com/mybusiness para receber:

CredencialDescrição
businessidSeu ID de empresa numérico
businesskeySua chave secreta - nunca compartilhe, nunca coloque no código do lado do cliente
Importante: Todas as chamadas de API devem vir do seu backend. A businesskey é usada para assinatura HMAC e nunca deve aparecer em JavaScript do navegador, no código-fonte HTML ou no código do aplicativo móvel.

Dois modos de verificação

O Phone Verify funciona em dois modos, escolhidos por solicitação. Em ambos, seu usuário envia o código para nós via WhatsApp - a única diferença é qual número de telefone é certificado.

confirm_phone (default)verify_sender
Você enviaum número de telefone Nnada (nenhum número)
O que é certificadoque o solicitante controla N especificamentequalquer número que realmente devolva o código
Uso típicologin / recuperação em um número cadastrado, proteção contra troca de SIMcadastro novo - "me dê um telefone real e comprovado para este cliente"
Entrega do códigoEnviado pelo WhatsApp para N e exibido na sua interface (delivery: pushed_to_phone)somente através de você (delivery: relay_by_business) - você entrega o código ao seu cliente
Resultado da consultasender_matches_intended informa se o remetente é NphoneEnc é o número certificado; sender_matches_intended é omitido
Segurança: confirm_phone prova o controle de um número declarado específico; verify_sender prova o controle de algum número e informa qual. Se o seu fluxo exige que "o número nesta conta realmente pertence ao usuário", fique com confirm_phone e on_mismatch: reject.

Telefone corrigido (on_mismatch): um caso comum é o cliente declarar A mas enviar o código de B (erro de digitação / dual-SIM). Em confirm_phone, reject (padrão) trata isso como uma tentativa falha; accept_sender certifica o remetente real B em vez disso (sender_matches_intended: false, phoneEnc = B), e seu backend decide se aceita o número corrigido B ou solicita um novo OTP para A.

Solicitar um OTP reverso

Chame isso do seu backend quando precisar verificar um usuário:

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

Corpo da solicitação (JSON)

CampoTipoDescrição
businessidintSeu ID de empresa
businessrefstringUma referência exclusiva que você gera para esta solicitação de autenticação (ex.: bin2hex(random_bytes(4)))
phonestringO número de telefone do usuário em formato internacional (+40755123456). Obrigatório no modo confirm_phone; omita ou deixe vazio para verify_sender.
modestringOpcional - confirm_phone (padrão quando um telefone é fornecido) ou verify_sender (padrão quando o telefone é omitido)
on_mismatchstringOpcional (apenas confirm_phone) - reject (padrão) ou accept_sender (certifica o remetente real se o código chegar de um número diferente)
tsintTimestamp Unix atual
hmacstringAssinatura HMAC-SHA256

Assinatura HMAC

Assine esta string com sua businesskey:

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

No modo verify_sender não há telefone, então a string assinada é {businessid}|{businessref}||{ts} (posição do meio vazia).

Exemplo:

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

Resposta

CampoTipoDescrição
statusstring"ok" or "error"
reverseotp_displaystringO código que seu usuário envia, ex.: "2FA-828161"
waphonestringO número do WhatsApp PARA o qual seu usuário envia o código
logincodestringCódigo interno a usar ao consultar
in_tsintTimestamp para a solicitação de consulta
out_tsintTimestamp da resposta
otp_valid_minutesintPor quanto tempo o código é válido (padrão 10)
modestringO modo ativo: confirm_phone ou verify_sender
deliverystringpushed_to_phone (confirm_phone: o código também é enviado pelo WhatsApp ao telefone declarado) ou relay_by_business (verify_sender: você mesmo deve entregar o código ao seu cliente)
hmacstringHMAC da resposta - verifique com sua businesskey

Verificar o HMAC da resposta against {businessid}|{businessref}|{logincode}|{reverseotp_display}|{waphone}|{out_ts}.

O que mostrar ao seu usuário

Exiba o código e o número de telefone. Use um link whatsapp://send para que o usuário possa enviá-lo com um único toque:

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

Consultar a verificação

Consultar a cada 2-3 segundos até que o usuário seja verificado:

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

Corpo da solicitação (JSON)

CampoTipoDescrição
businessidintSeu ID de empresa
businessrefstringA mesma referência da chamada anterior
logincodestringO logincode da resposta do getReverseOTP
in_tsintO ts original da solicitação getReverseOTP
hmacstringHMAC-SHA256 de {businessid}|{businessref}|{logincode}|{in_ts}

Resposta

CampoTipoSignificado
used0⏳ Ainda aguardando - consulte novamente
used1✅ Acabou de ser verificado - a primeira consulta que vê isso o consome
used2🔒 Já consumido por uma consulta anterior
auth1O usuário está verificado - faça o login dele!
phoneEncstringTelefone certificado criptografado com AES-256-CBC (apenas quando auth=1) - o remetente quando um código foi recebido (idêntico ao número declarado no modo confirm_phone estrito)
triesintTentativas falhas são contadas (código errado ou telefone errado)
expiredbooltrue quando há tentativas falhas demais (tentativas ≥ 4) - solicite um novo OTP
modestringO modo desta solicitação: confirm_phone ou verify_sender
sender_matches_intendedboolconfirm_phone apenas, quando um código for recebido - true = o remetente é o número que você pediu para verificar; false = um remetente corrigido foi certificado. Omitido em verify_sender.
out_tsintTimestamp da resposta
hmacstringHMAC - verifique com {businessid}|{businessref}|{logincode}|{used}|{phoneEnc}|{out_ts}

Quando auth === 1, um código válido foi recebido. Descriptografe phoneEnc para obter o telefone certificado (verifique sender_matches_intended no modo confirm_phone) e então faça o login do usuário.

Descriptografar o número de telefone

Quando auth=1, phoneEnc contém o telefone certificado (o remetente que se provou) criptografado com AES-256-CBC usando sua 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

Exemplo de frontend

A única interface necessária - mostre-a depois que seu backend chamar 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>

Exemplo completo em PHP

Pronto para copiar e colar. Substitua YOUR_BUSINESS_ID e 'your-secret-key' pelos 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: envie phone => '' (e opcionalmente mode => 'verify_sender') - nada é enviado pelo WhatsApp, então você mesmo deve repassar o reverseotp_display ao seu cliente. Com auth=1, phoneEnc é descriptografado para o número certificado do remetente; não há sender_matches_intended para verificar.

accept_sender: para confirm_phone, adicione 'on_mismatch' => 'accept_sender'. Se auth=1 e sender_matches_intended for false, o número certificado difere do solicitado - aceite-o como número corrigido ou solicite um novo OTP para o número que você realmente precisa.

Tratamento de erros

A API retorna "status": "error" com uma message legível:

HTTPmessageQuando
400Missing required parametersVocê esqueceu um campo obrigatório
400A phone is required in confirm_phone modeconfirm_phone solicitado sem um telefone
400Invalid mode / Invalid on_mismatchValor de enum desconhecido
400The phone number is invalid or not a mobile number.Formato de telefone inválido
403Unknown or invalid business IDbusinessid incorreto
403Invalid HMACA assinatura não corresponde - verifique sua string de assinatura
409This request was already used.businessref+in_ts duplicado

Segurança

🔐 HMAC-signedCada solicitação e resposta é verificada com sua businesskey
📱 Correspondência de telefone conforme o modoconfirm_phone verifica se o remetente corresponde ao número solicitado; verify_sender / accept_sender certificam apenas o remetente real - nunca um número que não enviou nada
🎯 Códigos ativos exclusivosDois códigos pendentes nunca compartilham o mesmo valor, então um código recebido é mapeado de forma determinística para uma única solicitação
🔂 Single-useOs códigos passam por 0→1→2, nunca reutilizáveis
⏱ Time-limitedOs códigos expiram após 10 minutos, máximo de 4 tentativas de entrega
🔒 Sem segredos do lado do clienteSua businesskey fica no seu servidor; nunca no código do navegador
🛡 Criptografado com AES-256Os números de telefone nas respostas são criptografados com sua businesskey

Experimente ao vivo

🎮 Fluxo de login da demonstração - uma demonstração funcional que mostra a experiência completa do usuário.

🧪 Ferramenta de teste de API - requer seu próprio businessid e businesskey de wappsync.com/mybusiness.