Pas avec un template OTP natif aujourd'hui : l'API ne sait ni le créer ni y glisser le code. Ce qui marche : un code en texte libre dans les 24 h après que le client vous a écrit, ou mieux un lien unique. Vous générez et vérifiez le code vous-même.
Astuce
Pas avec un template OTP natif aujourd'hui : l'API ne sait ni le créer ni y glisser le code. Ce qui marche : un code en texte libre dans les 24 h après que le client vous a écrit, ou mieux un lien unique. Vous générez et vérifiez le code vous-même.
Vous voulez vérifier le numéro d'un utilisateur ou le connecter : vous lui envoyez un code à 6 chiffres, il le saisit chez vous.
Réponse honnête : le template OTP natif de WhatsApp (catégorie AUTHENTICATION, bouton « Copier le code ») n'est pas utilisable de bout en bout avec cette API aujourd'hui. Voici ce que le code fait, et ce qui marche à la place.
Conclusion : ne comptez pas sur POST /v1/messages pour un OTP natif. Ne contournez pas en déguisant un code en template d'une autre catégorie : le code ne l'empêche pas, mais Meta peut refuser ou requalifier le template, et rien ici ne garantit qu'il passe.
L'API est un relais : le code, sa durée de vie et sa vérification restent chez vous.
Client : Connexion
Webhook : message.inbound from=+237690000001 text="Connexion"
Serveur : code 482913 créé, valable 10 min, 3 essais, lié au numéro
Vous : « Votre code Boutique Exemple : 482913. Valable 10 minutes. Ne le partagez jamais. »
Client : (saisit 482913 sur votre site ou le renvoie dans la conversation)
curl
curl -X POST "https://wa-api.geskap.com/v1/messages/reply" \
-H "Authorization: Bearer $GESKAP_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": "+237690000001",
"text": "Votre code Boutique Exemple : 482913. Valable 10 minutes. Ne le partagez jamais."
}'
Node.js
const res = await fetch("https://wa-api.geskap.com/v1/messages/reply", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.GESKAP_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"to": "+237690000001",
"text": "Votre code Boutique Exemple : 482913. Valable 10 minutes. Ne le partagez jamais."
}),
});
console.log(res.status, await res.json());
PHP
$ch = curl_init("https://wa-api.geskap.com/v1/messages/reply");
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("GESKAP_API_KEY"),
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode([
"to" => "+237690000001",
"text" => "Votre code Boutique Exemple : 482913. Valable 10 minutes. Ne le partagez jamais.",
]),
]);
$res = curl_exec($ch);
echo curl_getinfo($ch, CURLINFO_HTTP_CODE), " ", $res;
Python
import os, requests
res = requests.request(
"POST",
"https://wa-api.geskap.com/v1/messages/reply",
headers={"Authorization": f"Bearer {os.environ['GESKAP_API_KEY']}"},
json={
"to": "+237690000001",
"text": "Votre code Boutique Exemple : 482913. Valable 10 minutes. Ne le partagez jamais.",
},
timeout=15,
)
print(res.status_code, res.json())
Node.js
// Your server — generate, store hashed, verify. Nothing of this runs on our side.
import crypto from "node:crypto";
const sha = (s) => crypto.createHash("sha256").update(s).digest("hex");
export function issueCode(phone) {
const code = String(crypto.randomInt(0, 1_000_000)).padStart(6, "0");
db.otp.upsert(phone, { hash: sha(code), expiresAt: Date.now() + 10 * 60_000, triesLeft: 3 });
return code; // then POST /v1/messages/reply with this code
}
export function checkCode(phone, code) {
const row = db.otp.get(phone);
if (!row || row.expiresAt < Date.now() || row.triesLeft <= 0) return false;
row.triesLeft -= 1;
const ok = sha(code) === row.hash;
if (ok) db.otp.delete(phone); // single use
return ok;
}
Attention
Piège : un code en clair dans la conversation reste lisible dans l'historique du téléphone. Pour une action sensible (solde, paiement), préférez un lien unique et un PIN saisi sur votre page : le secret ne passe pas par WhatsApp.
Attention
Piège : associez toujours le code au numéro from qui l'a demandé et vérifiez les deux. Voir Reconnaître un client à son numéro. Limitez les essais et la durée (10 minutes, 3 essais ici).
Attention
Piège : POST /v1/messages/reply n'a pas d'idempotency_key (un champ en trop est ignoré sans erreur) : un rejeu réseau enverrait deux codes. Dédoublonnez de votre côté, par exemple sur le wa_message_id du message entrant qui a déclenché l'envoi (voir Idempotence).
Si votre besoin est l'OTP natif (bouton « Copier le code », hors 24 h), écrivez au support Geskap au +237 6 56 09 88 31 avec votre cas : il n'est pas disponible en libre-service. Voir aussi Limites, honnêtement.
Preuve — vérifié dans le code de l'API : api_quota.py, templates.py, api_schemas.py, cloud_api.py, api_send.py, WHATSAPP_DEV_API.md.