OTP WhatsApp au Maroc : intégrez l’authentification en 30 minutes

L’authentification par SMS, c’est fini. Au Maroc, les SMS OTP coûtent cher (0,50-1,20 MAD par message), arrivent avec des délais aléatoires (quand ils arrivent), et offrent une expérience utilisateur médiocre.

WhatsApp OTP offre 98% de délivrabilité, un coût 60-80% inférieur au SMS, et une expérience fluide pour vos utilisateurs. Et l’intégration prend 30 minutes.

Ce guide développeur vous donne le code prêt à l’emploi en Node.js, PHP et Python.


1. Pourquoi remplacer le SMS OTP par WhatsApp OTP ?

CritèreSMS OTPWhatsApp OTP
Coût par message (Maroc)0,50 - 1,20 MAD~0,20 MAD
Délivrabilité72-78%98%
Délai de réception5-30 secondes (parfois > 60s)< 3 secondes
Expérience utilisateurCode dans un SMS brutMessage formaté, branding entreprise
InternationalRoaming, filtrage opérateurFonctionne partout où WhatsApp est installé
SécuritéInterception SIM possibleChiffrement de bout en bout

Pour 10 000 OTP/mois :

  • SMS : 5 000 - 12 000 MAD/mois → 60 000 - 144 000 MAD/an
  • WhatsApp : ~2 000 MAD/mois → ~24 000 MAD/an
  • Économie annuelle : 36 000 à 120 000 MAD

2. Prérequis

Avant de coder, assurez-vous d’avoir :

  1. Un compte Wasel avec un numéro WhatsApp Business connecté à l’API
  2. Un template OTP approuvé par Meta — Wasel vous aide à le soumettre et le faire approuver (délai : 24-48h)
  3. Votre clé API Wasel — disponible dans votre dashboard
  4. Un endpoint sur votre serveur pour recevoir la vérification du code (webhook)

3. Intégration Node.js

const axios = require('axios');
const WASEL_API_KEY = 'votre_cle_api_wasel';
const WASEL_API_URL = 'https://api.wasel.ma/v1';
async function sendWhatsAppOTP(phoneNumber, otpCode) {
try {
const response = await axios.post(
`${WASEL_API_URL}/messages/authentication`,
{
to: phoneNumber, // Format: "212612345678"
template_name: "otp_verification",
template_language: "fr",
components: [
{
type: "body",
parameters: [
{ type: "text", text: otpCode }
]
},
{
type: "button",
sub_type: "url",
index: "0",
parameters: [
{ type: "text", text: otpCode }
]
}
]
},
{
headers: {
'Authorization': `Bearer ${WASEL_API_KEY}`,
'Content-Type': 'application/json'
}
}
);
console.log('OTP envoyé avec succès:', response.data.message_id);
return response.data.message_id;
} catch (error) {
console.error('Erreur envoi OTP:', error.response?.data || error.message);
throw error;
}
}
// Génération d'un code OTP à 6 chiffres
function generateOTP() {
return Math.floor(100000 + Math.random() * 900000).toString();
}
// Exemple d'utilisation
const phone = "212612345678";
const otp = generateOTP();
sendWhatsAppOTP(phone, otp)
.then(messageId => {
// Stocker l'OTP avec le messageId pour vérification ultérieure
console.log(`OTP ${otp} envoyé au ${phone}, message_id: ${messageId}`);
})
.catch(err => console.error("Échec de l'envoi:", err));

Configuration du template OTP dans Meta

Votre template doit ressembler à :

Bonjour,
Votre code de vérification est : {{1}}
Ce code expire dans 5 minutes. Ne le partagez avec personne.
[Bouton: Copier le code] → {{1}}

4. Intégration PHP

