WappSync
A

WappSync Phone Verify - Documentation de l'API

Vérification téléphonique où votre utilisateur envoie un code vers nous via WhatsApp - aucune saisie d'OTP, un seul tap, entièrement vérifié.

Comment ça fonctionne

1

Vous demandez un code

Votre backend appelle notre API avec le numéro de téléphone de l'utilisateur. Nous renvoyons un code unique et le numéro WhatsApp vers lequel l'envoyer.

2

L'utilisateur l'envoie via WhatsApp

Votre utilisateur touche un lien WhatsApp - le code est pré-rempli. Aucune saisie, aucun copier-coller. Il n'a qu'à appuyer sur envoyer.

3

Vérifié instantanément

Nous recevons le message, voyons depuis quel numéro WhatsApp il a été envoyé et votre interrogation renvoie auth=1 avec le téléphone certifié. Terminé !

Obtenez vos identifiants

Inscrivez-vous sur wappsync.com/mybusiness pour recevoir :

IdentifiantDescription
businessidVotre ID d'entreprise numérique
businesskeyVotre clé secrète - ne la partagez jamais, ne la mettez jamais dans du code côté client
Important : Tous les appels d'API doivent provenir de votre backend. La businesskey sert à la signature HMAC et ne doit jamais apparaître dans le JavaScript du navigateur, le code source HTML ou le code de l'application mobile.

Deux modes de vérification

Phone Verify fonctionne selon deux modes, choisis à chaque requête. Dans les deux, votre utilisateur envoie le code vers nous via WhatsApp - la seule différence est quel numéro de téléphone est certifié.

confirm_phone (default)verify_sender
Vous envoyezun numéro de téléphone Nrien (aucun numéro)
Ce qui est certifiéque l'appelant contrôle N spécifiquementle numéro qui renvoie réellement le code
Utilisation typiqueconnexion / récupération sur un numéro enregistré, protection contre le changement de SIMnouvelle inscription - « donne-moi un téléphone réel et prouvé pour ce client »
Livraison du codeEnvoyé via WhatsApp vers N et affiché dans votre interface (delivery: pushed_to_phone)uniquement via vous (delivery: relay_by_business) - vous remettez le code à votre client
Résultat de l'interrogationsender_matches_intended vous indique si l'expéditeur est NphoneEnc est le numéro certifié ; sender_matches_intended est omis
Sécurité : confirm_phone prouve le contrôle d'un numéro déclaré précis ; verify_sender prouve le contrôle d'un numéro et indique lequel. Si votre flux exige que « le numéro de ce compte appartienne réellement à l'utilisateur », restez en confirm_phone avec on_mismatch: reject.

Téléphone corrigé (on_mismatch) : un cas fréquent est que le client déclare A mais envoie le code depuis B (faute de frappe / double SIM). En confirm_phone, reject (par défaut) le traite comme une tentative échouée ; accept_sender certifie à la place l'expéditeur réel B (sender_matches_intended: false, phoneEnc = B), et votre backend décide d'accepter le numéro corrigé B ou de demander un nouvel OTP pour A.

Demander un OTP inversé

Appelez ceci depuis votre backend lorsque vous devez vérifier un utilisateur :

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

Corps de la requête (JSON)

