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é.
Sommaire
Comment ça fonctionne
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.
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.
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 :
| Identifiant | Description |
|---|---|
businessid | Votre ID d'entreprise numérique |
businesskey | Votre clé secrète - ne la partagez jamais, ne la mettez jamais dans du code côté client |
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 envoyez | un numéro de téléphone N | rien (aucun numéro) |
| Ce qui est certifié | que l'appelant contrôle N spécifiquement | le numéro qui renvoie réellement le code |
| Utilisation typique | connexion / récupération sur un numéro enregistré, protection contre le changement de SIM | nouvelle inscription - « donne-moi un téléphone réel et prouvé pour ce client » |
| Livraison du code | Envoyé 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'interrogation | sender_matches_intended vous indique si l'expéditeur est N | phoneEnc est le numéro certifié ; sender_matches_intended est omis |
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)
| Champ | Type | Description |
|---|---|---|
businessid | int | Votre ID d'entreprise |
businessref | string | Une référence unique que vous générez pour cette demande d'authentification (ex. : bin2hex(random_bytes(4))) |
phone | string | Le 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. |
mode | string | Facultatif - 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_mismatch | string | Facultatif (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) |
ts | int | Horodatage Unix actuel |
hmac | string | Signature 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
| Champ | Type | Description |
|---|---|---|
status | string | "ok" or "error" |
reverseotp_display | string | Le code que votre utilisateur envoie, ex. : "2FA-828161" |
waphone | string | Le numéro WhatsApp VERS lequel votre utilisateur envoie le code |
logincode | string | Code interne à utiliser lors de l'interrogation |
in_ts | int | Horodatage pour la requête d'interrogation |
out_ts | int | Horodatage de la réponse |
otp_valid_minutes | int | Durée de validité du code (par défaut 10) |
mode | string | Le mode actif : confirm_phone ou verify_sender |
delivery | string | pushed_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) |
hmac | string | HMAC 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)
| Champ | Type | Description |
|---|---|---|
businessid | int | Votre ID d'entreprise |
businessref | string | La même référence que lors de l'appel précédent |
logincode | string | Le logincode de la réponse getReverseOTP |
in_ts | int | Le ts d'origine de la requête getReverseOTP |
hmac | string | HMAC-SHA256 de {businessid}|{businessref}|{logincode}|{in_ts} |
Réponse
| Champ | Type | Signification |
|---|---|---|
used | 0 | ⏳ Toujours en attente - interrogez à nouveau |
used | 1 | ✅ Tout juste vérifié - la première interrogation qui le voit le consomme |
used | 2 | 🔒 Déjà consommé par une interrogation précédente |
auth | 1 | L'utilisateur est vérifié - connectez-le ! |
phoneEnc | string | Té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) |
tries | int | Les tentatives échouées sont comptées (code erroné ou téléphone erroné) |
expired | bool | true en cas de trop nombreuses tentatives échouées (tentatives ≥ 4) - demandez un nouvel OTP |
mode | string | Le mode de cette requête : confirm_phone ou verify_sender |
sender_matches_intended | bool | confirm_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_ts | int | Horodatage de la réponse |
hmac | string | HMAC - 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 :
| HTTP | message | Quand |
|---|---|---|
| 400 | Missing required parameters | Vous avez oublié un champ obligatoire |
| 400 | A phone is required in confirm_phone mode | confirm_phone demandé sans téléphone |
| 400 | Invalid mode / Invalid on_mismatch | Valeur d'énumération inconnue |
| 400 | The phone number is invalid or not a mobile number. | Format de téléphone incorrect |
| 403 | Unknown or invalid business ID | businessid erroné |
| 403 | Invalid HMAC | La signature ne correspond pas - vérifiez votre chaîne de signature |
| 409 | This request was already used. | businessref+in_ts en double |
Sécurité
| 🔐 HMAC-signed | Chaque requête et réponse est vérifiée avec votre businesskey |
| 📱 Correspondance des téléphones selon le mode | confirm_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 uniques | Deux 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-use | Les codes passent par 0→1→2, jamais réutilisables |
| ⏱ Time-limited | Les codes expirent après 10 minutes, 4 tentatives de livraison maximum |
| 🔒 Aucun secret côté client | Votre businesskey reste sur votre serveur ; jamais dans le code du navigateur |
| 🛡 Chiffré en AES-256 | Les 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.