Table des matières
Premiers pas
Connecter & Envoyer
Recevoir et automatiser
API WhatsApp avec PythonEnvoyer, recevoir et automatiser des messages
Tout ce dont vous avez besoin pour utiliser le API WhatsApp en Python: quelle bibliothèque choisir, comment connecter un compte lié avec un code QR, comment envoyer et recevoir des messages avec
demandes et httpx, et comment câbler un webhook FastAPI pour un bot ou un agent IA. API REST aujourd'hui, aucune vérification Meta Business nécessaire
import requests
BASE_URL = "https://{YOUR_DSN}/api/v1"
HEADERS = {"X-API-KEY": "YOUR_ACCESS_TOKEN"}
def send_whatsapp(chat_id: str, text: str) -> dict:
response = requests.post(
f"{BASE_URL}/chats/{chat_id}/messages",
headers=HEADERS,
data={"text": text},
)
response.raise_for_status()
return response.json()
send_whatsapp("9f9uio56sopa456s", "Hello from Python!")200 OK, message envoyé
Définition
Qu'est-ce que l'API WhatsApp en Python ?
Le API WhatsApp en Python signifie d'appeler la messagerie WhatsApp Business à partir de code Python au lieu de cliquer sur WhatsApp Web. Un script Python ou un service backend envoie une requête HTTP, généralement avec
demandes ou httpx, à une API REST qui expose les discussions, les messages et les webhooks, soit directement l'API Cloud de Meta, soit un fournisseur unifié comme Unipile qui connecte WhatsApp ainsi que LinkedIn, Instagram et Telegram derrière une seule interface. Meta ne publie pas de SDK Python WhatsApp officiel tout-en-un, c'est pourquoi presque chaque intégration Python de ce guide, et la plupart de ce que vous trouverez sur le reste du web, communique directement avec les points de terminaison REST.Une API REST pour WhatsApp, LinkedIn, Instagram et Telegram
Lié avec un code QR ou un code d'appairage, sans vérification Meta Business
demandes pour les scripts simples, httpx pour l'asynchrone à grande échelle Pour la couche d'orientation, l'accès, le coût et les limites, commencez par le Guide sur l'accès, les coûts et les limites de l'API WhatsApp. Construire en PHP au lieu de Python ?
Lire la même intégration en PHP Avant de construire
De quoi avez-vous besoin avant de commencer ?
Vous n'avez pas besoin d'un compte Meta Business ni d'une approbation de la plateforme WhatsApp Business pour commencer à envoyer et à recevoir des messages depuis Python. Vous avez besoin d'un environnement Python fonctionnel, d'un client HTTP, d'un endroit pour recevoir les webhooks et d'un compte Unipile.
Python 3.9+
Correspond à la version minimale requise par le SDK Python d'Unipile
pydantic dépendance, et par le moderne httpx et les versions de FastAPI.requests ou httpx
Un tunnel local
Un outil comme
ngrok ou cloudflared d'exposer votre route de webhook FastAPI sur une URL HTTPS publique pendant que vous développez.Jeton d'accès et DSN
Tous les deux proviennent du tableau de bord Unipile. Le DSN est l'hôte que vous appelez, le jeton d'accès va dans le
X-API-KEY en-tête de chaque requête.Comparaison de bibliothèques
Quelle bibliothèque Python devriez-vous utiliser pour WhatsApp ?
Il n'y a pas de réponse unique et évidente, et la plupart des articles de blog sur ce sujet font la promotion du paquet que leur auteur maintient. Voici une comparaison factuelle des cinq façons dont les développeurs Python appellent réellement WhatsApp aujourd'hui, de l'automatisation de navigateur à un fournisseur unifié, afin que vous puissiez choisir en fonction de ce que chaque option fait réellement, et non en fonction du marketing.
Bibliothèque / approche
Ce qu'il appelle réellement
Vérification Meta Business
Maintenu
Meilleur pour
pywhatkit
Pilote WhatsApp Web dans un onglet de navigateur (automatisation du clavier), et non une API côté serveur
N/A, pas d'API
Communauté, sporadique
Scripts ponctuels et démos sur une machine avec un écran, pas d'envoi en production
API Cloud WhatsApp
Léger wrapper Python autour des propres points de terminaison de l'API WhatsApp Cloud de Meta
Requis
Enveloppe de la communauté
Les équipes déjà approuvées sur l'API Cloud qui souhaitent un client Python
client-api-whatsapp-python
Appelle le SaaS green-api, qui à son tour détient la session WhatsApp
Pas nécessaire
Maintenu par le fournisseur
Des équipes disposées à dépendre d'un second fournisseur SaaS spécialisé
demandes, adresser directement à Meta
Points de terminaison de l'API Cloud de Meta, sans aucun wrapper
Requis
Faites-le vous-même
Équipes déjà validées pour la vérification Meta Business qui souhaitent un contrôle total
Unipile, requests ou httpx
L'API de messagerie unifiée d'Unipile, WhatsApp ainsi que LinkedIn, Instagram et Telegram
Pas nécessaire
Activement maintenu, SDK Python en version bêta
Produits SaaS connectant de nombreux comptes WhatsApp d'utilisateurs finaux pour le compte de chaque utilisateur
pywhatkit
AppelsExécute WhatsApp Web dans un onglet de navigateur, et non comme une API côté serveur
Vérification MetaN/A, pas d'API
MaintenuCommunauté, sporadique
Meilleur pourScripts ponctuels et démos, pas de production envoi
API Cloud WhatsApp
AppelsLéger surcouche autour des propres points de terminaison de l'API Cloud de Meta
Vérification MetaRequis
MaintenuEnveloppe de la communauté
Meilleur pourÉquipes déjà approuvées sur l'API Cloud
client-api-whatsapp-python
AppelsLe SaaS green-api, qui détient la session WhatsApp
Vérification MetaPas nécessaire
MaintenuMaintenu par le fournisseur
Meilleur pourÉquipes à l'aise avec un deuxième fournisseur SaaS
demandes, adresser directement à Meta
AppelsPoints de terminaison de l'API Cloud de Meta, sans wrapper
Vérification MetaRequis
MaintenuFaites-le vous-même
Meilleur pourÉquipes déjà validées pour la vérification Meta Business
Unipile, requests ou httpx
AppelsAPI de messagerie unifiée, WhatsApp avec LinkedIn, Instagram, Telegram
Vérification MetaPas nécessaire
MaintenuActivement maintenu, SDK Python en version bêta
Meilleur pourDes produits SaaS connectant de nombreux comptes d'utilisateurs finaux
Chaque option qui garde Vérification de l'entreprise Meta requise communique finalement avec la propre API WhatsApp Cloud de Meta (voir Documentation de la plateforme WhatsApp Business de Meta), ce qui est le bon choix si vous utilisez déjà un numéro d'entreprise vérifié. Si vous connectez des comptes WhatsApp pour le compte de nombreux utilisateurs finaux différents, un flux par code QR ou par code d'association supprime complètement cette étape de vérification, ce qui est le modèle utilisé par le reste de ce guide.
Connexion au compte
Comment connecter un compte WhatsApp en Python ?
Chaque appel de ce guide s'exécute au nom d'un utilisateur authentifié qui a lié son propre compte WhatsApp. Il n'y a pas d'étape de vérification Meta Business : depuis Python, vous envoyez un seul
POST /api/v1/accounts demande avec provider défini sur WHATSAPP, et l'utilisateur confirme la liaison soit en scannant un code QR, soit en saisissant un code d'appairage sur son téléphone.Option A : code QR (par défaut)
Partir
couplage_numéro_de_téléphone hors du corps de la requête et Unipile renvoie un point de contrôle contenant la charge utile du code QR. Affichez-le avec une bibliothèque telle que QR code et l'afficher pour que l'utilisateur puisse le scanner à partir de WhatsApp > Appareils connectés.import requests
BASE_URL = "https://{YOUR_DSN}/api/v1"
HEADERS = {"X-API-KEY": "YOUR_ACCESS_TOKEN", "accept": "application/json"}
def connect_whatsapp_qr() -> dict :
response = requests.post(
f"{BASE_URL}/accounts",
headers=HEADERS,
json={"provider": "WHATSAPP"},
)
response.raise_for_status()
return response.json()
account = connect_whatsapp_qr()
print(account)
# account contient un nouvel account_id ainsi qu'un objet checkpoint.
# Affichez le point de contrôle sous forme de code QR et demandez à l’utilisateur de le scanner
# depuis WhatsApp > Appareils associés.Option B : code d'association
Passe
couplage_numéro_de_téléphone en chiffres au format E.164 uniquement, code pays en premier, sans signe plus, sans espaces. Unipile renvoie un point de contrôle contenant un code court que l'utilisateur tape dans WhatsApp au lieu de scanner quoi que ce soit, ce qui convient mieux à un serveur sans tête dépourvu d'écran pour afficher un code QR.def connect_whatsapp_pairing_code(phone_e164_digits: str) -> dict:
response = requests.post(
f"{BASE_URL}/accounts",
headers=HEADERS,
json={
"provider": "WHATSAPP",
"pairing_phone_number": phone_e164_digits,
},
)
response.raise_for_status()
return response.json()
# Indicatif pays + numéro, chiffres uniquement, par exemple la France
account = connect_whatsapp_pairing_code("33612345678")
# Le " checkpoint " du compte contient le code d'appairage à afficher dans votre interface utilisateur.
# L’utilisateur le saisit dans WhatsApp > Appareils associés > Associer avec un numéro de téléphone.Confirmez que le compte est connecté
Une fois que l'utilisateur a scanné le code QR ou saisi le code d'appairage, vous devez savoir quand le compte est réellement prêt à envoyer et à recevoir. Unipile vous offre deux options.
Interroger le statut du compte
Appel
GET /api/v1/accounts/{account_id} toutes les quelques secondes jusqu'à ce que le compte n'ait plus besoin de son point de contrôle. Simple, mais cela gaspille des requêtes pendant que vous attendez.Webhook de l'état du compte
Enregistrer un webhook avec
source défini sur statut_du_compte (identique POST /api/v1/webhooks point de terminaison utilisé pour les messages) et les envois Unipile {"AccountStatus": {"account_id": "...", "message": "OK"}} dès que le compte est prêt. C'est ce que la plupart des intégrations en production utilisent.import time
def wait_for_connection(account_id: str, timeout_seconds: int = 120) -> dict:
deadline = time.time() + timeout_seconds
while time.time() < deadline:
response = requests.get(f"{BASE_URL}/accounts/{account_id}", headers=HEADERS)
response.raise_for_status()
account = response.json()
print(account) # : examinez la charge utile en temps réel pour effectuer votre propre vérification d'état
time.sleep(2)
raise TimeoutError("Le compte WhatsApp n'a pas confirmé la connexion à temps")Envoyer
Comment envoyer un message WhatsApp avec Python ?
Envoyer un message WhatsApp à partir de Python se résume à un seul appel HTTP :
POST /api/v1/chats/{chat_id}/messages, avec le chat_id vous avez déjà à partir de la liste des discussions ou d'un webhook entrant, et un text champ. L'endpoint accepte aussi bien les corps encodés en formulaire qu'en JSON, donc un simple requests.post avec données= fonctionne sans configuration supplémentaire.S'il n'y en a pas existant
chat_id, par exemple le premier message à un nouveau contact, appel POST /api/v1/chats au lieu d'avec un account_id et celui du destinataire attendees_ids; Unipile crée le chat 1:1 et envoie le message dans la même requête.import requests
BASE_URL = "https://{YOUR_DSN}/api/v1"
HEADERS = {"X-API-KEY": "YOUR_ACCESS_TOKEN"}
def send_message(chat_id: str, text: str) -> dict:
response = requests.post(
f"{BASE_URL}/chats/{chat_id}/messages",
headers=HEADERS,
data={"text": text},
)
response.raise_for_status()
return response.json()
def start_chat(account_id: str, attendee_provider_id: str, text: str) -> dict:
response = requests.post(
f"{BASE_URL}/chats",
headers=HEADERS,
data={
"account_id": account_id,
"attendees_ids": attendee_provider_id,
"text": text,
},
)
response.raise_for_status()
return response.json()Les types de messages (texte, média, notes vocales, modèles) et la fenêtre de service client de 24 heures constituent un sujet à part entière, traité en détail dans le guide de les types de messages pris en charge par l'API WhatsApp. Cette section couvre uniquement la tuyauterie Python.
Meta facture les messages de l'API WhatsApp par message envoyé, et non par conversation, depuis juillet 2025. Voir Comment fonctionne la tarification de l'API WhatsApp par message pour les tarifs actuels par pays.
Concurrence
Comment envoyer des messages WhatsApp de manière asynchrone en Python ?
Lorsque vous envoyez à trop de destinataires en même temps, une diffusion, une vidange de file d'attente, un travail de suivi en masse, une boucle qui en attend un
requests.post à la fois est le goulot d'étranglement, pas l'API. httpx.AsyncClient combiné avec asyncio.gather envoie de nombreuses requêtes simultanément à partir d'une seule boucle d'événements, sans aucun thread requis. Un sémaphore est ce qui vous permet de rester un bon citoyen : les comptes WhatsApp restent soumis aux propres limites de débit de la plateforme, de sorte qu'une concurrence illimitée se traduit simplement par le remplacement d'une boucle lente par un mur de réponses 429.import asyncio
import httpx
BASE_URL = "https://{YOUR_DSN}/api/v1"
HEADERS = {"X-API-KEY": "YOUR_ACCESS_TOKEN"}
CONCURRENCY_LIMIT = 5
async def send_message_async(
client: httpx.AsyncClient,
semaphore: asyncio.Semaphore,
chat_id: str,
text: str,
) -> dict:
async with semaphore:
response = await client.post(
f"{BASE_URL}/chats/{chat_id}/messages",
headers=HEADERS,
data={"text": text},
)
response.raise_for_status()
return response.json()
async def send_bulk(messages: list[tuple[str, str]]) -> list:
semaphore = asyncio.Semaphore(CONCURRENCY_LIMIT)
async with httpx.AsyncClient(timeout=30) as client:
tasks = [
send_message_async(client, semaphore, chat_id, text)
for chat_id, text in messages
]
return await asyncio.gather(*tasks, return_exceptions=True)
messages = [
("9f9uio56sopa456s", "Your order shipped!"),
("a1b2c3d4e5f6g7h8", "Your order shipped!"),
]
results = asyncio.run(send_bulk(messages))
for chat_id_text, result in zip(messages, results):
if isinstance(result, Exception):
print("failed:", chat_id_text[0], result)Garder
LIMITE_DE_CONCURRENCE soyez conservateur et ne l'augmentez qu'après avoir observé les taux d'erreur réels. return_exceptions=True ce qui signifie qu'un envoi échoué n'annule pas le reste du lot, ce qui importe une fois que vous envoyez des centaines de messages en une seule fois. La section sur la limitation du taux et les nouvelles tentatives ci-dessous s'appuie sur ce même modèle.Webhooks
Comment recevoir des messages WhatsApp avec un webhook FastAPI ?
Un webhook permet à votre service Python d'être informé d'un nouveau message WhatsApp dès son arrivée, au lieu d'interroger le système en continu. Vous enregistrez un point de terminaison auprès d'Unipile, et chaque événement correspondant est transmis à votre serveur sous forme de JSON. FastAPI convient naturellement au côté destinataire : un
pydantic le modèle valide la charge utile pour vous, et Tâches d'arrière-plan Permettez à votre route de renvoyer une réponse immédiatement tandis que le vrai travail, l'appel d'un modèle, l'écriture dans une base de données, se produit après.1. Enregistrer le webhook
Point
request_url à votre route FastAPI. Pendant le développement local, cela signifie l'URL HTTPS que votre tunnel (de la section des prérequis ci-dessus) expose, et non localhost.import requests
BASE_URL = "https://{YOUR_DSN}/api/v1"
HEADERS = {"X-API-KEY": "YOUR_ACCESS_TOKEN"}
response = requests.post(
f"{BASE_URL}/webhooks",
headers=HEADERS,
json={
"source": "messaging",
"request_url": "https://your-tunnel.example.com/webhooks/whatsapp",
"name": "whatsapp-fastapi",
"format": "json",
"events": ["message_received"],
},
)
response.raise_for_status()
print(response.json())2. Le recevoir dans FastAPI
La charge utile qu'envoie Unipile contient la discussion, l'expéditeur et le texte du message sous forme de champs plats, ainsi qu'une liste de pièces jointes lorsqu'il y en a. Ne modélisez que ce dont vous avez besoin ; Pydantic ignore les champs supplémentaires par défaut.
from typing import List, Optional
from fastapi import BackgroundTasks, FastAPI
from pydantic import BaseModel
app = FastAPI()
class Sender(BaseModel) :
attendee_id : str
attendee_name : Optional[str] = None
attendee_provider_id : str
class Attachment(BaseModel) :
id : str
type : str
mimetype : Optional[str] = None
unavailable : bool = False
class WhatsAppMessageEvent(BaseModel) :
account_id : str
account_type : str
event : str
chat_id : str
message_id : str
message : Optional[str] = None
timestamp : str
webhook_name : Optional[str] = None
expéditeur : Sender
pièces-jointes : List[Attachment] = []
def handle_message(event: WhatsAppMessageEvent) -> None :
si event.account_type != " WHATSAPP " ou event.event != " message_received " :
return
# Unipile inclut les messages envoyés par le compte lié lui-même, depuis
# un autre appareil ou à partir de vos propres appels API. Comparez l'expéditeur
# avec le propriétaire du compte que vous avez enregistré lors de la connexion si vous
# souhaitez uniquement réagir aux messages provenant de l'autre partie.
print(f"Nouveau message WhatsApp sur le chat {event.chat_id} : {event.message}")
# Transférez-le vers votre file d’attente, votre base de données ou un agent IA à partir d’ici
@app.post("/webhooks/whatsapp")
async def whatsapp_webhook(
event: WhatsAppMessageEvent,
background_tasks: BackgroundTasks,
):
background_tasks.add_task(handle_message, event)
return {"status": "received"}Exécutez-le avec
uvicorn main:app --reload, dirigez votre tunnel vers le port 8000 et enregistrez cette URL publique comme request_url à l'étape 1. Retour {"status": "received"} avant que le message ne soit entièrement traité importe : Unipile attend une réponse rapide et Tâches d'arrière-plan ce qui retient gérer_le_message de l'en empêcher.Encore une chose qui vaut la peine d'être intégrée dès le départ : stocker chaque élément traité
ID du message avant d'agir, et ignorez tout ce que vous avez déjà vu. Si le compte WhatsApp lié lui-même se déconnecte et se reconnecte, Unipile livre les messages arrivés pendant cette coupure une fois qu'il a rattrapé son retard, et un redéploiement ou une tâche de fond plantée peut séparément amener votre propre gestionnaire à voir le même événement deux fois, donc le traitement ID du message car une clé d'idempotence empêche un bot WhatsApp de répondre deux fois.Lu
Comment récupère-t-on les discussions et l'historique des messages en Python ?
Chaque point de terminaison de liste de l'API Unipile, qu'il s'agisse des discussions, des messages ou des participants, est paginé de la même manière : la réponse comporte un
articles tableau et un curseur. Passe-moi ça curseur de retour au prochain appel, et arrêtez-vous dès qu'il revient nul. De Python while True la boucle correspond directement à ce motif.Lister toutes les discussions WhatsApp pour un compte
import requests
BASE_URL = "https://{YOUR_DSN}/api/v1"
HEADERS = {"X-API-KEY": "YOUR_ACCESS_TOKEN"}
def list_all_whatsapp_chats(account_id: str) -> list:
chats = []
cursor = None
while True:
params = {"account_id": account_id, "limit": 100}
if cursor:
params["cursor"] = cursor
response = requests.get(f"{BASE_URL}/chats", headers=HEADERS, params=params)
response.raise_for_status()
page = response.json()
chats.extend(page["items"])
cursor = page["cursor"]
if not cursor:
break
return chats
for chat in list_all_whatsapp_chats("Yk08cDzzdsqs9_8ds"):
print(chat["id"], chat["name"], chat["unread_count"])Lire l'historique des messages et les participants d'une discussion
Les messages les plus récents s'affichent en premier. Utilisez le même
limite et curseur modèle pour parcourir l'historique plus ancien vers l'arrière et appeler l'endpoint des participants chaque fois que vous devez déterminer qui se trouve réellement dans une chat, individuel ou de groupe.def get_chat_history(chat_id: str, limit: int = 100) -> list:
response = requests.get(
f"{BASE_URL}/chats/{chat_id}/messages",
headers=HEADERS,
params={"limit": limit},
)
response.raise_for_status()
return response.json()["items"]
def get_chat_attendees(chat_id: str) -> list:
response = requests.get(
f"{BASE_URL}/chats/{chat_id}/attendees",
headers=HEADERS,
)
response.raise_for_status()
return response.json()["items"]
messages = get_chat_history("9f9uio56sopa456s")
attendees = get_chat_attendees("9f9uio56sopa456s")Il s'agit également du chemin de code qu'exécutent réellement une synchronisation CRM ou une boîte de réception de support en Python : sur une nouvelle connexion, parcourir chaque chat une seule fois avec
lister_toutes_les_discussions_whatsapp pour alimenter votre base de données, puis de vous fier au webhook de la section précédente pour la maintenir à jour au lieu de relancer des requêtes. GET /chats l'extrémité accepte également un non lu filtre, de sorte qu'une tâche plus légère qui vérifie uniquement les chats non lus selon un calendrier n'ait pas à parcourir tout l'historique d'un compte à chaque exécution.Les groupes WhatsApp sont aussi des chats, donc la même chose
GET /chats et GET /chats/{chat_id}/attendees appels, listez-les et leurs membres depuis Python sans code supplémentaire. Pour ajouter ou supprimer un participant, ou pour récupérer le lien d'invitation, utilisez PATCH /chats/{chat_id} avec un ajouterUnParticipant, supprimerLeParticipantou obtenirLienInvitation action. La procédure complète, ainsi que les limites de participants imposées par Meta sur sa propre API Groupes, se trouve dans le guide sur ajouter ou supprimer des participants à un groupe WhatsApp.Automatisation
Comment créer un bot WhatsApp ou un agent IA en Python ?
Chaque bot WhatsApp ou agent d'IA suit les mêmes trois étapes : recevoir un message via le webhook, décider qu'en faire, et envoyer une réponse sur le même
chat_id. Rien dans les étapes un et trois ne change lorsque vous intégrez un LLM au milieu, c'est pourquoi le gestionnaire FastAPI et le envoyer_message Les fonctions des sections précédentes constituent déjà la majeure partie du code dont vous avez besoin.from openai import OpenAI # ou tout autre client LLM que vous utilisez
llm = OpenAI()
_recent_bot_replies: dict = {}
def generate_reply(incoming_text: str) -> str:
completion = llm.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "Vous êtes un agent d'assistance WhatsApp très serviable."},
{"role": "user", "content": incoming_text},
],
)
return completion.choices[0].message.content
def handle_message(event: WhatsAppMessageEvent) -> None:
if event.account_type != "WHATSAPP" or event.event != "message_received":
return
if not event.message:
return
if _recent_bot_replies.get(event.chat_id) == event.message:
return # écho de notre dernière réponse, l'ignorer
reply_text = generate_reply(event.message)
_recent_bot_replies[event.chat_id] = reply_text
send_message(event.chat_id, reply_text)Le
_réponses_récentes_du_bot la garde compte plus qu'il n'y paraît : celle d'Unipile message_received l'événement se déclenche également pour les messages envoyés par le compte lié, depuis un autre appareil ou via vos propres appels API, de sorte que sans protection, un agent peut finir par répondre à sa propre réponse. Un dictionnaire convient pour une démonstration ; un agent de production doit conserver cet état dans Redis ou dans une base de données, aux côtés de l'historique des conversations et d'une clé d'idempotence.La charge utile du webhook et le
envoyer_message les appels ont la même forme sur WhatsApp, LinkedIn, Instagram et Telegram, uniquement type_de_compte modifications, afin que le même gestionnaire FastAPI puisse acheminer les réponses d'un agent sur tous les canaux connectés par un utilisateur. La gestion du ton, du formatage et des limites de débit propres à chaque canal lors de cette opération est abordée dans le guide du API multicanal pour agents IA.La delivrabilité
Comment gérez-vous les limites de taux et les nouvelles tentatives en Python ?
Unipile renvoie un corps JSON avec un
type champ, comme erreurs/identifiants_invalides ou erreurs/compte_deconnecte, chaque fois qu'une requête échoue. Certaines valent la peine d'être réessayées, comme une connexion interrompue ou un problème temporaire du fournisseur ; d'autres, comme des identifiants incorrects, ne se corrigeront pas d'elles-mêmes, peu importe le nombre de nouvelles tentatives. La vitesse et le volume des envois depuis un seul compte WhatsApp restent une décision du client, façonnés par les limites de débit que WhatsApp impose lui-même sur ce compte, et non par un nombre fixe imposé en plus par Unipile.Le
ténacité transformez cela en un décorateur au lieu d'une boucle faite maison. Enrobez le même envoyer_message fonction de la section d'envoi avec réessai exponentiel et un nombre maximal de tentatives :# pip install tenacity
import requests
from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type
@retry(
stop=stop_after_attempt(5),
wait=wait_exponential(multiplier=1, min=2, max=30),
retry=retry_if_exception_type(requests.exceptions.HTTPError),
)
def send_message_with_retry(chat_id: str, text: str) -> dict:
response = requests.post(
f"{BASE_URL}/chats/{chat_id}/messages",
headers=HEADERS,
data={"text": text},
)
response.raise_for_status()
return response.json()Cinq tentatives avec un délai exponentiel de 2 à 30 secondes constituent une valeur par défaut raisonnable pour une tâche de fond ; réduisez le nombre de tentatives pour tout ce qui s'exécute dans un chemin de requête destiné à l'utilisateur, car
ténacité gardera sinon la requête ouverte pendant qu'elle réessaie. Le même décorateur enveloppe la version asynchrone de la section sur la concurrence, il suffit d'ajouter await où ténacité le prend en charge par AsyncRetrying.SDK
Existe-t-il un SDK Python officiel pour Unipile ?
Oui.
unipile/unipile-python est réel et activement maintenu, avec un commit poussé pas plus tard qu'au 11 août 2026. Deux choses valent la peine d'être connues avant de l'utiliser : il n'est pas encore publié sur PyPI, et il cible l'API v2 d'Unipile, qui est toujours en version bêta, alors que chaque point de terminaison utilisé dans ce guide est en v1.Activement maintenu, uniquement sur GitHub
Python 3.9+, pydantic 2.11+
Pas sur PyPI, installer depuis GitHub
Cible l'API v2 bêta, pas la v1
pip install git+https://github.com/unipile/unipile-python.gitimport unipile
configuration = unipile.Configuration()
configuration.api_key["apiKey"] = "YOUR_ACCESS_TOKEN"
api_client = unipile.ApiClient(configuration)
messaging_api = unipile.MessagingApi(api_client)Pour tout ce que ce guide couvre aujourd'hui, développez à partir des points de terminaison REST v1 avec
demandes ou httpx: elles sont stables, documentées, et c'est ce sur quoi s'exécute réellement chaque exemple de code ci-dessus. Une fois que le SDK Python sortira de la version bêta et sera publié sur PyPI, la migration consistera principalement à remplacer les appels HTTP par des méthodes de client typées, les points de terminaison et le modèle de compte connecté sous-jacent ne changeant pas. À titre de comparaison, le SDK Node.js est celui actuellement référencé dans l'index de la documentation principale d'Unipile, et l'ancien SDK PHP est archivé depuis octobre 2023.Vous construisez le même type d'intégration pour un autre canal ? Le API Instagram avec Python le guide suit le même modèle de connexion, d'envoi, de récupération et de webhook présenté dans cet article.
API WhatsApp en Python : FAQ
Des réponses directes sur les bibliothèques, la connexion, les SDK et les webhooks pour créer l'API WhatsApp en Python.
Il n'y a pas de meilleure bibliothèque unique, cela dépend de ce que vous avez déjà. Si vous êtes déjà approuvé sur l'API Cloud de Meta,
API Cloud WhatsApp vous propose un wrapper Python. Si vous souhaitez ignorer complètement la vérification Meta Business et connecter des comptes WhatsApp à la place pour le compte de vos utilisateurs, l'API REST d'Unipile appelée avec demandes ou httpx prend en charge WhatsApp ainsi que LinkedIn, Instagram et Telegram depuis une seule interface. pywhatkit il vaut la peine de l'écarter rapidement : il pilote WhatsApp Web dans un navigateur, et non une API côté serveur, il ne convient donc pas à un backend de production.Envoyer un
POST demande de /api/v1/chats/{chat_id}/messages avec un text champ et votre X-API-KEY en-tête, par exemple requests.post(url, headers=headers, data={"text": "Bonjour"}). Si vous n'avez pas de chat_id pourtant, POST /api/v1/chats avec un account_id et celui du destinataire attendees_ids crée le chat et envoie le premier message dans le même appel.Oui. La connexion d'un compte WhatsApp via Unipile nécessite uniquement que le propriétaire du compte scanne un code QR ou saisisse un code d'appairage, de la même manière que fonctionne WhatsApp Web. Il n'y a pas d'application Meta Business Platform et pas de vérification de numéro de téléphone auprès de Meta, car l'intégration fonctionne au nom de l'utilisateur authentifié plutôt que par le biais d'un numéro WhatsApp Business enregistré.
Oui,
unipile/unipile-python est un SDK officiel activement maintenu, mais il n'est pas encore sur PyPI : installez-le avec pip install git+https://github.com/unipile/unipile-python.git. Il cible également l'API v2 d'Unipile, qui est en version bêta, alors que chaque point de terminaison de ce guide utilise l'API v1 stable, de sorte que la plupart des intégrations Python actuelles sont encore construites directement sur demandes ou httpx plutôt que le kit de développement (SDK).demandes est plus simple et suffit pour les scripts, les tâches cron et les envois à faible volume. httpx vaut le détour dès lors que vous envoyez des messages à de nombreux destinataires en même temps ou que vous créez un service FastAPI asynchrone, car son AsyncClient vous permet d'envoyer plusieurs requêtes simultanément depuis la même boucle d'événements au lieu de bloquer sur chacune d'elles.Exécuter une application FastAPI en local, l'exposer avec un tunnel comme
ngrok ou cloudflared pour obtenir une URL HTTPS publique et enregistrer cette URL en tant que request_url lorsque vous créez un webhook avec source défini sur messaging. Unipile publie chaque nouveau message sur cette URL de tunnel, qui le transmet directement à votre route FastAPI locale pendant que vous développez.Oui. Les groupes WhatsApp apparaissent comme des discussions normales, donc
GET /chats et GET /chats/{chat_id}/attendees les lister ainsi que leurs membres sans traitement spécial. Pour ajouter un participant, en supprimer un ou récupérer le lien d'invitation au groupe, envoyez un PATCH /chats/{chat_id} demande avec un ajouterUnParticipant, supprimerLeParticipantou obtenirLienInvitation action, détaillée dans le guide de ajout et suppression de membres de groupes WhatsApp.Les points de terminaison sous-jacents sont identiques, la différence réside dans l'environnement d'exécution et son écosystème : Python privilégie
demandes ou httpx avec asyncio pour la concurrence et FastAPI pour les webhooks, tandis que les intégrations PHP utilisent généralement Guzzle et s'intègrent dans une application Laravel avec des tâches en arrière-plan. Si votre stack technique est en PHP, la même intégration en PHP parcourt chaque étape équivalente.Vous avez encore des questions ? Notre équipe est là pour vous aider.