ChampTypeDescription
businessidintVotre ID d'entreprise
businessrefstringUne référence unique que vous générez pour cette demande d'authentification (ex. : bin2hex(random_bytes(4)))
phonestringLe numéro de téléphone de l'utilisateur au format international (+40755123456). Obligatoire en mode confirm_phone ; à omettre ou laisser vide pour verify_sender.
modestringFacultatif - confirm_phone (par défaut lorsqu'un téléphone est fourni) ou verify_sender (par défaut lorsque le téléphone est omis)
on_mismatchstringFacultatif (confirm_phone uniquement) - reject (par défaut) ou accept_sender (certifie l'expéditeur réel si le code arrive d'un autre numéro)
tsintHorodatage Unix actuel
hmacstringSignature HMAC-SHA256

Signature HMAC

Signez cette chaîne avec votre businesskey :

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

En mode verify_sender, il n'y a pas de téléphone, la chaîne signée est donc {businessid}|{businessref}||{ts} (emplacement central vide).

Exemple :

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

Réponse

ChampTypeDescription
statusstring"ok" or "error"
reverseotp_displaystringLe code que votre utilisateur envoie, ex. : "2FA-828161"
waphonestringLe numéro WhatsApp VERS lequel votre utilisateur envoie le code
logincodestringCode interne à utiliser lors de l'interrogation
in_tsintHorodatage pour la requête d'interrogation
out_tsintHorodatage de la réponse
otp_valid_minutesintDurée de validité du code (par défaut 10)
modestringLe mode actif : confirm_phone ou verify_sender
deliverystringpushed_to_phone (confirm_phone : le code est aussi envoyé via WhatsApp au téléphone déclaré) ou relay_by_business (verify_sender : vous devez transmettre le code à votre client vous-même)
hmacstringHMAC de la réponse - vérifiez avec votre businesskey

Vérifier le HMAC de la réponse against {businessid}|{businessref}|{logincode}|{reverseotp_display}|{waphone}|{out_ts}.

Quoi montrer à votre utilisateur

Affichez le code et le numéro de téléphone. Utilisez un lien whatsapp://send pour que l'utilisateur puisse l'envoyer en un seul tap :

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

Interroger la vérification

Interroger toutes les 2-3 secondes jusqu'à ce que l'utilisateur soit vérifié :

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

Corps de la requête (JSON)

ChampTypeDescription
businessidintVotre ID d'entreprise
businessrefstringLa même référence que lors de l'appel précédent
logincodestringLe logincode de la réponse getReverseOTP
in_tsintLe ts d'origine de la requête getReverseOTP
hmacstringHMAC-SHA256 de {businessid}|{businessref}|{logincode}|{in_ts}

Réponse

ChampTypeSignification
used0⏳ Toujours en attente - interrogez à nouveau
used1✅ Tout juste vérifié - la première interrogation qui le voit le consomme
used2🔒 Déjà consommé par une interrogation précédente
auth1L'utilisateur est vérifié - connectez-le !
phoneEncstringTéléphone certifié chiffré en AES-256-CBC (uniquement lorsque auth=1) - l'expéditeur lorsqu'un code a été reçu (identique à votre numéro déclaré en confirm_phone strict)
triesintLes tentatives échouées sont comptées (code erroné ou téléphone erroné)
expiredbooltrue en cas de trop nombreuses tentatives échouées (tentatives ≥ 4) - demandez un nouvel OTP
modestringLe mode de cette requête : confirm_phone ou verify_sender
sender_matches_intendedboolconfirm_phone uniquement, une fois un code reçu - true = l'expéditeur est le numéro que vous avez demandé à vérifier ; false = un expéditeur corrigé a été certifié. Omis en verify_sender.
out_tsintHorodatage de la réponse
hmacstringHMAC - vérifiez avec {businessid}|{businessref}|{logincode}|{used}|{phoneEnc}|{out_ts}

Lorsque auth === 1, un code valide a été reçu. Déchiffrez phoneEnc pour obtenir le téléphone certifié (vérifiez sender_matches_intended en mode confirm_phone), puis connectez l'utilisateur.

Déchiffrer le numéro de téléphone

Lorsque auth=1, phoneEnc contient le téléphone certifié (l'expéditeur qui s'est prouvé) chiffré en AES-256-CBC avec votre 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

Exemple frontend

La seule interface dont vous avez besoin - affichez-la après que votre backend a appelé 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>

Exemple PHP complet

Prêt à copier-coller. Remplacez YOUR_BUSINESS_ID et 'your-secret-key' par les valeurs 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 : envoyez phone => '' (et éventuellement mode => 'verify_sender') - aucun envoi WhatsApp n'a lieu, vous devez donc transmettre vous-même le reverseotp_display à votre client. Avec auth=1, phoneEnc se déchiffre en le numéro certifié de l'expéditeur ; il n'y a aucun sender_matches_intended à vérifier.

accept_sender : pour confirm_phone, ajoutez 'on_mismatch' => 'accept_sender'. Si auth=1 et que sender_matches_intended vaut false, le numéro certifié diffère de celui demandé - acceptez-le comme numéro corrigé ou demandez un nouvel OTP pour le numéro dont vous avez réellement besoin.

Gestion des erreurs

L'API renvoie "status": "error" avec un message lisible :

HTTPmessageQuand
400Missing required parametersVous avez oublié un champ obligatoire
400A phone is required in confirm_phone modeconfirm_phone demandé sans téléphone
400Invalid mode / Invalid on_mismatchValeur d'énumération inconnue
400The phone number is invalid or not a mobile number.Format de téléphone incorrect
403Unknown or invalid business IDbusinessid erroné
403Invalid HMACLa signature ne correspond pas - vérifiez votre chaîne de signature
409This request was already used.businessref+in_ts en double

Sécurité

🔐 HMAC-signedChaque requête et réponse est vérifiée avec votre businesskey
📱 Correspondance des téléphones selon le modeconfirm_phone vérifie que l'expéditeur correspond au numéro demandé ; verify_sender / accept_sender ne certifient que l'expéditeur réel - jamais un numéro qui n'a rien envoyé
🎯 Codes actifs uniquesDeux codes en attente ne partagent jamais la même valeur, un code entrant est donc associé de façon déterministe à une seule requête
🔂 Single-useLes codes passent par 0→1→2, jamais réutilisables
⏱ Time-limitedLes codes expirent après 10 minutes, 4 tentatives de livraison maximum
🔒 Aucun secret côté clientVotre businesskey reste sur votre serveur ; jamais dans le code du navigateur
🛡 Chiffré en AES-256Les numéros de téléphone dans les réponses sont chiffrés avec votre businesskey

Essayez en direct

🎮 Flux de connexion de la démo - une démo fonctionnelle qui montre l'expérience utilisateur complète.

🧪 Outil de test d'API - nécessite votre propre businessid et businesskey depuis wappsync.com/mybusiness.