Introduction
Avec l’API KoraFlow, votre application peut :
- envoyer des notifications WhatsApp : confirmation de commande, facture PDF, rappel de rendez-vous, code de vérification (OTP), avis d’expédition… ;
- répondre à vos clients depuis votre propre logiciel ou chatbot ;
- savoir si un message a été livré, lu ou a échoué ;
- recevoir par webhook chaque message entrant et chaque changement de statut ;
- synchroniser vos contacts avec KoraFlow.
Les messages partent du numéro WhatsApp Business connecté au compte KoraFlow (API Cloud officielle de Meta). Ils apparaissent dans la Boîte de réception KoraFlow : vos équipes voient tout ce que votre application envoie.
| Élément | Valeur |
|---|---|
| URL de base | https://api.kora-flow.com/api/v1 |
| Format | JSON (UTF-8) en entrée et en sortie — en-tête Content-Type: application/json |
| Authentification | Clé API dans l’en-tête Authorization: Bearer kfk_… |
| Protocole | HTTPS uniquement |
| Dates | ISO 8601 en UTC (ex. 2026-10-03T14:05:12.000Z) |
| Numéros de téléphone | Format international, indicatif pays inclus, sans + ni 00 (ex. 237699112233). Espaces, tirets et + sont tolérés et nettoyés. |
Démarrage rapide
- Créez un compte KoraFlow et connectez votre numéro WhatsApp Business (Réglages → WhatsApp).
- Dans Réglages → Intégrations, cliquez sur Créer la clé. Copiez-la immédiatement : elle ne sera plus jamais affichée.
- Vérifiez la clé :
curl https://api.kora-flow.com/api/v1/me \
-H "Authorization: Bearer kfk_VOTRE_CLE"Réponse :
{
"tenant": { "id": "4f6c…", "name": "Boutique Awa", "isActive": true },
"scopes": ["messages.send", "messages.read", "templates.read", "contacts.read"],
"plan": "Pro (Croissance)",
"rateLimitPerMinute": 120
}- Envoyez votre premier message. Pour un test, écrivez d’abord au numéro de l’entreprise depuis votre téléphone (cela ouvre la fenêtre de 24 h, voir plus bas), puis :
curl -X POST https://api.kora-flow.com/api/v1/messages \
-H "Authorization: Bearer kfk_VOTRE_CLE" \
-H "Content-Type: application/json" \
-d '{"to": "237699112233", "text": "Bonjour ! Ceci est un test KoraFlow 🎉"}'Le message apparaît sur le téléphone et dans la Boîte de réception KoraFlow. Suivez ensuite sa livraison avec GET /messages/{id} ou un webhook.
Authentification
Chaque requête doit contenir votre clé API dans l’en-tête Authorization :
Authorization: Bearer kfk_VOTRE_CLELes clés commencent par kfk_. KoraFlow ne stocke qu’une empreinte (hachage) de la clé : si vous la perdez, révoquez-la et créez-en une nouvelle. Seul le propriétaire du compte peut créer ou révoquer des clés.
Scopes (permissions)
Chaque clé ne peut faire que ce que ses scopes autorisent. Donnez à chaque application le strict nécessaire.
| Scope | Autorise |
|---|---|
messages.send | Envoyer des messages (POST /messages) |
messages.read | Lire le statut et l’historique des messages |
templates.read | Lister les modèles WhatsApp |
contacts.read | Lister et rechercher les contacts |
contacts.write | Créer des contacts et leur ajouter des tags |
campaigns.read | Lister les campagnes et leurs compteurs |
assistant.read | Lire les instructions de l’assistant IA de l’entreprise |
assistant.write | Modifier les instructions, le message d’accueil et les consignes par canal |
* | Tous les droits (à éviter en production) |
/me, /usage et /numbers sont accessibles avec n’importe quelle clé valide.
Ne mettez jamais la clé dans un navigateur ou une application mobile
La clé permet d’envoyer des messages au nom de l’entreprise. Appelez l’API uniquement depuis votre serveur(back-end, fonction cloud, outil d’automatisation). Ne la placez jamais dans du JavaScript côté navigateur, dans une application Android/iOS ni dans un dépôt Git. Stockez-la dans une variable d’environnement.
Règles WhatsApp à connaître
KoraFlow utilise l’API Cloud officielle de Meta. Trois règles de Meta déterminent ce que vous pouvez envoyer :
1. La fenêtre de 24 heures
Quand un client vous écrit, une fenêtre de 24 heures s’ouvre. Pendant cette fenêtre, vous pouvez lui envoyer des messages libres : texte, image, document, vidéo, audio. En dehors de cette fenêtre, seul un modèle approuvé peut être envoyé.
Piège fréquent
Un texte libre envoyé hors fenêtre est d’abord accepté (201, statut SENT), puis Meta le refuse quelques secondes plus tard : le statut passe à FAILED avec l’erreur Meta 131047. Pour écrire en premier à un client (notification, OTP, facture), utilisez toujours un modèle.
2. Les modèles (templates)
Un modèle est un message pré-écrit, validé par Meta, avec des variables {{1}}, {{2}}… que vous remplissez à l’envoi. Créez-les dans KoraFlow (menu Modèles) ; la validation par Meta prend de quelques minutes à 24 h. Meta classe les modèles en trois catégories :
| Catégorie | Usage | Exemple |
|---|---|---|
| UTILITY | Suite à une action du client (commande, paiement, rendez-vous) | Votre commande {{1}} de {{2}} est confirmée. |
| AUTHENTICATION | Codes de vérification | Votre code KoraShop est {{1}}. Il expire dans 10 minutes. |
| MARKETING | Promotions, relances, nouveautés | -20 % ce week-end sur toute la boutique ! |
3. Le consentement
N’écrivez qu’à des personnes qui ont accepté d’être contactées sur WhatsApp. Des signalements « spam » font baisser la note de qualité du numéro et peuvent entraîner des restrictions par Meta. La note de chaque numéro est visible via GET /numbers.
Facturation
Chaque message envoyé avec succès via l’API est décompté du quota de messages du forfait KoraFlow, comme un envoi depuis le tableau de bord (les envois échoués ne sont pas comptés). Les éventuels frais de Meta pour les modèles s’appliquent selon la grille tarifaire de Meta du compte WhatsApp Business connecté.
Envoyer un message
/api/v1/messagesscope : messages.sendUn seul point d’entrée pour tous les types de messages. Le type est déduit des champs fournis, ou indiqué avec type.
Paramètres du corps
| Champ | Type | Description | |
|---|---|---|---|
to | string | requis | Numéro du destinataire au format international (ex. 237699112233). Le contact est créé automatiquement s’il n’existe pas. |
type | string | optionnel | text, template, image, document, video ou audio. Par défaut : template si templateName est fourni, document si mediaUrl est fourni, sinon text. |
text | string | optionnel | Texte du message (max. 4 096 caractères). Requis pour type=text. Uniquement dans la fenêtre de 24 h. |
templateName | string | optionnel | Nom exact d’un modèle APPROVED. Requis pour type=template. |
variables | string[] | optionnel | Valeurs des variables du modèle, dans l’ordre : le 1er élément remplace {{1}}, le 2e {{2}}, etc. |
language | string | optionnel | Code langue du modèle (ex. fr, en_US). Si absent, KoraFlow utilise la langue sous laquelle le modèle est enregistré. |
mediaUrl | string | optionnel | URL publique HTTPS du fichier. Requis pour image/document/video/audio. Pour un modèle avec en-tête média (ex. facture PDF), sert d’en-tête au modèle. |
caption | string | optionnel | Légende d’une image, vidéo ou d’un document. |
filename | string | optionnel | Nom de fichier affiché pour un document (ex. Facture-A1234.pdf). |
from | string | optionnel | Numéro expéditeur : id renvoyé par GET /numbers ou numéro au format international. Par défaut : le numéro principal du compte. |
name | string | optionnel | Nom du contact, utilisé seulement s’il est créé par cet envoi. |
En-têtes optionnels
| En-tête | Description |
|---|---|
Idempotency-Key | Identifiant unique de votre côté (ex. commande-A1234-confirmation). Si la même requête est rejouée avec la même clé dans les 24 h, le message n’est pas renvoyé : vous recevez la réponse d’origine. Détails. |
Exemple : texte libre (dans la fenêtre de 24 h)
{
"to": "237699112233",
"text": "Bonjour Awa, votre colis est arrivé à l'agence de Douala. Passez le récupérer avant 18 h."
}Exemple : modèle avec variables (à tout moment)
Modèle confirmation_commande : « Bonjour, votre commande {{1}} d’un montant de {{2}} est confirmée. Livraison prévue le {{3}}. »
curl -X POST https://api.kora-flow.com/api/v1/messages \
-H "Authorization: Bearer kfk_VOTRE_CLE" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: commande-A1234-confirmation" \
-d '{
"to": "237699112233",
"templateName": "confirmation_commande",
"variables": ["A1234", "45 000 FCFA", "lundi 6 octobre"]
}'Exemple : document PDF (facture, reçu, bulletin)
{
"to": "237699112233",
"type": "document",
"mediaUrl": "https://exemple.com/factures/A1234.pdf",
"filename": "Facture-A1234.pdf",
"caption": "Votre facture A1234"
}L’URL doit être publique (accessible sans connexion) au moment de l’envoi. Formats acceptés par WhatsApp : images JPEG/PNG (5 Mo max.), documents PDF, Word, Excel… (100 Mo max.), vidéos MP4 (16 Mo max.), audio MP3/OGG/AAC (16 Mo max.). Hors fenêtre de 24 h, utilisez un modèle à en-tête « Document » et passez le PDF dans mediaUrl avec templateName.
Réponse
{
"ok": true,
"id": "8b1e6c2a-3f0d-4c55-9a8e-2f1b7d9e4a10",
"status": "SENT",
"to": "237699112233",
"metaMessageId": "wamid.HBgMMjM3Njk5MTEyMjMzFQIAERgSM0Q…"
}| Champ | Description |
|---|---|
id | Identifiant KoraFlow du message. Conservez-le pour suivre son statut. |
status | Toujours SENT à ce stade : Meta a accepté le message. La livraison réelle arrive ensuite (voir Suivre un message). |
metaMessageId | Identifiant WhatsApp (wamid…). Utilisable aussi avec GET /messages/{id}. |
Suivre un message
/api/v1/messages/{id}scope : messages.read{id} accepte l’id KoraFlow ou le metaMessageId.
curl https://api.kora-flow.com/api/v1/messages/8b1e6c2a-3f0d-4c55-9a8e-2f1b7d9e4a10 \
-H "Authorization: Bearer kfk_VOTRE_CLE"{
"data": {
"id": "8b1e6c2a-3f0d-4c55-9a8e-2f1b7d9e4a10",
"to": "237699112233",
"direction": "OUTBOUND",
"status": "READ",
"text": "Bonjour, votre commande A1234 d'un montant de 45 000 FCFA est confirmée…",
"template": "confirmation_commande",
"media": null,
"error": null,
"metaMessageId": "wamid.HBgMMjM3Njk5MTEyMjMzFQIAERgSM0Q…",
"createdAt": "2026-10-03T14:05:12.000Z"
}
}Cycle de vie d’un message
| Statut | Signification |
|---|---|
SENT | Accepté par Meta, en route vers le téléphone. |
DELIVERED | Arrivé sur le téléphone du destinataire (deux coches grises). |
READ | Ouvert par le destinataire (deux coches bleues). Absent si le destinataire a désactivé les confirmations de lecture. |
FAILED | Non livré. La raison donnée par Meta est dans error (voir erreurs Meta courantes). |
Plutôt que d’interroger cette route en boucle, abonnez-vous au webhook message.status_updated : vous êtes prévenu à chaque changement.
Historique
/api/v1/messagesscope : messages.read| Paramètre de requête | Description |
|---|---|
phone | Filtrer sur un numéro (conversation complète, messages entrants et sortants). |
limit | Nombre de messages (1 à 200, défaut 50), du plus récent au plus ancien. |
curl "https://api.kora-flow.com/api/v1/messages?phone=237699112233&limit=20" \
-H "Authorization: Bearer kfk_VOTRE_CLE"Réponse : { "data": [ …messages au même format que GET /messages/{id}… ], "count": 20 }. Les messages reçus ont direction: "INBOUND".
Modèles
/api/v1/templatesscope : templates.readListe les modèles approuvés (paramètre status=ALL pour inclure ceux en attente ou refusés). variablesCount indique combien d’éléments mettre dans variables.
{
"data": [
{
"id": "0c9d…",
"name": "confirmation_commande",
"language": "fr",
"category": "UTILITY",
"status": "APPROVED",
"variablesCount": 3,
"components": [
{ "type": "BODY", "text": "Bonjour, votre commande {{1}} d'un montant de {{2}} est confirmée. Livraison prévue le {{3}}." }
]
}
]
}Numéros expéditeurs
/api/v1/numbersSi le compte a plusieurs numéros WhatsApp (ex. une agence par ville), choisissez l’expéditeur avec le champ from de POST /messages.
{
"data": [
{ "id": "a1f2…", "name": "Boutique Douala", "phoneNumber": "237699112233", "isDefault": true, "status": "ACTIVE", "qualityRating": "GREEN" },
{ "id": "b7c3…", "name": "Agence Yaoundé", "phoneNumber": "237677445566", "isDefault": false, "status": "ACTIVE", "qualityRating": "GREEN" }
]
}qualityRating : GREEN (bonne), YELLOW (à surveiller), RED (risque de restriction par Meta).
Contacts
/api/v1/contactsscope : contacts.readParamètres : limit (1–200, défaut 50), phone (recherche par numéro).
/api/v1/contactsscope : contacts.writeCrée le contact (ou met à jour son nom s’il existe déjà) et lui ajoute des tags — pratique pour cibler ensuite des campagnes dans KoraFlow.
{
"phoneNumber": "237699112233",
"name": "Awa Mballa",
"tags": ["client-vip", "douala"]
}Chaque nouveau contact compte dans la limite de contacts du forfait (erreur 402 CONTACTS_LIMIT si elle est atteinte).
Campagnes
/api/v1/campaignsscope : campaigns.readLes 50 dernières campagnes avec leurs compteurs (targetCount, deliveredCount, failedCount) et leur status. Les campagnes se créent depuis le tableau de bord KoraFlow.
Assistant IA
Chaque entreprise a son propre assistant : ces routes lisent et modifient uniquement celui de l’entreprise de la clé. Les instructions décrivent l’activité, le ton et les règles de réponse ; elles s’appliquent à tous les canaux, sauf si un canal a ses propres consignes. Fonctionne avec la clé IA KoraFlow comme avec votre propre clé IA. La clé IA personnelle n’est jamais renvoyée.
/api/v1/assistantscope : assistant.read{
"data": {
"enabled": true,
"instructions": "Tu es l'assistant de la boutique Awa (pagnes, Douala)…",
"welcomeMessage": "Bienvenue chez Awa !",
"ai": { "keyMode": "OWN", "provider": "openai", "model": "gpt-5" },
"channels": [
{ "channel": "WHATSAPP", "enabled": true, "instructions": null, "welcomeMessage": null },
{ "channel": "MESSENGER", "enabled": true, "instructions": null, "welcomeMessage": null },
{ "channel": "INSTAGRAM", "enabled": true, "instructions": "Tutoie le client.", "welcomeMessage": null }
]
}
}/api/v1/assistantscope : assistant.writeModification partielle : seuls les champs envoyés changent. null efface un texte. Réponse : la configuration complète à jour.
curl -X PUT https://api.kora-flow.com/api/v1/assistant \
-H "Authorization: Bearer kfk_VOTRE_CLE" \
-H "Content-Type: application/json" \
-d '{
"instructions": "Tu vends des pagnes et du wax. Livraison à Douala sous 24 h. Paiement Mobile Money.",
"channels": [{ "channel": "WHATSAPP", "instructions": "Réponds en 2 phrases au maximum." }]
}'| Champ | Type | Description |
|---|---|---|
enabled | boolean | Active ou coupe les réponses de l’IA |
instructions | string | null | Instructions générales (20 000 caractères max) |
welcomeMessage | string | null | Message d’accueil (2 000 caractères max) |
channels | array | Par canal (WHATSAPP, MESSENGER, INSTAGRAM) : enabled, instructions, welcomeMessage |
Chaque modification est inscrite au journal d’audit de l’entreprise (avec l’identifiant de la clé). Erreurs : 400 INVALID_REQUEST, 400 EMPTY_UPDATE, 403 si la clé n’a pas le scope.
Consommation & compte
/api/v1/usage{
"plan": "Pro (Croissance)",
"period": "month",
"messages": { "used": 3820, "limit": 10000 },
"contacts": { "used": 1240, "limit": 10000 },
"thisKey": { "messagesThisMonth": 2950 }
}period vaut month pour les forfaits payants (remise à zéro le 1er du mois) et total pour le forfait gratuit (quota cumulé). thisKey donne la consommation de la clé utilisée.
/api/v1/meCompte, scopes de la clé, forfait et débit autorisé (voir Démarrage rapide).
Webhooks
Les webhooks vous préviennent en temps réel : KoraFlow envoie une requête POST en JSON vers votre URL à chaque événement. Configurez-les dans Réglages → Intégrations → Webhooks sortants : saisissez l’URL HTTPS, cochez les événements, conservez le secret affiché, puis cliquez sur Tester.
Événements
| Événement | Déclenché quand… |
|---|---|
message.received | un client envoie un message WhatsApp |
message.sent | un message est envoyé via l’API |
message.status_updated | un message passe à DELIVERED, READ ou FAILED |
contact.created | un contact est créé (tableau de bord ou API) |
campaign.launched | une campagne démarre |
campaign.completed | tous les messages d’une campagne ont été traités |
lead.captured | un prospect remplit un formulaire Facebook Lead Ads |
form.completed | un client termine un formulaire WhatsApp KoraFlow (réponses incluses ; contactId nul si le formulaire est anonyme) |
form.automation | action « webhook » d'une automatisation de formulaire : envoyé au seul webhook choisi dans l'automatisation (événement, formulaire, session ; contactId nul si anonyme ; même identifiant d'événement à chaque nouvel essai) |
webhook.test | vous cliquez sur « Tester » |
Format de la requête
| En-tête | Valeur |
|---|---|
Content-Type | application/json |
X-KoraFlow-Event | nom de l’événement (ex. message.received) |
X-KoraFlow-Event-Id | identifiant unique de l’événement, identique à chaque nouvelle tentative (dédoublonnage) |
X-KoraFlow-Signature | sha256=<HMAC-SHA256 hexadécimal du corps brut, avec votre secret> |
User-Agent | KoraFlow-Webhook/1.0 |
Tous les événements partagent la même enveloppe ; le contenu propre à l’événement est dans data :
{
"id": "9b1f…",
"event": "message.received",
"tenantId": "4f6c…",
"timestamp": "2026-10-03T14:07:40.120Z",
"data": {
"messageId": "c41d…",
"contactId": "5d2a…",
"phoneNumber": "237699112233",
"contactName": "Awa Mballa",
"text": "Bonjour, je veux commander 2 sacs de riz",
"metaMsgId": "wamid.HBgM…",
"receivedAt": "2026-10-03T14:07:39.000Z"
}
}Vérifier la signature
Vérifiez toujours X-KoraFlow-Signature pour être sûr que la requête vient de KoraFlow. Calculez le HMAC-SHA256 du corps brut (avant tout décodage JSON) avec votre secret, puis comparez.
import crypto from "crypto";
import express from "express";
const app = express();
app.post("/webhooks/koraflow", express.raw({ type: "application/json" }), (req, res) => {
const expected = "sha256=" + crypto
.createHmac("sha256", process.env.KORAFLOW_WEBHOOK_SECRET)
.update(req.body) // Buffer brut
.digest("hex");
const received = req.get("X-KoraFlow-Signature") || "";
const valid = received.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected));
if (!valid) return res.sendStatus(401);
const { event, data } = JSON.parse(req.body.toString("utf8"));
res.sendStatus(200); // répondre vite, traiter ensuite
if (event === "message.received") handleIncoming(data);
if (event === "message.status_updated") updateDelivery(data.messageId, data.status);
});Livraison et nouvelles tentatives
- Votre endpoint doit répondre un code 2xx en moins de 10 secondes. Répondez d’abord, traitez ensuite (file d’attente, tâche de fond).
- En cas d’échec (code non-2xx, délai dépassé, erreur réseau), KoraFlow réessaie 2 fois : après 2 s puis après 5 s.
- Un même événement peut exceptionnellement arriver deux fois : dédoublonnez avec
data.messageId(oudata.metaMsgId). - L’ordre d’arrivée n’est pas garanti (un
READpeut arriver avant unDELIVERED) : ne faites jamais régresser un statut. - L’historique des livraisons (code HTTP, réponse de votre serveur) est visible dans Réglages → Intégrations.
Erreurs
En cas d’erreur, la réponse contient un message lisible et, le plus souvent, un code stable à utiliser dans votre programme :
{
"error": "Limite de 10000 messages mensuels atteinte sur le forfait Pro (Croissance). Passez au forfait supérieur dans « Abonnement » ou attendez le mois prochain.",
"code": "MESSAGES_LIMIT"
}| HTTP | code | Cause | Que faire |
|---|---|---|---|
| 400 | INVALID_PARAM | Champ manquant ou invalide (to, text, templateName, from…) | Corriger la requête |
| 401 | — | Clé absente, mal formée ou révoquée | Vérifier l’en-tête Authorization |
| 402 | MESSAGES_LIMIT | Quota de messages du forfait atteint | Changer de forfait ou attendre le mois suivant |
| 402 | CONTACTS_LIMIT | Limite de contacts du forfait atteinte | Changer de forfait |
| 402 | API_NOT_IN_PLAN | L’API n’est pas incluse dans le forfait | Changer de forfait |
| 403 | — | La clé n’a pas le scope requis | Créer une clé avec le bon scope |
| 404 | NOT_FOUND | Message introuvable | Vérifier l’id |
| 409 | WHATSAPP_NOT_CONNECTED | Aucun numéro WhatsApp connecté au compte | Connecter WhatsApp dans Réglages |
| 429 | RATE_LIMITED | Trop de requêtes par minute | Attendre Retry-After secondes |
| 502 | META_ERROR | Meta a refusé l’envoi (détails dans details) | Voir le tableau ci-dessous |
| 500 | — | Erreur interne KoraFlow | Réessayer plus tard avec la même Idempotency-Key |
Erreurs Meta courantes
Elles apparaissent dans details (réponse 502) ou dans error d’un message FAILED.
| Code Meta | Signification | Solution |
|---|---|---|
| 131047 | Plus de 24 h depuis le dernier message du client | Envoyer un modèle |
| 132001 | Le modèle n’existe pas (nom ou langue incorrects) | Vérifier GET /templates |
| 132000 | Nombre de variables incorrect | Fournir exactement variablesCount valeurs |
| 131026 | Message non livrable (numéro sans WhatsApp, version trop ancienne…) | Vérifier le numéro |
| 131049 | Meta a limité les messages marketing vers ce destinataire | Réessayer plus tard, espacer les envois marketing |
| 131056 | Trop de messages vers le même destinataire en peu de temps | Espacer les envois |
| 131053 | Fichier média illisible ou trop lourd | Vérifier l’URL et le format |
Limites & idempotence
Débit
Le nombre de requêtes par minute est limité par clé, selon le forfait. Valeurs standard ci-dessous ; la valeur exacte de votre compte est renvoyée par GET /me (rateLimitPerMinute).
| Forfait | Requêtes / minute / clé |
|---|---|
| Gratuit (Découverte) | 10 |
| Starter | 30 |
| Pro | 120 |
| Enterprise | 600 |
Chaque réponse indique où vous en êtes :
| En-tête | Description |
|---|---|
X-RateLimit-Limit | Requêtes autorisées par minute |
X-RateLimit-Remaining | Requêtes restantes dans la minute en cours |
X-RateLimit-Reset | Début de la minute suivante (timestamp Unix, secondes) |
Retry-After | Secondes à attendre (uniquement sur une réponse 429) |
Pour des envois en masse (plusieurs centaines de destinataires), préférez les campagnes du tableau de bord : elles gèrent le rythme d’envoi pour vous.
Idempotence
Un réseau instable peut vous faire perdre une réponse alors que le message est parti. Pour réessayer sans risque de doublon, ajoutez Idempotency-Key à POST /messages :
- même clé + même compte API dans les 24 h → la réponse d’origine est renvoyée, avec l’en-tête
Idempotent-Replayed: true, et rien n’est renvoyé à WhatsApp ; - les réponses
429et5xxne sont pas mémorisées : vous pouvez réessayer avec la même clé ; - construisez la clé à partir de votre donnée métier :
otp-{userId}-{timestamp},commande-{ref}-expedition…
Recettes
Envoyer un code de vérification (OTP)
Créez un modèle de catégorie AUTHENTICATION (ex. code_verification : « Votre code est {{1}} »), puis :
const code = String(Math.floor(100000 + Math.random() * 900000));
await saveOtp(user.id, code, { expiresInMinutes: 10 }); // dans VOTRE base
await fetch("https://api.kora-flow.com/api/v1/messages", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KORAFLOW_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": `otp-${user.id}-${Date.now()}`,
},
body: JSON.stringify({ to: user.phone, templateName: "code_verification", variables: [code] }),
});Confirmation de commande + facture PDF
- Créez un modèle UTILITY avec un en-tête Document : « Merci {{1}} ! Voici la facture de votre commande {{2}} ».
- Générez le PDF sur une URL publique (lien signé valable quelques heures, par exemple).
- Envoyez le modèle en passant le PDF dans
mediaUrl:
{
"to": "237699112233",
"templateName": "facture_commande",
"variables": ["Awa", "A1234"],
"mediaUrl": "https://exemple.com/factures/A1234.pdf?signature=…"
}Brancher votre propre chatbot ou CRM
- Abonnez un webhook à
message.received. - À chaque message, votre serveur calcule la réponse.
- Il répond avec un
textlibre : le client vient d’écrire, la fenêtre de 24 h est ouverte.
async function handleIncoming(data) {
const answer = await monBot.repondre(data.phoneNumber, data.text);
await fetch("https://api.kora-flow.com/api/v1/messages", {
method: "POST",
headers: { "Authorization": `Bearer ${process.env.KORAFLOW_API_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({ to: data.phoneNumber, text: answer }),
});
}Chatbot KoraFlow et chatbot externe
Si vous répondez vous-même via l’API, désactivez le chatbot / l’IA de KoraFlow (Réglages → Chatbot) pour éviter que le client reçoive deux réponses.
Make, Zapier, n8n (sans code)
Dans votre scénario, ajoutez un module HTTP → Make a request (Make), Webhooks by Zapier → Custom Request (Zapier) ou HTTP Request (n8n) :
| Réglage | Valeur |
|---|---|
| Méthode | POST |
| URL | https://api.kora-flow.com/api/v1/messages |
| En-têtes | Authorization = Bearer kfk_… et Content-Type = application/json |
| Corps (JSON) | {"to": "<téléphone>", "templateName": "confirmation_commande", "variables": ["<réf>", "<montant>"]} |
Remplacez les valeurs entre chevrons par les champs de l’étape précédente (ligne Google Sheets, commande WooCommerce, formulaire…).
Bonnes pratiques
- Une clé par application et par environnement (« ERP – production », « Site – test ») avec le minimum de scopes. En cas de fuite, révoquez une seule clé.
- Modèles pour le premier contact, texte libre seulement pour répondre dans les 24 h.
- Toujours une Idempotency-Key sur les envois déclenchés par un événement métier (commande, paiement, OTP).
- Webhooks plutôt que interrogation en boucle pour suivre les statuts et les réponses.
- Gérez le 402 : prévenez l’administrateur du compte quand le quota est atteint au lieu de réessayer en boucle.
- Numéros propres : stockez-les au format international dès la saisie (237…, 225…, 221…).
- Respectez le consentement et proposez toujours un moyen de se désabonner pour les messages marketing.
Versions
L’API est versionnée dans l’URL (/api/v1). Dans une même version, nous pouvons ajouter des champs, des routes ou des événements sans préavis : ignorez les champs que vous ne connaissez pas. Tout changement incompatible fera l’objet d’une nouvelle version (/api/v2).
| Date | Changement |
|---|---|
| 3 octobre 2026 | Envoi de médias, choix du numéro expéditeur (from), Idempotency-Key, GET /messages/{id}, /messages, /templates, /numbers, /usage ; limites de débit par forfait ; messageId et raison d’échec dans message.status_updated ; événement message.sent. |
| 13 septembre 2026 | Variables de modèle (variables) dans POST /messages. |
| 2026 | Première version : contacts, envoi texte et modèle, campagnes, webhooks signés. |
Besoin d’aide pour votre intégration ?
Écrivez-nous à contact@tch-solution.com en précisant le id du message ou l’heure de la requête (jamais votre clé API). Notre équipe peut aussi réaliser l’intégration pour vous.