Skip to main content

No project description provided

Project description

django-whatsapp-api-wrapper

Importante: Esta biblioteca está em desenvolvimento ativo e ainda não possui cobertura de testes automatizados. As APIs podem mudar entre versões menores. Utilize com cautela em produção, valide os fluxos críticos e, se possível, contribua com issues/PRs.

Um wrapper simples para enviar mensagens via WhatsApp Cloud API e expor um endpoint de webhook, pronto para integrar em qualquer projeto Django.

Instalação

python -m pip install django-whatsapp-api-wrapper

Configuração (Django)

  1. Adicione o app em INSTALLED_APPS:
INSTALLED_APPS = [
    # ...
    "django_whatsapp_api_wrapper",
]
  1. Inclua as URLs no urls.py principal:
from django.urls import path, include

urlpatterns = [
    # ...
    path("whatsapp-api-wrapper/", include("django_whatsapp_api_wrapper.urls")),
]
  1. Defina as variáveis de ambiente (ou no seu .env):
WHATSAPP_CLOUD_API_TOKEN=
WHATSAPP_CLOUD_API_PACKAGE_VERSION=0.1.1
WHATSAPP_CLOUD_API_VERSION=v23.0
WHATSAPP_CLOUD_API_PHONE_NUMBER_ID=
WHATSAPP_CLOUD_API_WABA_ID=
WHATSAPP_CLOUD_API_VERIFY_TOKEN=
  1. Configure a autenticação para as rotas de templates (opcional, mas recomendado):
# settings.py

# Opção 1: Usar Token Authentication do DRF (padrão)
WHATSAPP_API_AUTHENTICATION_CLASSES = [
    'rest_framework.authentication.TokenAuthentication',
]

# Opção 2: Usar JWT (se você já tem configurado)
WHATSAPP_API_AUTHENTICATION_CLASSES = [
    'rest_framework_simplejwt.authentication.JWTAuthentication',
]

# Opção 3: Usar API Key simples
WHATSAPP_API_AUTHENTICATION_CLASSES = [
    'django_whatsapp_api_wrapper.authentication.APIKeyAuthentication',
]
WHATSAPP_API_KEY = "sua_api_key_secreta_aqui"

# Permissões (padrão: IsAuthenticated)
WHATSAPP_API_PERMISSION_CLASSES = [
    'rest_framework.permissions.IsAuthenticated',
]

Importante: Se não configurar a autenticação, as rotas de templates usarão TokenAuthentication por padrão. As rotas de mensagens herdam a mesma configuração.

O endpoint de webhook ficará disponível em:

  • GET/POST: /whatsapp-api-wrapper/webhook/
  • Verificação (GET): /whatsapp-api-wrapper/webhook/?hub.mode=subscribe&hub.verify_token=<TOKEN>&hub.challenge=123

Extensibilidade do Webhook

Você pode customizar o processamento do webhook no projeto hospedeiro de duas formas:

  • Via setting com handler plugável:
# settings.py
WHATSAPP_WEBHOOK_HANDLER = "meuapp.whatsapp.handle_webhook"
# meuapp/whatsapp.py
from django.http import JsonResponse

def handle_webhook(request, payload):
    # sua lógica aqui (salvar eventos, acionar tasks, etc)
    return JsonResponse({"ok": True})
  • Via signal webhook_event_received:
from django.dispatch import receiver
from django_whatsapp_api_wrapper.signals import webhook_event_received

@receiver(webhook_event_received)
def on_whatsapp_event(sender, payload, request, **kwargs):
    # sua lógica aqui
    pass

Mensagens

Envio e recebimento de mensagens via Cloud API.

Envio (Python)

from django_whatsapp_api_wrapper import WhatsApp
from django_whatsapp_api_wrapper.messages import types as WATypes

wp = WhatsApp()

# Texto (construa o objeto e passe o objeto diretamente)
text = WATypes.Text(body="olá do wrapper", preview_url=False)
m_text = wp.build_message(to="551199999999", type="text", data=text)
m_text.send()

# Template
tpl = WATypes.Template(name="opa", language={"code": "pt_BR"}, components=[])
m_tpl = wp.build_message(to="551199999999", type="template", data=tpl)
m_tpl.send()

# Sticker (exemplo com media ID)
stk = WATypes.Sticker(id="MEDIA_ID")
m_stk = wp.build_message(to="551199999999", type="sticker", data=stk)
m_stk.send()

# Imagem por URL
img = WATypes.Image(link="https://exemplo.com/foto.jpg", caption="Legenda")
m_img = wp.build_message(to="551199999999", type="image", data=img)
m_img.send()

