Voltar para artigosArtigo

Como enviar mensagens no WhatsApp com Python e Twilio

Projeto Python que busca cotacoes em tempo real e envia notificacoes WhatsApp via API do Twilio. Setup passo a passo com cron pra automatizar.

9 min
0
Ilustração anime estilo build com carlos: um balão de conversa do WhatsApp com a cotação USD para BRL, símbolos R$ e $ com setas de câmbio, o logo do Python, a faísca do Twilio e um ícone de cron.

Você já precisou ficar atualizado com cotações de câmbio em tempo real e receber notificações instantâneas? Se sim, tenho um projeto interessante pra compartilhar. Apresento o Currency Exchange Rate to BRL WhatsApp Notifier, uma ferramenta em Python que busca cotações atuais de várias moedas e criptomoedas, converte pra Real brasileiro (BRL) ou outras, e envia direto pro seu WhatsApp ou grupo usando a API do Twilio.

Neste artigo eu vou além do “clone e roda”. Explico as decisões de projeto que importam quando você quer que um bot desses fique de pé por meses sem babá: qual API de câmbio escolher, como estruturar o código, como agendar de forma confiável, como não vazar credenciais, e onde o WhatsApp Business (via Twilio) te impõe limites que não dá pra ignorar. E, no fim, uma seção honesta do que não funcionou.

Por que esse projeto?

Ficar atualizado com cotações recentes é crucial pra traders, investidores e qualquer pessoa lidando com várias moedas. Mas conferir cotação toda hora consome tempo e esforço. Esse projeto automatiza o processo inteiro, garantindo que você receba atualizações em tempo real direto no WhatsApp, facilitando decisões informadas.

Geralmente preciso estar por dentro das coisas mesmo ocupado. Então receber essas conversões e valores via WhatsApp ajuda a acompanhar meu swing trade e saber a hora de comprar ou vender uma moeda. Isso me poupa de ter que lembrar e ficar logando em sites de cotação.

Vale a nota pragmática: um bot de notificação não é conselho de investimento e não substitui um terminal sério de mercado. O objetivo aqui é o oposto da tela cheia de gráficos - é reduzir o número de vezes que você precisa abrir o celular pra “só dar uma olhadinha”. Uma mensagem duas vezes por dia com os números que interessam já resolve 90% da ansiedade de acompanhar câmbio.

Funcionalidades

  • Busca automática: pega as cotações atuais de USD, BTC, EUR e ETH.
  • Conversão pra BRL: converte as cotações pra Real brasileiro (BRL).
  • Notificações WhatsApp: envia as cotações convertidas pro seu WhatsApp via API do Twilio.
  • Variáveis de ambiente: usa arquivos .env pra gerenciar informações sensíveis com segurança.

Escolhendo a fonte das cotações

Essa é a decisão mais importante do projeto, e a que menos gente pensa antes de começar. A fonte dos dados define se o bot vai ser confiável ou se vai quebrar silenciosamente numa terça-feira qualquer.

Existem três caminhos comuns:

1. Scraping de páginas (Google Finance, sites de câmbio). É o mais fácil de começar e o mais frágil de manter. Você usa requests + BeautifulSoup pra ler o HTML e extrair o número. Funciona até o site mudar uma classe CSS ou colocar um bloqueio de bot, e aí seu bot para sem avisar. Não há contrato de API, então nenhuma garantia de estabilidade. Use só pra protótipo.

2. Bibliotecas de mercado (yfinance). A yfinance puxa dados do Yahoo Finance e cobre ações, câmbio (par USDBRL=X) e cripto. É gratuita e prática, mas não é uma API oficial: ela também depende de endpoints internos do Yahoo que mudam sem aviso. Ótima pra uso pessoal, arriscada pra qualquer coisa que precise de SLA.

3. APIs de câmbio dedicadas. Serviços como exchangerate.host, Open Exchange Rates, Fixer, CurrencyAPI ou a Frankfurter (que serve dados do Banco Central Europeu, gratuita e sem chave). Essas têm contrato de resposta em JSON estável, documentação e planos gratuitos com limites de requisição. Para cripto, CoinGecko tem um plano gratuito generoso.

Meu conselho, depois de ter quebrado a cara com scraping: comece com uma API JSON de verdade. O plano gratuito da maioria (algumas centenas a alguns milhares de requisições por mês) sobra pra um bot que roda 2 vezes por dia, o que dá cerca de 60 requisições no mês. Um exemplo de leitura contra uma API JSON:

