---
title: "API do WhatsApp em Python: tutorial com a API não oficial (requests + Flask)"
description: "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."
url: "https://wame.api.br/blog/api-whatsapp-python-nao-oficial"
language: "pt-BR"
og:type: "article"
published_time: "2026-09-28"
modified_time: "2026-09-28"
author: "Raphael Serafim"
keywords: "api whatsapp não oficial, api não oficial whatsapp, api whatsapp python, whatsapp python, enviar mensagem whatsapp python, webhook whatsapp flask, bot whatsapp python"
reading_time: "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.

**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://server.wame.api.br"
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](/blog/seguranca-api-whatsapp-token-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](/blog/conectar-whatsapp-codigo-pareamento-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](/blog/api-nao-oficial-whatsapp-recursos-exemplos).

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](/blog/aquecer-numero-whatsapp-api-nao-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](/blog/tutorial-presenca-digitando-whatsapp-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](/blog/webhook-producao-assinatura-retry-idempotencia) 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](/blog/fila-rate-limit-retry-disparo-whatsapp).

## 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](/blog/uso-responsavel-api-whatsapp-nao-oficial-spam) 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](/blog/whatsapp-api-oficial-vs-nao-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](/docs).

## 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://server.wame.api.br/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.
