Oui : reçu instantané après une collecte terrain (PDF possible), échéance de remboursement, solde derrière lien + PIN et code de vérification, avec l'API.
Astuce
Oui : reçu instantané après une collecte terrain (PDF possible), échéance de remboursement, solde derrière lien + PIN et code de vérification, avec l'API.
| Besoin | Comment | Recette |
|---|---|---|
| Reçu après une collecte terrain | Dans les 24 h : texte libre. Sinon : template recu_collecte avec le reçu en PDF en en-tête. | PDF en en-tête · Répondre en texte libre |
| Échéance de remboursement | Template echeance_remboursement quelques jours avant la date ; relance en cas de retard avec un autre template. | Relance d'impayé · Boutons de template |
| Solde et opérations | Le client le demande donc il est dans les 24 h : message avec lien personnel + code PIN. Le solde n'est jamais écrit dans WhatsApp. | Données sensibles : lien et PIN · Reconnaître le client par son numéro |
| Ouverture de compte accueillie | Template compte_ouvert avec le nom de l'agent collecteur. | Écrire le premier message |
| Code de vérification (OTP) | En texte libre dans les 24 h, ou par lien unique ; le template OTP natif n'est pas encore utilisable par l'API. | Code OTP |
Hors des 24 h qui suivent le dernier message du client, seul un template approuvé par Meta peut partir. Dans les 24 h, vous composez librement : boutons (3 de 20 caractères au plus), liste (10 lignes de 24 caractères au plus) ou texte libre.
| Nom | Catégorie | Texte | Boutons |
|---|---|---|---|
| recu_collecte | UTILITY | Bonjour {{1}}, nous avons bien reçu votre versement de {{2}} le {{3}} (référence {{4}}). Votre reçu est joint à ce message en PDF. Merci de votre confiance. | en-tête PDF |
| echeance_remboursement | UTILITY | Bonjour {{1}}, votre échéance de {{2}} est prévue le {{3}}. Vous pouvez régler auprès de votre agent collecteur ou en agence. Si vous avez déjà payé, merci d'ignorer ce message. | réponse rapide : « Parler à un conseiller » |
| compte_ouvert | UTILITY | Bonjour {{1}}, votre compte n° {{2}} est ouvert chez Microfinance Exemple. Votre agent collecteur est {{3}}. Votre code PIN vous est remis par l'agent, jamais par message. | — |
Reçu de collecte, avec le PDF du reçu en en-tête. Création, une seule fois : le PDF d'exemple est envoyé en base64 avec son type MIME.
curl
curl -X POST "https://wa-api.geskap.com/v1/templates" \
-H "Authorization: Bearer $GESKAP_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "recu_collecte",
"language": "fr",
"category": "UTILITY",
"body_text": "Bonjour {{1}}, nous avons bien reçu votre versement de {{2}} le {{3}} (référence {{4}}). Votre reçu est joint à ce message en PDF. Merci de votre confiance.",
"example_values": ["Awa", "5 000 F", "30 octobre", "COL-2087"],
"header_image_mime": "application/pdf",
"header_image_base64": "JVBERi0xLjQK…"
}'
Node.js
const res = await fetch("https://wa-api.geskap.com/v1/templates", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.GESKAP_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"name": "recu_collecte",
"language": "fr",
"category": "UTILITY",
"body_text": "Bonjour {{1}}, nous avons bien reçu votre versement de {{2}} le {{3}} (référence {{4}}). Votre reçu est joint à ce message en PDF. Merci de votre confiance.",
"example_values": ["Awa", "5 000 F", "30 octobre", "COL-2087"],
"header_image_mime": "application/pdf",
"header_image_base64": "JVBERi0xLjQK…"
}),
});
console.log(res.status, await res.json());
PHP
$ch = curl_init("https://wa-api.geskap.com/v1/templates");
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([
"name" => "recu_collecte",
"language" => "fr",
"category" => "UTILITY",
"body_text" => "Bonjour {{1}}, nous avons bien reçu votre versement de {{2}} le {{3}} (référence {{4}}). Votre reçu est joint à ce message en PDF. Merci de votre confiance.",
"example_values" => ["Awa", "5 000 F", "30 octobre", "COL-2087"],
"header_image_mime" => "application/pdf",
"header_image_base64" => "JVBERi0xLjQK…",
]),
]);
$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/templates",
headers={"Authorization": f"Bearer {os.environ['GESKAP_API_KEY']}"},
json={
"name": "recu_collecte",
"language": "fr",
"category": "UTILITY",
"body_text": "Bonjour {{1}}, nous avons bien reçu votre versement de {{2}} le {{3}} (référence {{4}}). Votre reçu est joint à ce message en PDF. Merci de votre confiance.",
"example_values": ["Awa", "5 000 F", "30 octobre", "COL-2087"],
"header_image_mime": "application/pdf",
"header_image_base64": "JVBERi0xLjQK…",
},
timeout=15,
)
print(res.status_code, res.json())
Envoi juste après chaque versement. header_document_url est l'adresse publique du PDF du jour, header_document_filename le nom affiché dans la bulle.
curl
curl -X POST "https://wa-api.geskap.com/v1/messages" \
-H "Authorization: Bearer $GESKAP_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": "+237690000016",
"template": {
"name": "recu_collecte",
"language": "fr",
"variables": ["Awa", "5 000 F", "30 octobre", "COL-2087"],
"header_document_url": "https://exemple-microfinance.test/recus/COL-2087.pdf",
"header_document_filename": "recu-COL-2087.pdf"
}
}'
Node.js
const res = await fetch("https://wa-api.geskap.com/v1/messages", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.GESKAP_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"to": "+237690000016",
"template": {
"name": "recu_collecte",
"language": "fr",
"variables": ["Awa", "5 000 F", "30 octobre", "COL-2087"],
"header_document_url": "https://exemple-microfinance.test/recus/COL-2087.pdf",
"header_document_filename": "recu-COL-2087.pdf"
}
}),
});
console.log(res.status, await res.json());
PHP
$ch = curl_init("https://wa-api.geskap.com/v1/messages");
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" => "+237690000016",
"template" => [
"name" => "recu_collecte",
"language" => "fr",
"variables" => ["Awa", "5 000 F", "30 octobre", "COL-2087"],
"header_document_url" => "https://exemple-microfinance.test/recus/COL-2087.pdf",
"header_document_filename" => "recu-COL-2087.pdf",
],
]),
]);
$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",
headers={"Authorization": f"Bearer {os.environ['GESKAP_API_KEY']}"},
json={
"to": "+237690000016",
"template": {
"name": "recu_collecte",
"language": "fr",
"variables": ["Awa", "5 000 F", "30 octobre", "COL-2087"],
"header_document_url": "https://exemple-microfinance.test/recus/COL-2087.pdf",
"header_document_filename": "recu-COL-2087.pdf",
},
},
timeout=15,
)
print(res.status_code, res.json())
Client : Bonjour, quel est mon solde ?
Banque : Pour votre sécurité, confirmez votre identité avec votre code PIN.
Le lien est personnel et expire dans 10 minutes. Nous ne vous demanderons jamais votre PIN ici.
https://exemple-microfinance.test/connexion/ab12cd
Client : (ouvre le lien, saisit son PIN sur la page : le solde s'affiche là-bas)
Client : Merci
Banque : Avec plaisir, Awa. [ Mes opérations ] [ Menu ]
Webhook : message.inbound type=text text="Mes opérations" button_id="operations" (quand il touche un bouton)
Le principe est détaillé dans Données sensibles : lien et PIN ; le numéro identifie le client grâce à Reconnaître le client par son numéro.
Attention
Piège : Un solde, un numéro de compte complet ou un historique d'opérations ne s'écrivent jamais dans WhatsApp : lien personnel + code PIN saisi sur votre page, jamais dans la conversation. Si vous montrez un numéro de compte, masquez-le (••••4821).
Attention
Piège : n'envoyez pas de code de vérification dans un template UTILITY : Meta le requalifie ou le refuse. Voir Code OTP pour ce qui marche.
Preuve — vérifié dans le code de l'API : api_schemas.py ; appliqué par la démo WhatsApp : banque, engine.