Índice
Empezando
Conectar y enviar
Recibir y Automatizar
API de WhatsApp con PythonEnviar, recibir y automatizar mensajes
Todo lo que necesitas para usar el API de WhatsApp en Python: qué biblioteca elegir, cómo conectar una cuenta vinculada con un código QR, cómo enviar y recibir mensajes con
solicita y httpx, y cómo conectar un webhook de FastAPI para un bot o un agente de inteligencia artificial. API REST hoy, sin necesidad de verificación de Meta Business
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", "¡Hola desde Python!")200 OK, mensaje enviado
Definición
¿Qué es la API de WhatsApp en Python?
En API de WhatsApp en Python significa llamar a la mensajería de WhatsApp Business desde código de Python en lugar de hacer clic en WhatsApp Web. Un script de Python o un servicio de backend envía una solicitud HTTP, generalmente con
solicita o httpx, a una API REST que expone chats, mensajes y webhooks, ya sea la API en la nube de Meta directamente o un proveedor unificado como Unipile que conecta WhatsApp junto con LinkedIn, Instagram y Telegram detrás de una sola interfaz. Meta no publica un SDK oficial de Python todo en uno para WhatsApp, razón por la cual casi todas las integraciones de Python en esta guía, y la mayor parte de lo que encontrará en el resto de la web, se comunican directamente con los endpoints REST.Una API REST para WhatsApp, LinkedIn, Instagram y Telegram
Vinculado con un código QR o un código de emparejamiento, sin verificación de Meta Business
solicita para scripts sencillos, httpx para asincronía a escala Para la capa de orientación, acceso, costo y límites, comience con el Guía de acceso, costos y límites de la API de WhatsApp. ¿Construir en PHP en lugar de Python?
Lee la misma integración en PHP Antes de construir
¿Qué necesitas antes de empezar?
No necesitas una cuenta de Meta Business ni la aprobación de WhatsApp Business Platform para empezar a enviar y recibir mensajes desde Python. Necesitas un entorno de Python operativo, un cliente HTTP, un lugar para recibir webhooks y una cuenta de Unipile.
Python 3.9+
Coincide con la versión mínima requerida por el propio SDK de Python de Unipile
pydantic dependencia, y por moderno httpx y lanzamientos de FastAPI.requests o httpx
Un túnel local
Una herramienta como
ngrok o cloudflared para exponer tu ruta de webhook de FastAPI en una URL HTTPS pública mientras desarrollas.Token de acceso y DSN
Ambos provienen del panel de control de Unipile. El DSN es el host al que llamas, el Token de Acceso va en el
X-API-KEY cabecera de cada solicitud.Comparación de bibliotecas
¿Qué biblioteca de Python deberías usar para WhatsApp?
No hay una sola respuesta obvia y la mayoría de las publicaciones de blogs sobre este tema promocionan el paquete que mantiene su autor. Aquí tienes una comparación objetiva de las cinco formas en que los desarrolladores de Python realmente llaman a WhatsApp hoy en día, desde la automatización de navegadores hasta un proveedor unificado, para que puedas elegir según lo que cada opción realmente hace, y no basándote en el marketing.
Biblioteca / enfoque
Lo que realmente llama
Verificación comercial de Meta
Mantenido
Mejor para
pywhatkit
Controla WhatsApp Web en una pestaña del navegador (automatización de teclado), no una API del lado del servidor
N/D, sin API
Comunidad, esporádico
Scripts únicos y demos en una máquina con pantalla, no para producción
whatsapp-cloud-api
Delgado contenedor en Python para los propios endpoints de la API de WhatsApp Cloud de Meta
Requerido
Contenedor de la comunidad
Equipos ya aprobados en Cloud API que quieren un cliente en Python
whatsapp-api-client-python
Llama al SaaS de green-api, que a su vez mantiene la sesión de WhatsApp
No es necesario
Mantenido por el proveedor
Equipos cómodos dependiendo de un segundo proveedor de SaaS de propósito único
solicitudes, directo a Meta
Endpoints de la API en la nube de Meta, sin ningún contenedor
Requerido
Hazlo tú mismo
Equipos que ya cuentan con la verificación comercial de Meta aprobada y que desean un control total
Unipile, requests o httpx
API de mensajería unificada de Unipile, WhatsApp junto con LinkedIn, Instagram y Telegram
No es necesario
Mantenido activamente, SDK de Python en fase beta
Productos SaaS que conectan muchas cuentas de WhatsApp de usuarios finales en nombre de cada usuario
pywhatkit
LlamadasControla WhatsApp Web en una pestaña del navegador, no una API del lado del servidor
Verificación de MetaN/D, sin API
MantenidoComunidad, esporádico
Mejor paraScripts puntuales y demostraciones, no para producción
whatsapp-cloud-api
LlamadasLigera capa alrededor de los propios puntos de conexión de la API en la nube de Meta
Verificación de MetaRequerido
MantenidoContenedor de la comunidad
Mejor paraEquipos ya aprobados en la Cloud API
whatsapp-api-client-python
LlamadasEl SaaS green-api, que mantiene la sesión de WhatsApp
Verificación de MetaNo es necesario
MantenidoMantenido por el proveedor
Mejor paraEquipos cómodos con un segundo proveedor de SaaS
solicitudes, directo a Meta
LlamadasEndpoints de la API de Cloud de Meta, sin contenedores
Verificación de MetaRequerido
MantenidoHazlo tú mismo
Mejor paraEquipos ya aprobados para la verificación de Meta Business
Unipile, requests o httpx
LlamadasAPI de mensajería unificada, WhatsApp con LinkedIn, Instagram, Telegram
Verificación de MetaNo es necesario
MantenidoMantenido activamente, SDK de Python en fase beta
Mejor paraProductos SaaS que conectan muchas cuentas de usuarios finales
Cada opción que mantiene Verificación de Meta Business requerida en última instancia, se comunica con la propia API de WhatsApp Cloud de Meta (ver Documentación de la Plataforma de WhatsApp Business de Meta), lo cual es la decisión correcta si ya opera con un número de empresa verificado. Si en su lugar conecta cuentas de WhatsApp en nombre de muchos usuarios finales diferentes, un flujo de código QR o de emparejamiento elimina por completo ese paso de verificación, que es el modelo que utiliza el resto de esta guía.
Conexión de cuentas
¿Cómo se conecta una cuenta de WhatsApp en Python?
Cada llamada de esta guía se ejecuta en nombre de un usuario autenticado que vinculó su propia cuenta de WhatsApp. No hay un paso de verificación de Meta Business: desde Python, envías un único
POST /api/v1/accounts solicitud con provider establecer en WHATSAPP, y el usuario confirma el enlace escaneando un código QR o introduciendo un código de emparejamiento en su teléfono.Opción A: Código QR (predeterminado)
Vete
vinculación_de_número_de_teléfono fuera del cuerpo de la solicitud y Unipile devuelve un punto de control que contiene la carga útil del código QR. Renderícelo con una biblioteca como código QR y muéstrala para que el usuario la escanee desde WhatsApp > Dispositivos vinculados.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 contiene un nuevo account_id y un objeto de punto de control.
# Genera el punto de control como un código QR y pide al usuario que lo escanee
# desde WhatsApp > Dispositivos vinculados.Opción B: código de emparejamiento
Pasar
vinculación_de_número_de_teléfono en dígitos E.164 únicamente, código de país primero, sin signo más, sin espacios. Unipile devuelve un punto de control que lleva un código corto que el usuario escribe en WhatsApp en lugar de escanear nada, lo cual se adapta mejor a un servidor headless sin pantalla para mostrar un código 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()
# Código de país + número, solo dígitos; p. ej., Francia
account = connect_whatsapp_pairing_code("33612345678")
# El objeto "account" contiene el código de emparejamiento que debe mostrarse en tu interfaz de usuario.
# El usuario lo introduce en WhatsApp > Dispositivos vinculados > Vincular con número de teléfono.Confirme que la cuenta está conectada
Una vez que el usuario escanea el código QR o escribe el código de emparejamiento, necesitas saber cuándo la cuenta está realmente lista para enviar y recibir. Unipile te ofrece dos opciones.
Consultar el estado de la cuenta
Llamar
GET /api/v1/accounts/{account_id} cada pocos segundos hasta que la cuenta ya no necesite su punto de control. Simple, pero desperdicia peticiones mientras esperas.Webhook de estado de cuenta
Registrar un webhook con
fuente establecer en estado_de_cuenta (igual POST /api/v1/webhooks punto de extremo utilizado para los mensajes) y Unipile envía {"AccountStatus": {"account_id": "...", "message": "OK"}} en el instante en que la cuenta esté lista. Esto es lo que usan la mayoría de las integraciones de producción.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) #: comprueba la carga útil en tiempo real para tu propia comprobación de estado
time.sleep(2)
raise TimeoutError("La cuenta de WhatsApp no ha confirmado la conexión a tiempo")Enviar
¿Cómo se envía un mensaje de WhatsApp con Python?
Enviar un mensaje de WhatsApp desde Python es una sola llamada HTTP:
POST /api/v1/chats/{chat_id}/messages, con el chat_id ya tienes de la lista de chats o de un webhook entrante, y un text campo. El "endpoint" acepta cuerpos codificados en formulario y en formato JSON por igual, por lo que un simple requests.post con datos= funciona sin configuración adicional.Si no existe
chat_id, por ejemplo, el primer mensaje a un nuevo contacto, llamada POST /api/v1/chats en su lugar con un account_id y el del destinatario attendees_ids; Unipile crea el chat 1:1 y envía el mensaje en la misma solicitud.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()Los tipos de mensajes (texto, multimedia, notas de voz, plantillas) y la ventana de atención al cliente de 24 horas son un tema propio, tratado en detalle en la guía de tipos de mensajes que admite la API de WhatsApp. Esta sección solo cubre la fontanería de Python.
Meta factura los mensajes de la API de WhatsApp por mensaje enviado, no por conversación, desde julio de 2025. Ver cómo funciona el precio de la API de WhatsApp por mensaje para consultar las tarifas actuales por país.
Concurrencia
¿Cómo se envían mensajes de WhatsApp de forma asíncrona en Python?
Cuando envías a muchos destinatarios a la vez, una difusión, un vaciado de cola, un trabajo de seguimiento masivo, un bucle que espera uno
requests.post a la vez es el cuello de botella, no la API. httpx.AsyncClient combinado con asyncio.gather dispara muchas solicitudes de forma concurrente desde un solo bucle de eventos, sin necesidad de hilos. Un semáforo es lo que te mantiene siendo un buen ciudadano: las cuentas de WhatsApp siguen estando sujetas a los propios límites de velocidad de la plataforma, por lo que una concurrencia sin límites solo cambia un bucle lento por un muro de respuestas 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", "¡Tu pedido ha sido enviado!"),
("a1b2c3d4e5f6g7h8", "¡Tu pedido ha sido enviado!"),
]
results = asyncio.run(send_bulk(messages))
for chat_id_text, result in zip(messages, results):
if isinstance(result, Exception):
print("falló:", chat_id_text[0], result)Conservar
LÍMITE_DE_CONCURRENCIA conservador y súbelo solo después de haber visto las tasas de errores reales. return_exceptions=True significa que un envío fallido no cancela el resto del lote, lo cual importa una vez que estás disparando cientos de mensajes en una sola ejecución. La sección de límite de velocidad y reintentos a continuación se basa en este mismo patrón.Webhooks
¿Cómo se reciben los mensajes de WhatsApp con un webhook de FastAPI?
Un webhook es la forma en que tu servicio en Python se entera de un nuevo mensaje de WhatsApp en el momento en que llega, en lugar de consultar constantemente. Registras un punto de enlace (endpoint) en Unipile, y cada evento correspondiente se entrega a tu servidor en formato JSON. FastAPI se adapta perfectamente al lado receptor: un
pydantic el modelo valida el pago por ti, y Tareas en segundo plano permite que tu ruta devuelva una respuesta inmediatamente mientras el trabajo real, llamar a un modelo, escribir en una base de datos, ocurre después.1. Registrar el webhook
Punto
URL_solicitud en tu ruta de FastAPI. Durante el desarrollo local, eso significa la URL HTTPS que expone tu túnel (de la sección de requisitos previos anterior), no 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. Recíbelo en FastAPI
El payload que envía Unipile transporta el chat, el remitente y el texto del mensaje como campos planos, además de una lista de archivos adjuntos cuando los hay. Modela solo lo que necesites; Pydantic ignora los campos adicionales por defecto.
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
id_del_proveedor_del_asistente: str
clase Attachment(BaseModel):
id: str
tipo: str
tipo_MIME: Optional[str] = None
no_disponible: 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
remitente: Remitente
archivos adjuntos: Lista[Archivo adjunto] = []
def gestionar_mensaje(evento: WhatsAppMessageEvent) -> None:
si evento.tipo_de_cuenta != "WHATSAPP" o evento.evento != "message_received":
return
# Unipile incluye los mensajes que la propia cuenta vinculada ha enviado, ya sea desde
# otro dispositivo o a través de tus propias llamadas a la API. Compara el remitente
# con el titular de la cuenta que guardaste en el momento de la conexión si
# solo quieres reaccionar a los mensajes que provienen de la otra parte.
print(f"Nuevo mensaje de WhatsApp en el chat {event.chat_id}: {event.message}")
# reenvía desde aquí a tu cola, a tu base de datos o a un agente de IA
@app.post("/webhooks/whatsapp")
async def whatsapp_webhook(
event: WhatsAppMessageEvent,
background_tasks: BackgroundTasks,
):
background_tasks.add_task(handle_message, event)
return {"status": "received"}Ejecútalo con
uvicorn main:app --reload, apunta tu túnel al puerto 8000 y registra esa URL pública como URL_solicitud en el paso 1. Devolución {"status": "received"} importa antes de que el mensaje sea procesado por completo: Unipile espera una respuesta rápida y Tareas en segundo plano es lo que mantiene manejar_mensaje de bloquearlo.Otra cosa que vale la pena incorporar desde el principio: almacenar cada procesado
id_de_mensaje antes de actuar en consecuencia, y omite cualquier cosa que ya hayas visto. Si la cuenta de WhatsApp vinculada se desconecta y se vuelve a conectar, Unipile entrega los mensajes que llegaron durante ese intervalo una vez que se pone al día, y un nuevo despliegue o una tarea en segundo plano caída pueden hacer por separado que tu propio controlador vea el mismo evento dos veces, por lo que tratar id_de_mensaje cómo una clave de idempotencia evita que un bot de WhatsApp responda dos veces.Leer
¿Cómo se recuperan los chats y el historial de mensajes en Python?
Cada punto de acceso de lista en la API de Unipile, chats, mensajes, asistentes, está paginado de la misma manera: la respuesta incluye un
artículos matriz y un cursor. Pásame eso cursor de vuelta en la próxima llamada, y detenerse una vez que regrese null. de Python mientras True el bucle se mapea directamente en ese patrón.Listar todos los chats de WhatsApp de una cuenta
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"])Lee el historial de mensajes y los asistentes de un chat
Los mensajes más recientes aparecen primero. Utiliza el mismo
límite y cursor patrón para retroceder en el historial más antiguo y llamar al punto de conexión de asistentes siempre que necesite resolver quién está realmente en un chat, individual o grupal.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")Este es también el código que una sincronización de CRM o una bandeja de entrada de soporte ejecutan realmente en Python: en una conexión nueva, recorrer cada chat una vez con
listar_todos_los_chats_de_whatsapp para inicializar tu base de datos y luego confiar en el webhook de la sección anterior para mantenerla actualizada en lugar de volver a consultar. GET /chats el endpoint también acepta un no leído filtro, de modo que un trabajo más ligero que solo comprueba los chats no leídos según una programación no tenga que recorrer todo el historial de la cuenta cada vez que se ejecute.Los grupos de WhatsApp también son chats, así que lo mismo
GET /chats y GET /chats/{chat_id}/attendees llamadas, lista de ellas y sus miembros desde Python sin código adicional. Para agregar o eliminar a un participante, o para obtener el enlace de invitación, usa PATCH /chats/{chat_id} con un agregarParticipante, eliminarParticipanteo obtenerEnlaceDeInvitacion acción. La guía completa, junto con los límites de participación propios de Meta en su API nativa de Grupos, se encuentra en la guía para añadir o eliminar participantes de un grupo de WhatsApp.Automatización
¿Cómo se crea un bot de WhatsApp o un agente de inteligencia artificial en Python?
Todo bot de WhatsApp o agente de inteligencia artificial sigue los mismos tres pasos: recibir un mensaje a través del webhook, decidir qué hacer con él y enviar una respuesta al mismo
chat_id. Nada sobre los pasos uno y tres cambia cuando pones un LLM en el medio, razón por la cual el manejador de FastAPI y el enviar_mensaje Las funciones de las secciones anteriores ya son la mayor parte del código que necesitas.from openai import OpenAI # o cualquier cliente LLM que utilices
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": "Eres un agente de asistencia de WhatsApp muy servicial."},
{"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 #: eco de nuestra última respuesta, ignóralo
reply_text = generate_reply(event.message)
_recent_bot_replies[event.chat_id] = reply_text
send_message(event.chat_id, reply_text)En
_respuestas_recientes_del_bot la guardia importa más de lo que parece: la de Unipile mensaje_recibido el evento se dispara también para los mensajes que envía la cuenta vinculada, desde otro dispositivo o desde tus propias llamadas a la API, por lo que sin una protección un agente puede terminar respondiendo a su propia respuesta. Un diccionario está bien para una demo; un agente de producción debe mantener ese estado en Redis o en una base de datos junto con el historial de conversación y una clave de idempotencia.El payload del webhook y el
enviar_mensaje las llamadas tienen la misma forma en WhatsApp, LinkedIn, Instagram y Telegram, solamente tipo_de_cuenta cambios, para que el mismo gestor de FastAPI pueda enrutar las respuestas de un agente a través de todos los canales a los que se conectó un usuario. Mantener correctos el tono, el formato y los límites de tasa específicos de cada canal al hacer eso se cubre en la guía sobre el API multicanal para agentes de IA.Fiabilidad
¿Cómo manejas los límites de velocidad y los reintentos en Python?
Unipile devuelve un cuerpo JSON con un
tipo campo, como errores/credenciales_invalidas o errors/disconnected_account, siempre que una solicitud falla. Algunas de ellas vale la pena reintentarlas, como una conexión interrumpida o un problema temporal del proveedor; otras, como credenciales incorrectas, no se solucionarán por sí mismas sin importar cuántas veces vuelva a llamar. La velocidad y la cantidad que envíe desde una sola cuenta de WhatsApp sigue siendo una decisión del cliente, moldeada por los límites de velocidad que el propio WhatsApp impone a esa cuenta, y no un número fijo que Unipile imponga adicionalmente.En
tenacidad empaqueta eso convirtiéndolo en un decorador en lugar de un bucle hecho a mano. Envuelve lo mismo enviar_mensaje función de la sección de envío con retroceso exponencial y un recuento de intentos limitado:# 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 enviar_mensaje_con_reintento(id_chat: str, texto: str) -> dict:
response = requests.post(
f"{BASE_URL}/chats/{chat_id}/messages",
headers=HEADERS,
data={"text": text},
)
response.raise_for_status()
return response.json()Cinco intentos con un retroceso exponencial de 2 a 30 segundos es un valor predeterminado sensato para una tarea en segundo plano; reduzca el número de intentos para cualquier cosa que se ejecute en una ruta de solicitud orientada al usuario, ya que
tenacidad mantendrá la solicitud abierta mientras se reintenta. El mismo decorador envuelve la versión asíncrona de la sección de concurrencia, solo agregue await dónde tenacidad lo apoya a través de AsyncRetrying.SDK
¿Existe un SDK oficial de Python para Unipile?
Sí.
unipile/unipile-python es real y se mantiene activamente, con una confirmación de cambios enviada tan recientemente como el 11 de agosto de 2026. Hay dos cosas que vale la pena saber antes de recurrir a ella: aún no está publicada en PyPI y apunta a la API v2 de Unipile, que todavía está en fase beta, mientras que cada extremo utilizado en esta guía es v1.Mantenido activamente, solo en GitHub
Python 3.9+, pydantic 2.11+
No está en PyPI, instálalo desde GitHub
Dirigido a la API v2 beta, no a 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)Para todo lo que esta guía cubre hoy, amplía los endpoints REST de la v1 con
solicita o httpxson estables, están documentadas y son sobre las que realmente se ejecuta cada ejemplo de código anterior. Una vez que el SDK de Python salga de la fase beta y llegue a PyPI, migrar significará principalmente cambiar las llamadas HTTP por métodos de cliente tipados; los endpoints y el modelo de cuentas conectadas subyacente no cambian. A modo de comparación, el SDK de Node.js es el que se referencia actualmente en todo el índice de documentación principal de Unipile, y el antiguo SDK de PHP ha estado archivado desde octubre de 2023.¿Construyendo el mismo tipo de integración para otro canal? El API de Instagram con Python la guía sigue el idéntico patrón de conectar, enviar, recuperar y webhook mostrado en este artículo.
API de WhatsApp en Python: Preguntas frecuentes
Respuestas directas sobre bibliotecas, conexión, SDKs y webhooks para construir la API de WhatsApp en Python.
No hay una sola mejor biblioteca, depende de lo que ya tengas. Si ya estás aprobado en la API en la nube de Meta,
whatsapp-cloud-api te ofrece una interfaz en Python. Si deseas omitir por completo la verificación de Meta Business y en su lugar conectar cuentas de WhatsApp en nombre de tus usuarios, la API REST de Unipile invocada con solicita o httpx cubre WhatsApp junto con LinkedIn, Instagram y Telegram desde una sola interfaz. pywhatkit vale la pena descartarlo pronto: funciona mediante WhatsApp Web en un navegador, no con una API del lado del servidor, por lo que no se adapta a un backend de producción.Enviar un
POST solicitud para /api/v1/chats/{chat_id}/mensajes with a text campo y tu X-API-KEY encabezado, por ejemplo requests.post(url, headers=headers, data={"text": "Hola"}). Si no tienes un chat_id todavía, POST /api/v1/chats con un account_id y el del destinatario attendees_ids crea el chat y envía el primer mensaje en la misma llamada.Sí. Conectar una cuenta de WhatsApp a través de Unipile solo requiere que el propietario de la cuenta escanee un código QR o introduzca un código de vinculación, de la misma manera que funciona WhatsApp Web. No hay ninguna aplicación de Meta Business Platform ni verificación de número de teléfono con Meta, porque la integración se ejecuta en nombre del usuario autenticado en lugar de a través de un número de WhatsApp Business registrado.
Sí,
unipile/unipile-python es un SDK oficial mantenido activamente, pero aún no está en PyPI: instálalo con pip install git+https://github.com/unipile/unipile-python.git. También apunta a la API v2 de Unipile, que está en fase beta, mientras que cada extremo de esta guía utiliza la API v1 estable, por lo que la mayoría de las integraciones en Python de hoy en día todavía se basan directamente en solicita o httpx en lugar del SDK.solicita es más simple y suficiente para scripts, tareas cron y envíos de bajo volumen. httpx vale la pena hacer el cambio una vez que estás enviando a muchos destinatarios a la vez o construyendo un servicio FastAPI asíncrono, porque su AsyncClient te permite disparar múltiples solicitudes de forma concurrente desde el mismo bucle de eventos en lugar de bloquearse en cada una.Ejecutar una aplicación FastAPI localmente, exponerla con un túnel como
ngrok o cloudflared para obtener una URL pública HTTPS y registrar esa URL como URL_solicitud cuando creas un webhook con fuente establecer en messaging. Unipile publica cada mensaje nuevo en esa URL de túnel, que lo reenvía directamente a tu ruta de FastAPI local mientras desarrollas.Sí. Los grupos de WhatsApp aparecen como chats normales, así que
GET /chats y GET /chats/{chat_id}/attendees enuméralos y a sus miembros sin distinción de mayúsculas y minúsculas. Para añadir un participante, eliminar uno o obtener el enlace de invitación del grupo, envía un PATCH /chats/{chat_id} solicitud con un agregarParticipante, eliminarParticipanteo obtenerEnlaceDeInvitacion acción, detallada en la guía para añadir y eliminar miembros de grupos de WhatsApp.Los puntos de conexión subyacentes son idénticos, la diferencia es el tiempo de ejecución y su ecosistema: Python favorece
solicita o httpx con asyncio para concurrencia y FastAPI para webhooks, mientras que las integraciones en PHP típicamente usan Guzzle y encajan en una aplicación de Laravel con trabajos en cola. Si tu pila tecnológica es PHP, la misma integración en PHP recorre cada paso equivalente.¿Aún tiene preguntas? Nuestro equipo está aquí para ayudarle.