import requests

def get_usd_brl() -> float:
    resp = requests.get(
        "https://api.frankfurter.app/latest",
        params={"from": "USD", "to": "BRL"},
        timeout=10,
    )
    resp.raise_for_status()
    return resp.json()["rates"]["BRL"]

Nota de revisão factual: os nomes de planos, limites de requisição e a gratuidade de cada provedor mudam com frequência. Confirme o rate limit e o custo atual na documentação do provedor antes de fechar a escolha.

Como funciona

O fluxo é simples e vale entender antes de mexer no código: (1) o script chama a API de câmbio e recebe os valores; (2) monta uma mensagem de texto legível com as cotações e a data/hora; (3) usa a API do Twilio pra enviar essa mensagem no WhatsApp; (4) um agendador dispara o script nos horários que você definir. Cada etapa pode falhar de forma diferente, então trato erro em cada uma.

Originalmente o projeto usava requests, BeautifulSoup e yfinance pra buscar e parsear cotações do Google Finance. Se você seguir o conselho da seção anterior e trocar por uma API JSON, o resto do fluxo continua idêntico. Segue um guia passo a passo pra configurar.

Passo 1: Clonar o repositório

Primeiro, clone o repositório GitHub pra sua máquina local:

git clone https://github.com/yourusername/currency-exchange-whatsapp-notifier.git
cd currency-exchange-whatsapp-notifier

Passo 2: Configurar o ambiente

Crie um ambiente virtual e ative:

python3 -m venv venv
source venv/bin/activate  # No Windows use: venv\Scripts\activate

Instale as dependências necessárias:

pip install -r requirements.txt

Passo 3: Configurar variáveis de ambiente

Crie um arquivo .env na raiz do projeto e adicione suas credenciais do Twilio e números de WhatsApp:

TWILIO_ACCOUNT_SID=your_twilio_account_sid
TWILIO_AUTH_TOKEN=your_twilio_auth_token
TWILIO_WHATSAPP_NUMBER=whatsapp:+14155238886
RECIPIENT_WHATSAPP_NUMBER=whatsapp:+recipient_phone_number

Segurança das credenciais: não commite seus tokens

Isso merece uma seção própria porque é o erro mais comum e o mais caro. O TWILIO_AUTH_TOKEN é efetivamente uma senha da sua conta: quem tiver ele pode enviar mensagens e gastar seu saldo. Três regras que sigo sempre:

1. .env nunca vai pro Git. Adicione a linha no .gitignore antes do primeiro commit, não depois:

# .gitignore
.env
venv/
__pycache__/

2. Carregue via ambiente, nunca hardcode. No código, leia as variáveis e falhe rápido se faltarem, em vez de mandar um None pro Twilio e receber um erro obscuro:

import os
from dotenv import load_dotenv

load_dotenv()

def require_env(name: str) -> str:
    value = os.environ.get(name)
    if not value:
        raise RuntimeError(f"Variável de ambiente obrigatória ausente: {name}")
    return value

ACCOUNT_SID = require_env("TWILIO_ACCOUNT_SID")
AUTH_TOKEN = require_env("TWILIO_AUTH_TOKEN")

3. Se vazou, rotacione. Se um token cair num commit público, não basta apagar o arquivo - o histórico do Git guarda. Gere um novo token no painel do Twilio e revogue o antigo imediatamente. Em produção, prefira um gerenciador de segredos (variáveis de ambiente do runner de CI, AWS Secrets Manager, etc.) em vez do .env no disco.

Passo 4: Montar a mensagem e enviar via Twilio

Com as cotações em mãos, monte um texto legível e envie. O padrão do cliente Python do Twilio é direto:

from twilio.rest import Client

def build_message(rates: dict[str, float]) -> str:
    linhas = ["Cotações de hoje (BRL):"]
    for moeda, valor in rates.items():
        linhas.append(f"- {moeda}: R$ {valor:,.2f}")
    return "\n".join(linhas)

def send_whatsapp(body: str) -> str:
    client = Client(ACCOUNT_SID, AUTH_TOKEN)
    msg = client.messages.create(
        from_=require_env("TWILIO_WHATSAPP_NUMBER"),
        to=require_env("RECIPIENT_WHATSAPP_NUMBER"),
        body=body,
    )
    return msg.sid