Webhook

  • Recebe eventos (mensagens/atualizações de status) em GET/POST /whatsapp-api-wrapper/webhook/.
  • Verificação (GET): /whatsapp-api-wrapper/webhook/?hub.mode=subscribe&hub.verify_token=<TOKEN>&hub.challenge=123.
  • Personalize via setting WHATSAPP_WEBHOOK_HANDLER ou escute o signal webhook_event_received (veja seção Extensibilidade do Webhook acima).

Endpoints HTTP de Mensagens (DRF)

Prefixo base: /whatsapp-api-wrapper/messages/

⚠️ Importante: Todos os endpoints de mensagens requerem autenticação (veja seção Autenticação acima).

  1. Enviar mensagem (genérico)

POST /whatsapp-api-wrapper/messages/send/

Body (exemplos por tipo):

Texto

{ "to": "551199999999", "type": "text", "text": {"preview_url": false, "body": "Olá!"} }

Texto (reply)

{ "to": "551199999999", "type": "text", "context": {"message_id": "wamid.xxx"}, "text": {"body": "Resposta"} }

Template

{ "to": "551199999999", "type": "template", "template": {"name": "opa", "language": {"code": "pt_BR"}, "components": []} }

Imagem por URL

{ "to": "551199999999", "type": "image", "image": {"link": "https://exemplo.com/foto.jpg", "caption": "Legenda"} }
  1. Enviar texto

POST /whatsapp-api-wrapper/messages/text/

{ "to": "551199999999", "body": "Olá!", "preview_url": false }

Exemplo com curl:

curl -X POST \
  -H "Authorization: Token seu_token_aqui" \
  -H "Content-Type: application/json" \
  -d '{"to": "551199999999", "body": "Olá!", "preview_url": false}' \
  "$BASE/whatsapp-api-wrapper/messages/text/"
  1. Responder com texto

POST /whatsapp-api-wrapper/messages/text/reply/

{ "to": "551199999999", "reply_to": "wamid.xxx", "body": "Resposta", "preview_url": false }
  1. Enviar template

POST /whatsapp-api-wrapper/messages/template/

{ "to": "551199999999", "name": "opa", "language": {"code": "pt_BR"}, "components": [] }

Respostas: mesmas do Graph (inclui messages[0].id com prefixo wamid).


Mensagens por tipo (Python + HTTP)

Observação: Para todos os tipos abaixo você pode:

  • Python: instanciar o objeto em django_whatsapp_api_wrapper.messages.types e passar diretamente como data=<objeto> no build_message.
  • HTTP: usar o endpoint genérico POST /whatsapp-api-wrapper/messages/send/ com type=<tipo> e o objeto correspondente no corpo.
  • Atalhos existentes: text/, text/reply/, template/.

Texto

  • Python:
text = WATypes.Text(body="Olá!", preview_url=False)
wp.build_message(to="551199999999", type="text", data=text).send()
  • HTTP (atalho): POST /messages/text/
{ "to": "551199999999", "body": "Olá!", "preview_url": false }
  • HTTP (genérico): POST /messages/send/
{ "to": "551199999999", "type": "text", "text": {"body": "Olá!", "preview_url": false} }

Texto (reply)

  • Python:
text = WATypes.Text(body="Resposta")
wp.build_message(to="551199999999", type="text", data=text).send()
# Para reply via HTTP use context.message_id
  • HTTP (atalho): POST /messages/text/reply/
{ "to": "551199999999", "reply_to": "wamid.xxx", "body": "Resposta", "preview_url": false }
  • HTTP (genérico): POST /messages/send/
{ "to": "551199999999", "type": "text", "context": {"message_id": "wamid.xxx"}, "text": {"body": "Resposta"} }

Template

  • Python:
tpl = WATypes.Template(name="opa", language={"code": "pt_BR"}, components=[])
wp.build_message(to="551199999999", type="template", data=tpl).send()
  • HTTP (atalho): POST /messages/template/
{ "to": "551199999999", "name": "opa", "language": {"code": "pt_BR"}, "components": [] }
  • HTTP (genérico): POST /messages/send/
{ "to": "551199999999", "type": "template", "template": {"name": "opa", "language": {"code": "pt_BR"}, "components": []} }

Imagem

  • Python:
img = WATypes.Image(link="https://exemplo.com/foto.jpg", caption="Legenda")
wp.build_message(to="551199999999", type="image", data=img).send()
  • HTTP (genérico): POST /messages/send/
{ "to": "551199999999", "type": "image", "image": {"link": "https://exemplo.com/foto.jpg", "caption": "Legenda"} }

