Raphael Serafim· Publicado em 28 de setembro de 2026· 9 min de leitura

API do WhatsApp em Python: tutorial com a API não oficial (requests + Flask)

API do WhatsApp em Python com a API não oficial: conectar por QR Code, enviar texto, imagem e botões com requests e receber mensagens num webhook Flask.

Ver como Markdown

Para usar a API do WhatsApp em Python com a API não oficial da WAME, você só precisa de requests para enviar e de um servidor web como Flask para receber o webhook — não há SDK obrigatório nem servidor de WhatsApp para hospedar. O número conecta por QR Code, a autenticação é a key da instância na própria URL, e cada mensagem recebida chega como um POST JSON no envelope padrão da Meta.

Neste tutorial você monta, do zero, um pequeno bot em Python: conecta o número, envia texto, imagem e botões, recebe mensagens e responde com o indicador "digitando…".

O que você precisa

  • Python 3.10 ou mais recente;
  • uma instância na WAME e a sua key;
  • pip install requests flask;
  • uma URL pública para o webhook (em desenvolvimento, ngrok ou similar).

A API é hospedada e gerenciada: diferente de rodar uma biblioteca de WhatsApp Web por conta própria, você não mantém sessão, reconexão nem atualização de protocolo. Seu Python só conversa com HTTP.

Passo 1: um cliente mínimo

Comece com um módulo pequeno que centraliza a URL e a key:

python
# wame.py
import os
import requests

BASE = "https://us.api-wa.me"
KEY = os.environ["WAME_KEY"]

session = requests.Session()
session.headers.update({"Content-Type": "application/json"})


def call(method: str, path: str, **kwargs):
    url = f"{BASE}/{KEY}{path}"
    resp = session.request(method, url, timeout=30, **kwargs)
    resp.raise_for_status()
    return resp.json() if resp.content else None

Guardar a key em variável de ambiente não é detalhe: ela autentica tudo. Veja segurança de token e webhook.

Passo 2: conectar o número

Gere o QR Code:

python
from wame import call

qr = call("POST", "/instance")
print(qr)  # o formato do retorno (QR em base64, status) está em /docs

Escaneie em Aparelhos conectados no app do WhatsApp. Se estiver num servidor sem tela, prefira o código de pareamento:

python
call("POST", "/instance/pairing-code", json={"phoneNumber": "5511999999999"})

Você digita o código no celular e a instância conecta. Detalhes em conectar sem QR Code. Para conferir o estado:

python
print(call("GET", "/instance"))

Passo 3: enviar mensagens

Números sempre em formato internacional, só dígitos: DDI + DDD + número.

Texto:

python
def enviar_texto(para: str, texto: str):
    return call("POST", "/message/text", json={"to": para, "text": texto})

enviar_texto("5511999999999", "Olá! Mensagem enviada pelo Python.")

Imagem por URL:

python
def enviar_imagem(para: str, url: str, legenda: str = ""):
    return call("POST", "/message/image", json={
        "to": para,
        "url": url,
        "caption": legenda,
    })

Botões de resposta rápida:

python
def enviar_menu(para: str):
    return call("POST", "/message/button_reply", json={
        "to": para,
        "header": {"title": "Atendimento"},
        "text": "Como posso ajudar?",
        "footer": "Escolha uma opção",
        "buttons": [
            {"type": "quick_reply", "id": "pedido", "text": "Meu pedido"},
            {"type": "quick_reply", "id": "suporte", "text": "Suporte"},
            {"type": "quick_reply", "id": "humano", "text": "Falar com alguém"},
        ],
    })

Botões, listas, enquete e figurinha estão entre os recursos que a camada não oficial libera por conectar como o WhatsApp Web — veja todos em recursos da API não oficial.

Uma observação prática: mensagens interativas funcionam melhor em conversas já iniciadas. Se o contato nunca falou com o seu número, abra com um texto antes do menu. O motivo está em aquecer número na API não oficial.

Passo 4: configurar o webhook

Aponte a instância para a sua URL, no formato meta:

python
call("PUT", "/instance", json={
    "allowWebhook": True,
    "allowNumber": "all",
    "webhookMessage": "https://seu-dominio.com/webhook/wame",
    "webhookFormat": "meta",
})

No formato meta, cada mensagem chega no mesmo envelope da Meta Cloud API:

json
{
  "object": "wame",
  "provider": "whatsapp",
  "entry": [{
    "changes": [{
      "field": "messages",
      "value": {
        "messages": [{
          "from": "5511999999999",
          "id": "wamid.XXXX",
          "type": "text",
          "text": { "body": "oi, quero saber do meu pedido" }
        }]
      }
    }]
  }]
}

Passo 5: receber no Flask

O extrator, com as guardas que evitam os bugs mais comuns:

python
def extrair(body: dict):
    try:
        msg = body["entry"][0]["changes"][0]["value"]["messages"][0]
    except (KeyError, IndexError, TypeError):
        return None  # status de entrega e outros eventos não têm "messages"

    if msg.get("type") != "text":
        return None

    return {
        "de": msg["from"],
        "texto": msg["text"]["body"],
        "id": msg["id"],
    }