Repare que o número precisa do prefixo whatsapp: (ex.: whatsapp:+5511999999999), senão o Twilio trata como SMS. Para testar sem custo de produção, o Twilio oferece um sandbox de WhatsApp: você manda uma palavra-chave pro número de sandbox deles e passa a poder trocar mensagens por 72 horas, o suficiente pra validar o fluxo antes de configurar um número aprovado.

Tratamento de erros e retries

Um bot agendado precisa aguentar falha de rede sem morrer. As duas chamadas externas - a API de câmbio e o Twilio - podem dar timeout, retornar 5xx ou estourar rate limit. Eu embrulho cada uma com tentativa e recuo:

import time
import requests

def with_retry(fn, tentativas=3, espera=5):
    for i in range(tentativas):
        try:
            return fn()
        except (requests.RequestException, Exception) as e:
            if i == tentativas - 1:
                raise
            print(f"Tentativa {i + 1} falhou: {e}. Repetindo em {espera}s.")
            time.sleep(espera)

Boas práticas que valem a pena: use sempre timeout nas requisições (sem ele o script pode travar indefinidamente); trate o caso de a API devolver JSON sem o campo esperado; e, principalmente, faça o erro ser visível. Um bot que falha em silêncio é pior que não ter bot, porque você confia numa mensagem que nunca chega. Logue em arquivo e, se possível, mande uma notificação de falha (um segundo canal, e-mail simples) quando o job estourar todas as tentativas.

Passo 5: Agendar o script

Você pode agendar o script pra rodar em horários específicos. Existem quatro abordagens, da mais simples à mais robusta:

cron (macOS e Linux). O caminho clássico pra uma máquina sempre ligada. Edite o crontab:

crontab -e

E adicione as linhas (aqui, 8h e 14h todos os dias):

0 8 * * * /path/to/venv/bin/python /path/to/send_exchange_rates.py >> /path/to/bot.log 2>&1
0 14 * * * /path/to/venv/bin/python /path/to/send_exchange_rates.py >> /path/to/bot.log 2>&1

Sempre use caminhos absolutos (do Python do venv e do script) e redirecione a saída pra um log - o cron não roda com o mesmo PATH do seu shell interativo, e é aí que muita gente se perde.

APScheduler (dentro do próprio Python). Se você quer que o processo Python fique rodando e cuide do agendamento sozinho, sem depender do cron do sistema, a biblioteca APScheduler resolve. Útil quando você já tem um processo de longa duração ou vai empacotar num container.

GitHub Actions (sem servidor). Minha preferida pra bots pessoais: não exige máquina ligada. Um workflow com schedule roda em horário de cron nos runners do GitHub, de graça dentro da cota de minutos de repositórios públicos ou dentro do free tier. As credenciais ficam em GitHub Secrets, não no disco. Esboço:

# .github/workflows/rates.yml
on:
  schedule:
    - cron: "0 11,17 * * *"  # UTC; equivale a 8h e 14h em BRT
jobs:
  send:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - run: pip install -r requirements.txt
      - run: python send_exchange_rates.py
        env:
          TWILIO_ACCOUNT_SID: ${{ secrets.TWILIO_ACCOUNT_SID }}
          TWILIO_AUTH_TOKEN: ${{ secrets.TWILIO_AUTH_TOKEN }}

Atenção a dois detalhes do GitHub Actions: o cron é sempre em UTC (some as 3 horas do horário de Brasília na conta), e os jobs agendados podem sofrer atraso em horários de pico - se você precisa de precisão ao minuto, não é a ferramenta certa.

Cloud scheduler gerenciado. Em nuvem, um AWS EventBridge disparando uma Lambda, ou o Cloud Scheduler do GCP, faz o mesmo com mais garantias de entrega. Overkill pra uso pessoal, mas é o caminho natural se o bot virar algo sério.

Custo do Twilio e limites do WhatsApp