<?php
class WaselOTP {
private $apiKey;
private $apiUrl = 'https://api.wasel.ma/v1';
public function __construct($apiKey) {
$this->apiKey = $apiKey;
}
public function sendOTP($phoneNumber, $otpCode) {
$payload = [
'to' => $phoneNumber,
'template_name' => 'otp_verification',
'template_language' => 'fr',
'components' => [
[
'type' => 'body',
'parameters' => [
['type' => 'text', 'text' => $otpCode]
]
],
[
'type' => 'button',
'sub_type' => 'url',
'index' => '0',
'parameters' => [
['type' => 'text', 'text' => $otpCode]
]
]
]
];
$ch = curl_init($this->apiUrl . '/messages/authentication');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $this->apiKey,
'Content-Type: application/json'
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 200) {
throw new Exception('Erreur API Wasel: ' . $response);
}
$data = json_decode($response, true);
return $data['message_id'];
}
public function verifyOTP($phoneNumber, $otpCode, $messageId) {
$payload = [
'to' => $phoneNumber,
'code' => $otpCode,
'message_id' => $messageId
];
$ch = curl_init($this->apiUrl . '/messages/authentication/verify');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $this->apiKey,
'Content-Type: application/json'
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return $httpCode === 200;
}
}
// Utilisation
$wasel = new WaselOTP('votre_cle_api_wasel');
$otp = str_pad(random_int(0, 999999), 6, '0', STR_PAD_LEFT);
try {
$messageId = $wasel->sendOTP('212612345678', $otp);
$_SESSION['wasel_otp'] = $otp;
$_SESSION['wasel_message_id'] = $messageId;
echo json_encode(['success' => true, 'message' => 'OTP envoyé']);
} catch (Exception $e) {
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
}
?>

5. Intégration Python

import requests
import random
import string
class WaselOTP:
def __init__(self, api_key: str):
self.api_key = api_key
self.api_url = "https://api.wasel.ma/v1"
self.headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
def send_otp(self, phone_number: str, otp_code: str) -> str:
payload = {
"to": phone_number,
"template_name": "otp_verification",
"template_language": "fr",
"components": [
{
"type": "body",
"parameters": [
{"type": "text", "text": otp_code}
]
},
{
"type": "button",
"sub_type": "url",
"index": "0",
"parameters": [
{"type": "text", "text": otp_code}
]
}
]
}
response = requests.post(
f"{self.api_url}/messages/authentication",
json=payload,
headers=self.headers,
timeout=10
)
if response.status_code != 200:
raise Exception(f"API Error: {response.text}")
data = response.json()
return data["message_id"]
def verify_otp(self, phone_number: str, otp_code: str, message_id: str) -> bool:
payload = {
"to": phone_number,
"code": otp_code,
"message_id": message_id
}
response = requests.post(
f"{self.api_url}/messages/authentication/verify",
json=payload,
headers=self.headers,
timeout=10
)
return response.status_code == 200
@staticmethod
def generate_otp(length: int = 6) -> str:
return ''.join(random.choices(string.digits, k=length))
# Utilisation
wasel = WaselOTP("votre_cle_api_wasel")
phone = "212612345678"
otp = WaselOTP.generate_otp()
try:
message_id = wasel.send_otp(phone, otp)
print(f"OTP {otp} envoyé au {phone}, message_id: {message_id}")
except Exception as e:
print(f"Erreur: {e}")

6. Gestion des erreurs courantes

Code HTTPErreurCause probableSolution
400Bad RequestFormat du numéro invalideUtilisez le format international sans ”+” : “212612345678”
401UnauthorizedClé API invalide ou expiréeVérifiez votre clé dans le dashboard Wasel
403ForbiddenTemplate non approuvéVérifiez le statut du template dans Meta Business Manager
429Rate LimitTrop de requêtesRespectez la limite de 80 requêtes/seconde
500Server ErrorErreur côté Wasel/MetaRéessayez avec un backoff exponentiel
// Retry avec backoff exponentiel en Node.js
async function sendOTPWithRetry(phone, otp, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await sendWhatsAppOTP(phone, otp);
} catch (error) {
if (i === maxRetries - 1) throw error;
const delay = Math.pow(2, i) * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}

7. Vérification du code OTP — flux complet

1. Utilisateur saisit son numéro → POST /api/auth/request-otp
2. Serveur génère un OTP 6 chiffres
3. Serveur appelle Wasel API → OTP envoyé sur WhatsApp
4. Utilisateur reçoit le code → le saisit dans votre app
5. Votre app envoie le code + message_id au serveur → POST /api/auth/verify-otp
6. Serveur vérifie via Wasel API → retourne succès/échec
7. Si succès → génération JWT/session token

Passez à l’OTP WhatsApp en 30 minutes

Documentation API complète, SDKs, exemples de code et support développeur. Intégrez l’authentification WhatsApp la plus fiable et la moins chère du marché.

Voir la documentation API →