API WhatsApp

Connecte un compte WhatsApp, reçois les messages sur ton site et réponds avec ton propre code.

URL de base :

Introduction

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 :

Tes commandes (!menu, !ping...) vivent dans ton propre code. Tu ne modifies jamais l'API.

Tu peux tout faire sans coder depuis le panneau web : /panel.

Démarrage rapide

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 !"}'

Authentification

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.

Sécurité : n'utilise la clé que côté serveur. Ne la mets jamais dans du JavaScript visible dans le navigateur, ni sur GitHub.

Endpoints

Toutes les réponses sont en JSON. Les erreurs ont la forme {"error":"message"}.

GET/status

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"
}
ChampDescription
labelNom de ta clé
statusÉtat de la connexion (voir Statuts)
phoneNuméro lié, ou null
sinceTimestamp (ms) de la dernière connexion réussie
registeredtrue si un compte est déjà lié
webhookURL du webhook enregistré, ou null

POST/pair

Génère un code d'appairage pour lier un numéro WhatsApp.

ChampTypeDescription
numberstringNumé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.

POST/stop

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"}

POST/start

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.

POST/logout

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}
Pause ou suppression ? /stop garde le compte lié (tu relances avec /start). /logout efface tout (tu recommences avec /pair).

POST/webhook

Enregistre l'URL qui recevra tes messages entrants.

ChampTypeDescription
urlstringURL 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"}

GET/webhook

Renvoie le webhook actuel.

curl {{BASE}}/webhook -H "x-api-key: SA_CLE"
{"url":"https://monsite.com/wa-hook"}

DELETE/webhook

Supprime le webhook. Tu ne reçois plus de messages.

curl -X DELETE {{BASE}}/webhook -H "x-api-key: SA_CLE"

POST/send

Envoie un message. La session doit être open. Limite : 30 messages par minute.

ChampTypeDescription
tostringNuméro international sans +, ou identifiant complet (ex. 1203630...@g.us pour un groupe). Utilise le champ from reçu dans le webhook.
typestringtext (défaut), image, video, audio, document
textstringLe message (obligatoire si type = text)
urlstringLien public du fichier (pour image, video, audio, document)
captionstringLégende (image, video, document)
filenamestringNom 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.

Webhook : recevoir les messages

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
}
ChampDescription
fromConversation d'origine : à réutiliser dans to pour répondre
senderAuteur du message (utile dans un groupe)
nameNom affiché de l'expéditeur
isGrouptrue si le message vient d'un groupe
typeType WhatsApp (conversation, imageMessage, extendedTextMessage...)
textTexte ou légende (vide si le message n'a pas de texte)
timestampDate du message en secondes

Ne sont pas transmis : tes propres messages, les statuts des contacts et les chaînes (newsletters).

Vérifier la signature

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.

Statuts de connexion

StatutSignificationQue faire
openConnecté, tout fonctionneRien
connectingConnexion en coursAttends quelques secondes
reconnectingConnexion perdue, nouvelle tentative automatique (délai croissant)Attends
stoppedSession en pausePOST /start
disconnectedAucune session activePOST /start si le compte est lié, sinon POST /pair
replacedLa session a été ouverte ailleursFerme 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.

Erreurs et limites

CodeSignification
400Paramètre manquant ou invalide, ou action impossible dans l'état actuel (ex. Session non connectée)
401Clé API manquante ou invalide
429Trop de requêtes : limite dépassée
500Erreur interne : réessaie, puis contacte l'administrateur
LimiteValeur
/send30 messages par minute et par clé
/pair5 demandes par 10 minutes et par clé
Toutes les routes10 requêtes par seconde et par adresse IP

Exemples de code

Un bot minimal qui répond à !ping et !menu, avec vérification de la signature.

Node.js (Express)

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)

Python (Flask)

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

<?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);

Questions fréquentes

Combien de comptes puis-je lier ?

Un compte WhatsApp par clé. Chaque clé a sa session, isolée des autres.

Le code d'appairage est refusé, que faire ?

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.

La session est passée à disconnected toute seule

Essaie POST /start. Si l'erreur indique qu'aucune session n'existe, WhatsApp a délié l'appareil : refais un /pair.

Je ne reçois rien sur mon webhook

Comment éviter un bannissement du numéro ?

Cette API repose sur une bibliothèque non officielle. WhatsApp peut restreindre ou bannir un numéro en cas d'usage abusif : utilise-la avec prudence et évite ton numéro principal pour les tests.

Panneau de gestion : /panel