Áudio

  • Python:
aud = WATypes.Audio(id="MEDIA_ID")  # ou link="https://..."
wp.build_message(to="551199999999", type="audio", data=aud).send()
  • HTTP (genérico): POST /messages/send/
{ "to": "551199999999", "type": "audio", "audio": {"id": "MEDIA_ID"} }

Documento

  • Python:
doc = WATypes.Document(link="https://exemplo.com/arquivo.pdf", filename="arquivo.pdf")
wp.build_message(to="551199999999", type="document", data=doc).send()
  • HTTP (genérico): POST /messages/send/
{ "to": "551199999999", "type": "document", "document": {"link": "https://exemplo.com/arquivo.pdf", "filename": "arquivo.pdf"} }

Vídeo

  • Python:
vid = WATypes.Video(id="MEDIA_ID", caption="Demo")
wp.build_message(to="551199999999", type="video", data=vid).send()
  • HTTP (genérico): POST /messages/send/
{ "to": "551199999999", "type": "video", "video": {"id": "MEDIA_ID", "caption": "Demo"} }

Sticker

  • Python:
stk = WATypes.Sticker(id="MEDIA_ID")
wp.build_message(to="551199999999", type="sticker", data=stk).send()
  • HTTP (genérico): POST /messages/send/
{ "to": "551199999999", "type": "sticker", "sticker": {"id": "MEDIA_ID"} }

Localização

  • Python:
loc = WATypes.Location(latitude=-23.56, longitude=-46.63, name="SP", address="Av. Paulista")
wp.build_message(to="551199999999", type="location", data=loc).send()
  • HTTP (genérico): POST /messages/send/
{ "to": "551199999999", "type": "location", "location": {"latitude": -23.56, "longitude": -46.63, "name": "SP", "address": "Av. Paulista"} }

Contacts

  • Python:
contact = WATypes.Contact(name={"formatted_name": "Maria"}, phones=[{"phone": "+551199999999", "type": "CELL"}])
wp.build_message(to="551199999999", type="contacts", data=[contact]).send()  # lista de contatos
  • HTTP (genérico): POST /messages/send/
{ "to": "551199999999", "type": "contacts", "contacts": [{ "name": {"formatted_name": "Maria"}, "phones": [{"phone": "+551199999999", "type": "CELL"}] }] }

Reaction

  • Python:
react = WATypes.Reaction(message_id="wamid.xxx", emoji="😀")
wp.build_message(to="551199999999", type="reaction", data=react).send()
  • HTTP (genérico): POST /messages/send/
{ "to": "551199999999", "type": "reaction", "reaction": {"message_id": "wamid.xxx", "emoji": "😀"} }

Interativo (Reply Buttons)

  • Python:
interactive = WATypes.Interactive(
    type="button",
    header={"type": "text", "text": "Título"},
    body={"text": "Mensagem"},
    footer={"text": "Rodapé"},
    action={"buttons": [{"title": "OK", "id": "ok"}, {"title": "Cancelar", "id": "cancel"}]}
)
wp.build_message(to="551199999999", type="interactive", data=interactive).send()
  • HTTP (genérico): POST /messages/send/
{ "to": "551199999999", "type": "interactive", "interactive": {
  "type": "button",
  "header": {"type": "text", "text": "Título"},
  "body": {"text": "Mensagem"},
  "footer": {"text": "Rodapé"},
  "action": {"buttons": [
    {"type": "reply", "title": "OK", "id": "ok"},
    {"type": "reply", "title": "Cancelar", "id": "cancel"}
  ]}
} }

Autenticação

Proteção das Rotas de API

Por padrão, todas as rotas de templates (/templates/) e mensagens (/messages/) são protegidas e requerem autenticação. O webhook permanece público (necessário para o WhatsApp).

Opções de Autenticação

1. Token Authentication (Padrão)

# settings.py
WHATSAPP_API_AUTHENTICATION_CLASSES = [
    'rest_framework.authentication.TokenAuthentication',
]

Uso:

curl -H "Authorization: Token seu_token_aqui" \
     "$BASE/whatsapp-api-wrapper/templates/"

2. JWT Authentication

# settings.py
WHATSAPP_API_AUTHENTICATION_CLASSES = [
    'rest_framework_simplejwt.authentication.JWTAuthentication',
]

Uso:

curl -H "Authorization: Bearer seu_jwt_token" \
     "$BASE/whatsapp-api-wrapper/templates/"

3. API Key Authentication