Aqui está a parte que muda o projeto de “brinquedo” pra “coisa que você precisa entender antes de escalar”. O WhatsApp Business, que o Twilio revende, não é um SMS livre - ele tem regras próprias:

  • Janela de 24 horas. Você só pode enviar mensagem de texto livre pra um usuário dentro de 24 horas após a última mensagem que ele te enviou. Fora dessa janela, é obrigatório usar um template de mensagem previamente aprovado pelo WhatsApp. Como um bot de cotação envia por iniciativa própria (o usuário não está respondendo nada), na prática você cai no caso de template aprovado pra o uso “de verdade”, fora do sandbox.

  • Templates precisam de aprovação. Cadastrar um template (“Cotações de hoje: {{1}}”) passa por revisão do WhatsApp e leva de minutos a alguns dias. É um passo burocrático que pega quem só testou no sandbox de surpresa.

  • Cobrança por conversa/mensagem. O Twilio cobra pelo uso do WhatsApp, e o modelo do WhatsApp é baseado em conversas iniciadas, com preço que varia por país e por categoria (marketing, utilidade, autenticação). Some a isso a taxa do próprio Twilio por mensagem. Para um bot pessoal que manda 2 mensagens por dia, o custo mensal tende a ser baixo, mas não é zero fora do sandbox.

Nota de revisão factual: os valores exatos (preço por conversa, taxa do Twilio, duração exata da janela e prazos de aprovação de template) mudam e variam por país. Confirme na documentação oficial do Twilio e do WhatsApp Business antes de assumir qualquer número. No sandbox, o custo de teste é isento, mas a janela de sessão de 72h e as restrições de destinatário se aplicam.

O que NÃO funcionou / limites

Sendo honesto sobre onde bati a cabeça:

  • Scraping do Google Finance quebrou. A versão inicial dependia de ler HTML, e bastou uma mudança de layout pra o parser voltar None sem erro claro. Foi o que me empurrou pra APIs JSON. Se você herdou uma versão com BeautifulSoup, considere isso dívida técnica.
  • yfinance some sem aviso. Em alguns dias a yfinance retornava vazio por rate limit ou instabilidade do endpoint do Yahoo. Funciona bem 95% do tempo, mas os 5% te ensinam a tratar o caso de “sem dado” em vez de mandar uma mensagem com valor errado.
  • A janela de 24h me pegou. No sandbox tudo funcionava, e a ficha só caiu na hora de sair dele: notificação proativa exige template aprovado. Se você não planeja isso, o bot “funciona no teste” e falha em produção.
  • cron em laptop é ilusão de confiabilidade. Enquanto rodava no meu Mac, todo sleep ou reboot perdia disparos. Migrar pra GitHub Actions resolveu o “máquina precisa estar ligada”.
  • Sem alerta de falha, você não sabe que quebrou. Passei dias achando que estava recebendo cotações quando o job silenciosamente falhava. Visibilidade de erro não é opcional.

Como estender

Depois que o básico funciona, dá pra evoluir sem reescrever:

  • Múltiplas moedas e pares. Parametrize a lista de pares (USD/BRL, EUR/BRL, BTC/BRL) e itere. A montagem da mensagem já lida com um dicionário.
  • Alertas por limiar. Em vez de mandar toda vez, só notifique quando o dólar cruzar um valor que te interessa (ex.: abaixo de R$ 5,00). Isso reduz mensagens e resolve o custo/janela do WhatsApp de quebra.
  • Histórico e gráfico. Salve cada leitura num CSV ou SQLite e gere um gráfico simples com matplotlib pra anexar tendência semanal.
  • Variação percentual. Guarde a última cotação e mande “USD: R$ 5,42 (+0,8% vs ontem)” - o delta costuma ser mais útil que o número absoluto.

Conclusão

Com o Currency Exchange Rate to BRL (ou outra moeda/país) WhatsApp Notifier, você fica atualizado com cotações em tempo real sem esforço. Trader, investidor ou alguém que precisa acompanhar conversões de moeda - essa ferramenta pode ser uma adição valiosa ao seu fluxo. Só não pule as três decisões que separam o brinquedo do bot confiável: uma fonte de dados estável, um agendador que não dependa da sua máquina ligada, e o entendimento das regras do WhatsApp Business antes de sair do sandbox.

Confira o repositório GitHub pro código fonte completo e instruções detalhadas.

Se esse projeto te ajudou, deixa uma estrela no GitHub e compartilha com quem possa se beneficiar. Feedback e contribuições são sempre bem-vindos.

Para aprofundar

Originalmente publicado no Medium

Este artigo foi publicado originalmente em 15 de junho de 2024. Esta versão no buildcomcarlos.com é a cópia editorial integral mantida no meu site. Você pode ler o original no Medium com formato original, claps e respostas.

  • Versão original no Medium
  • Voltar para a lista de artigos