E o servidor. A regra de ouro: responda 200 imediatamente e processe depois. Webhook que demora é reenviado, e o cliente recebe a resposta duas vezes.

python
# app.py
import threading
from flask import Flask, request
from wame import call

app = Flask(__name__)
processadas = set()  # em produção, use Redis ou banco


@app.post("/webhook/wame")
def webhook():
    msg = extrair(request.get_json(silent=True) or {})
    if msg and msg["id"] not in processadas:
        processadas.add(msg["id"])
        threading.Thread(target=responder, args=(msg,), daemon=True).start()
    return "", 200

Passo 6: responder com "digitando…"

Resposta instantânea parece robô. Mostre "digitando…" por um tempo proporcional ao texto antes de enviar:

python
import random
import time


def responder(msg: dict):
    texto = msg["texto"].lower()

    if "pedido" in texto:
        resposta = "Me passa o número do pedido que eu confiro pra você."
    elif "humano" in texto or "atendente" in texto:
        resposta = "Certo! Já chamo alguém do time."
    else:
        enviar_menu(msg["de"])
        return

    call("POST", "/message/presence", json={"to": msg["de"], "status": "composing"})
    time.sleep(min(6, 1 + len(resposta) / 18) * random.uniform(0.8, 1.2))
    call("POST", "/message/text", json={"to": msg["de"], "text": resposta})

A WAME já aplica tempo humano e limites de ritmo na camada de conexão; o indicador "digitando…" é a parte visível para o cliente, e melhora a experiência. Veja também como simular digitando pela API.

Levando para produção

O código acima funciona, mas três mudanças separam o protótipo do sistema real:

  1. Servidor WSGI. Rode com gunicorn app:app, não com o servidor de desenvolvimento do Flask.
  2. Fila em vez de thread. Thread solta perde trabalho quando o processo reinicia. Use RQ, Celery ou uma fila no Redis: o webhook só enfileira e responde 200; um worker processa.
  3. Idempotência persistente. O set() em memória some no restart. Guarde os ids tratados em Redis com expiração. O artigo webhook em produção mostra o padrão completo.

Para envios iniciados por você — lembretes, notificações — coloque os envios numa fila com intervalo entre eles, em vez de um for com requests.post. O motivo e o desenho estão em fila, rate limit e retry.

Usando com responsabilidade

A API não oficial é estável e a taxa de bloqueio é muito baixa para quem usa do jeito certo: responder quem chamou, notificar cliente, atender. A WAME não apoia spam — um script Python que percorre uma lista de números desconhecidos é exatamente o que derruba números. Leia uso responsável da API não oficial antes de automatizar envios ativos.

A camada não oficial não é afiliada ao WhatsApp nem à Meta, e o uso é de responsabilidade de quem envia. Se precisar de garantia formal da Meta, compare com a API oficial.

Conclusão

Integrar WhatsApp em Python com a API não oficial da WAME é HTTP puro: requests para enviar texto, imagem e botões, Flask para receber o webhook no envelope da Meta, e um endpoint de presença para o "digitando…". Conecte por QR Code ou código de pareamento, responda 200 na hora, processe em fila e ignore duplicatas. O resto — sessão, reconexão, uptime — fica com a plataforma. A referência completa de endpoints está na documentação.

Pronto para automatizar seu WhatsApp?

Crie sua conta gratuita e comece a enviar mensagens pela API em minutos.

Começar grátis

Perguntas frequentes

Existe biblioteca Python para a API do WhatsApp da WAME?+

Você não precisa de biblioteca específica. A API é REST: com o pacote requests você envia mensagens, e com Flask (ou FastAPI, Django) você recebe o webhook. A autenticação é a key da instância na própria URL, sem header extra.

Como conecto meu número usando Python?+

Faça requests.post para https://us.api-wa.me/SUA_KEY/instance para gerar o QR Code e escaneie em Aparelhos conectados no celular. Se preferir não usar QR, envie o número para /instance/pairing-code e digite o código no próprio WhatsApp.

Como recebo mensagens do WhatsApp em Python?+

Configure a URL do webhook da instância com PUT /instance e formato meta. Cada mensagem chega como POST JSON no envelope da Meta Cloud API; no Flask você lê request.get_json(), extrai entry → changes → value → messages e responde 200 imediatamente.

Por que meu bot em Python responde duas vezes a mesma mensagem?+

Normalmente porque o webhook demorou para responder e o evento foi reenviado. Responda 200 na hora, processe em segundo plano (thread, fila ou worker) e guarde os ids das mensagens já tratadas para ignorar duplicatas.

A API não oficial funciona com Python em produção?+

Sim. A infraestrutura é hospedada e gerenciada pela WAME, com 99,9% de uptime; seu código Python só faz chamadas HTTP. Para produção, rode o Flask atrás de um servidor WSGI como gunicorn e use uma fila para o processamento.

Continue lendo