# settings.py
WHATSAPP_API_AUTHENTICATION_CLASSES = [
    'django_whatsapp_api_wrapper.authentication.APIKeyAuthentication',
]
WHATSAPP_API_KEY = "sua_api_key_secreta"

Uso:

curl -H "X-WhatsApp-API-Key: sua_api_key_secreta" \
     "$BASE/whatsapp-api-wrapper/templates/"

4. Múltiplas Autenticações

# settings.py
WHATSAPP_API_AUTHENTICATION_CLASSES = [
    'rest_framework.authentication.TokenAuthentication',
    'django_whatsapp_api_wrapper.authentication.APIKeyAuthentication',
]

Permissões Customizadas

# settings.py
WHATSAPP_API_PERMISSION_CLASSES = [
    'rest_framework.permissions.IsAuthenticated',
    # ou 'rest_framework.permissions.IsAdminUser',
    # ou 'myapp.permissions.CustomPermission',
]

Templates

Endpoints REST (DRF) para gerenciar Message Templates do WhatsApp (proxy para Graph API). Todos os endpoints abaixo partem do prefixo que você incluir no projeto, por exemplo: .../whatsapp-api-wrapper/.

⚠️ Importante: Todos os endpoints de templates requerem autenticação (veja seção Autenticação acima).

Requisitos de ambiente: WHATSAPP_CLOUD_API_TOKEN, WHATSAPP_CLOUD_API_VERSION, WHATSAPP_CLOUD_API_WABA_ID.

Aqui a documentação OFICIAL:

https://www.postman.com/meta/whatsapp-business-platform/folder/2ksdd2s/whatsapp-cloud-api

Listar e criar

  • GET GET /templates/?limit=&after=&before=
  • POST POST /templates/ com payload conforme a Graph API.

Exemplo de criação:

curl -X POST \
  "$BASE/whatsapp-api-wrapper/templates/" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "authentication_code_copy_code_button",
    "language": "en_US",
    "category": "AUTHENTICATION",
    "components": [
      {"type": "BODY", "add_security_recommendation": true},
      {"type": "FOOTER", "code_expiration_minutes": 10},
      {"type": "BUTTONS", "buttons": [{"type": "OTP", "otp_type": "COPY_CODE", "text": "Copy Code"}]}
    ]
  }'

Buscar por ID e editar

  • GET GET /templates/<template_id>/
  • POST POST /templates/<template_id>/ para editar (mesmo formato do corpo de criação).

Buscar e excluir por nome

  • GET GET /templates/by-name/?name=<TEMPLATE_NAME>
  • DELETE DELETE /templates/by-name/?name=<TEMPLATE_NAME>

Excluir por ID (hsm_id) e nome

  • DELETE DELETE /templates/delete-by-id/?hsm_id=<HSM_ID>&name=<NAME>

Obter namespace

  • GET GET /templates/namespace/

Notas:

  • Os payloads aceitos seguem a documentação oficial de Message Templates da Meta (Graph API). Este wrapper só valida campos básicos e encaminha a requisição.
  • As respostas retornadas são as mesmas da Graph API (status code e corpo JSON), para facilitar troubleshooting.

Notas

  • Nome do pacote no PyPI: django-whatsapp-api-wrapper
  • Nome do módulo/import: django_whatsapp_api_wrapper

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_whatsapp_api_wrapper-0.14.0.tar.gz (55.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

django_whatsapp_api_wrapper-0.14.0-py3-none-any.whl (85.4 kB view details)

Uploaded Python 3

File details

Details for the file django_whatsapp_api_wrapper-0.14.0.tar.gz.

File metadata

File hashes

Hashes for django_whatsapp_api_wrapper-0.14.0.tar.gz
Algorithm Hash digest
SHA256 48292c985b73c1a5e28fc63825d0e35d2f9a512097d7eba73c2e354b4331156d
MD5 7de72f15a63cd8c36989ff117a4de9e8
BLAKE2b-256 51891c3c05833a6832db45d297b280a5bb7e77a5c987a58fac3ec9d8e2c492ee

See more details on using hashes here.

File details

Details for the file django_whatsapp_api_wrapper-0.14.0-py3-none-any.whl.

File metadata

File hashes

Hashes for django_whatsapp_api_wrapper-0.14.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9389090eff96ac94f6e351c9e4de44d1fe3253cda5b11548037c77eac1d6d290
MD5 aabd8294e9243b1adfb28daad21ddd8e
BLAKE2b-256 50f2b3eace6f27a11b02b6491438e2fe83275086f151607e01f7f29081a20f2b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page