Connecte un compte WhatsApp, reçois les messages sur ton site et réponds avec ton propre code.
URL de base :
Cette API gère la connexion d'un compte WhatsApp. Chaque clé secrète possède sa propre session, indépendante des autres. Une fois connecté, tu peux :
/send.Tes commandes (!menu, !ping...) vivent dans ton propre code. Tu ne modifies jamais l'API.
1. Récupère ta clé auprès de l'administrateur. Elle ressemble à a1b2c3... (48 caractères). Garde-la secrète.
2. Demande un code d'appairage avec ton numéro (format international, sans +) :
curl -X POST {{BASE}}/pair \
-H "x-api-key: SA_CLE" -H "Content-Type: application/json" \
-d '{"number":"50937000000"}'Réponse :
{"code":"ABCD1234"}3. Entre le code dans WhatsApp : Appareils connectés, Connecter un appareil, Lier avec le numéro de téléphone. Fais-le vite, le code expire au bout de quelques minutes.
4. Vérifie la connexion :
curl {{BASE}}/status -H "x-api-key: SA_CLE"Tu dois voir "status":"open".
5. Envoie un premier message :
curl -X POST {{BASE}}/send \
-H "x-api-key: SA_CLE" -H "Content-Type: application/json" \
-d '{"to":"50937000000","text":"Bonjour !"}'Toutes les routes (sauf /panel et /docs) demandent ta clé dans le header x-api-key.
x-api-key: SA_CLE
Une clé ne donne accès qu'à sa propre session. Une clé invalide renvoie 401.
Toutes les réponses sont en JSON. Les erreurs ont la forme {"error":"message"}.
Renvoie l'état de ta connexion.
curl {{BASE}}/status -H "x-api-key: SA_CLE"{
"label": "cle1",
"status": "open",
"phone": "50937000000",
"since": 1790000000000,
"registered": true,
"webhook": "https://monsite.com/wa-hook"
}| Champ | Description |
|---|---|
label | Nom de ta clé |
status | État de la connexion (voir Statuts) |
phone | Numéro lié, ou null |
since | Timestamp (ms) de la dernière connexion réussie |
registered | true si un compte est déjà lié |
webhook | URL du webhook enregistré, ou null |
Génère un code d'appairage pour lier un numéro WhatsApp.
| Champ | Type | Description |
|---|---|---|
number | string | Numéro en format international, sans + (ex. 50937000000) |
curl -X POST {{BASE}}/pair \
-H "x-api-key: SA_CLE" -H "Content-Type: application/json" \
-d '{"number":"50937000000"}'{"code":"ABCD1234"}Limite : 5 demandes par 10 minutes. Si un compte est déjà lié, l'API répond Déjà connecté : utilise /logout d'abord.
Met la session en pause. Le compte reste lié, mais l'API se déconnecte de WhatsApp. Aucun message n'est reçu ni envoyé pendant la pause, et elle est conservée après un redémarrage du serveur.
curl -X POST {{BASE}}/stop -H "x-api-key: SA_CLE"{"ok":true,"status":"stopped"}Relance une session en pause (ou reconnecte une session liée). Pas besoin d'un nouveau code.
curl -X POST {{BASE}}/start -H "x-api-key: SA_CLE"{"ok":true,"status":"connecting"}Si aucun compte n'est lié, l'API répond Aucune session, utilise /pair.
Supprime définitivement la session et délie l'appareil dans WhatsApp. Pour te reconnecter, il faut un nouveau code avec /pair. Le webhook n'est pas supprimé.
curl -X POST {{BASE}}/logout -H "x-api-key: SA_CLE"{"ok":true}/stop garde le compte lié (tu relances avec /start). /logout efface tout (tu recommences avec /pair).Enregistre l'URL qui recevra tes messages entrants.
| Champ | Type | Description |
|---|---|---|
url | string | URL http(s) de ta route. Les réseaux privés (10.x, 192.168.x, 172.16-31.x, 169.254.x) sont refusés ; 127.0.0.1 est autorisé si ton site est sur le même serveur. |
curl -X POST {{BASE}}/webhook \
-H "x-api-key: SA_CLE" -H "Content-Type: application/json" \
-d '{"url":"https://monsite.com/wa-hook"}'{"ok":true,"url":"https://monsite.com/wa-hook"}Renvoie le webhook actuel.
curl {{BASE}}/webhook -H "x-api-key: SA_CLE"{"url":"https://monsite.com/wa-hook"}Supprime le webhook. Tu ne reçois plus de messages.
curl -X DELETE {{BASE}}/webhook -H "x-api-key: SA_CLE"Envoie un message. La session doit être open. Limite : 30 messages par minute.
| Champ | Type | Description |
|---|---|---|
to | string | Numéro international sans +, ou identifiant complet (ex. 1203630...@g.us pour un groupe). Utilise le champ from reçu dans le webhook. |
type | string | text (défaut), image, video, audio, document |
text | string | Le message (obligatoire si type = text) |
url | string | Lien public du fichier (pour image, video, audio, document) |
caption | string | Légende (image, video, document) |
filename | string | Nom du fichier (document) |
Texte :
curl -X POST {{BASE}}/send \
-H "x-api-key: SA_CLE" -H "Content-Type: application/json" \
-d '{"to":"50937000000","text":"Bonjour !"}'Image :
curl -X POST {{BASE}}/send \
-H "x-api-key: SA_CLE" -H "Content-Type: application/json" \
-d '{"to":"50937000000","type":"image","url":"https://monsite.com/photo.jpg","caption":"Ma photo"}'Document :
curl -X POST {{BASE}}/send \
-H "x-api-key: SA_CLE" -H "Content-Type: application/json" \
-d '{"to":"50937000000","type":"document","url":"https://monsite.com/facture.pdf","filename":"facture.pdf"}'{"ok":true}Les liens de fichiers doivent être publics (http ou https) et ne pas pointer vers un réseau privé ou localhost.
Quand quelqu'un écrit à ton numéro, l'API envoie une requête POST à ton URL avec ce JSON :
{
"label": "cle1",
"id": "3EB0A1B2C3D4E5F6",
"from": "50937000000@s.whatsapp.net",
"sender": "50937000000@s.whatsapp.net",
"name": "Jean",
"isGroup": false,
"type": "conversation",
"text": "!menu",
"timestamp": 1790000000
}| Champ | Description |
|---|---|
from | Conversation d'origine : à réutiliser dans to pour répondre |
sender | Auteur du message (utile dans un groupe) |
name | Nom affiché de l'expéditeur |
isGroup | true si le message vient d'un groupe |
type | Type WhatsApp (conversation, imageMessage, extendedTextMessage...) |
text | Texte ou légende (vide si le message n'a pas de texte) |
timestamp | Date du message en secondes |
Ne sont pas transmis : tes propres messages, les statuts des contacts et les chaînes (newsletters).
Chaque requête contient le header x-signature : un HMAC SHA-256 (en hexadécimal) du corps brut, calculé avec ta clé. La clé n'est jamais envoyée. Vérifie toujours la signature avant de traiter le message.
Si ton site ne répond pas 200 dans les 8 secondes, l'API réessaie une fois, puis abandonne le message. Réponds vite, et fais tes traitements longs après la réponse.
| Statut | Signification | Que faire |
|---|---|---|
open | Connecté, tout fonctionne | Rien |
connecting | Connexion en cours | Attends quelques secondes |
reconnecting | Connexion perdue, nouvelle tentative automatique (délai croissant) | Attends |
stopped | Session en pause | POST /start |
disconnected | Aucune session active | POST /start si le compte est lié, sinon POST /pair |
replaced | La session a été ouverte ailleurs | Ferme l'autre instance, puis POST /start |
Si WhatsApp délie l'appareil depuis ton téléphone, la session est supprimée automatiquement : redemande un code avec /pair.
| Code | Signification |
|---|---|
400 | Paramètre manquant ou invalide, ou action impossible dans l'état actuel (ex. Session non connectée) |
401 | Clé API manquante ou invalide |
429 | Trop de requêtes : limite dépassée |
500 | Erreur interne : réessaie, puis contacte l'administrateur |
| Limite | Valeur |
|---|---|
/send | 30 messages par minute et par clé |
/pair | 5 demandes par 10 minutes et par clé |
| Toutes les routes | 10 requêtes par seconde et par adresse IP |
Un bot minimal qui répond à !ping et !menu, avec vérification de la signature.
import express from 'express'
import crypto from 'crypto'
const app = express()
const KEY = process.env.WA_API_KEY
const API = '{{BASE}}'
async function send(to, text) {
await fetch(API + '/send', {
method: 'POST',
headers: { 'x-api-key': KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ to, text })
})
}
app.post('/wa-hook', express.json({ verify: function (req, res, buf) { req.raw = buf } }), async function (req, res) {
const sig = crypto.createHmac('sha256', KEY).update(req.raw).digest('hex')
if (sig !== req.headers['x-signature']) return res.sendStatus(401)
res.sendStatus(200)
const { from, text, isGroup } = req.body
if (isGroup) return
if (text === '!ping') await send(from, 'pong')
if (text === '!menu') await send(from, 'Boutique | Compte | Support')
})
app.listen(5001)import hmac, hashlib, os, requests
from flask import Flask, request, abort
app = Flask(__name__)
KEY = os.environ['WA_API_KEY']
API = '{{BASE}}'
@app.post('/wa-hook')
def hook():
sig = hmac.new(KEY.encode(), request.get_data(), hashlib.sha256).hexdigest()
if not hmac.compare_digest(sig, request.headers.get('x-signature', '')):
abort(401)
data = request.get_json()
if data['text'] == '!ping':
requests.post(API + '/send', headers={'x-api-key': KEY},
json={'to': data['from'], 'text': 'pong'})
return '', 200<?php
$KEY = getenv('WA_API_KEY');
$raw = file_get_contents('php://input');
$sig = hash_hmac('sha256', $raw, $KEY);
if (!hash_equals($sig, $_SERVER['HTTP_X_SIGNATURE'] ?? '')) { http_response_code(401); exit; }
$data = json_decode($raw, true);
if ($data['text'] === '!ping') {
$ch = curl_init('{{BASE}}/send');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['x-api-key: ' . $KEY, 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode(['to' => $data['from'], 'text' => 'pong']),
CURLOPT_RETURNTRANSFER => true
]);
curl_exec($ch);
}
http_response_code(200);Un compte WhatsApp par clé. Chaque clé a sa session, isolée des autres.
Vérifie le numéro (format international, sans +), demande un nouveau code et entre-le rapidement. Attention à la limite de 5 demandes par 10 minutes.
disconnected toute seuleEssaie POST /start. Si l'erreur indique qu'aucune session n'existe, WhatsApp a délié l'appareil : refais un /pair.
/status montre open et que le webhook est bien enregistré.POST JSON et répond 200 rapidement.Panneau de gestion : /panel