Saudações.
Vou apresentar o software WAHA (WhatsApp HTTP API), um software que provê a API não oficial do WhatsApp para suas integrações, automações e IA.
Ele é uma alternativa ao antigo Evolution API (agora https://evolutionfoundation.com.br/).
1 – O que é o Waha
O WAHA (site: https://waha.devlike.pro/) é um gateway (software que fica entre dois sistemas) que roda em container Docker e se conecta a uma ou várias contas do WhatsApp como se fosse o app WhatsApp Web (app do Zap que você usa pelo navegador ou pelo desktop).
De um lado ele se conecta a sua conta WhatsApp, do outro ele te fornece:
- APIs HTTP para envio e recebimento de mensagens;
- Interface Web para envio e recebimento de mensagens;
- Integração com ChatWoot;
Ele era distribuído em duas versões, community e plus. Recentemente os desenvolvedores abriram a versão plus para uso gratuito e ilimitado.
2 – Cuidados
Antes de utilizar o WAHA é importante salientar que ele é um software não oficial, ou seja, a META (Face/Zap/Insta) não autoriza o uso de softwares desse tipo pois obviamente concorrem com o WhatsApp Business API (WABA).
2.1 – Riscos
Os riscos são:
- Bloqueio temporário da sua conta (número);
- Bloqueio permanente e irreversível da sua conta;
Esse tipo de sistema não tem futuro, a META está constantemente alterando o canal de comunicação entre os clientes (WhatsApp Desktop, WhatsApp Web, APP) para dificultar a vida dos desenvolvedores e motivar as vendas do WABA.
2.2 – Manutenção constante
Por causa desse alteração constante você deve sempre manter o WAHA atualizado semanalmente (fazer pull da imagem latest e recriar o container, os dados não são perdidos pois ficam armazenados no PostgreSQL e no S3).
2.3 – Recomendações
Recomendo utilizar para pequenas tarefas de automação e interação com sistemas e agentes de IA.
Cuidados contantes:
- Atualizar a imagem do container semanalmente e recriando o container do Waha;
- Usar em números “aquecidos” (usados por humanos por alguns dias antes de ligar nos bots);
- Não enviar mensagens para contatos que não possuem seu número salvo, cada nova mensagem “selvagem” é um ponto negativo na sua conta. Cada contato selvagem que reporta sua mensagem como spam acelera o bloqueio da sua conta;
- Não enviar mensagens com intervalos curtos, um humano não consegue enviar 10 mensagens por segundo, é uma indicação obvia de uso irregular do WhatsApp;
- Não enviar mensagens com intervalos fixos (como 1 mensagem a cada 5 segundos), coloque sempre um fator aleatório nos intervalos dos loops em suas automações;
- Não envie a mesma mensagem para vários contatos (mesmo HASH), sempre adicione alguma frase ou número diferente ou coloque a IA com temperature aumentada.
Uso comum e tranquilo:
- Monitoramento de sistemas e eventos;
- Interação com agentes de IA;
- Comunicação com clientes e contatos conhecidos sem envio em massa.
Para todos os demais casos, contrate o WABA, nele você não poderá cometer os mesmo erros mas poderá aumentar a taxa de envio levemente (você pagará por isso!).
3 – Preparativos
O Waha precisa de:
- Um banco de dados – PostgreSQL;
- Um cache RESP – Redis ou Valkey;
- Um storage S3 – Minio.
3.1 – Rede
Crie a rede Docker “network_public“:
# Rede de containers
docker network create network_public \
-d bridge \
-o com.docker.network.bridge.name=br-net-public \
-o com.docker.network.driver.mtu=1500 \
-o com.docker.network.bridge.gateway_mode_ipv4=nat-unprotected \
--subnet 10.249.0.0/16 \
--gateway 10.249.255.254;
3.2 – Banco de dados PostgreSQL
Vou usar a imagem pgvector (debian trixie + postgres 18 + pgvector).
O nome do container será “waha-database” e as credenciais:
- Usuário: postgres
- Senha: tulipasql
- Banco de dados: waha
Script em shell:
# Variaveis
NAME="waha-database";
# Argumentos do postgres (usado somente no primeiro boot)
POSTGRES_USER="postgres";
POSTGRES_PASSWORD="tulipasql";
POSTGRES_DB="waha";
# Imagem
IMAGE="pgvector/pgvector:pg18-trixie";
docker pull $IMAGE;
# Volume
# obs: pg18 usa pasta principal interna: /var/lib/postgresql
DATADIR=/storage/$NAME;
mkdir -p $DATADIR;
chown -R 999:999 $DATADIR;
# Renovar/rodar:
docker rm -f $NAME 2>/dev/null;
docker run \
-d \
--restart always \
--name $NAME \
--hostname $NAME.intranet.br \
\
--cpus 2.0 \
--cpu-shares 1024 \
--memory 2g \
--memory-swap 2g \
--memory-reservation 1g \
--shm-size 1g \
\
--network network_public \
--ip 10.249.130.1 \
\
--tmpfs /run:rw,noexec,nosuid,size=64m \
--tmpfs /tmp:rw,exec,suid,size=64m \
\
-v $DATADIR:/var/lib/postgresql \
\
-e POSTGRES_USER=$POSTGRES_USER \
-e POSTGRES_PASSWORD=$POSTGRES_PASSWORD \
-e POSTGRES_DB=$POSTGRES_DB \
-e PGDATA=/var/lib/postgresql/data/pgdata \
\
--health-cmd="pg_isready -U postgres" \
--health-interval=5s \
--health-timeout=5s \
--health-retries=10 \
\
--entrypoint "docker-entrypoint.sh" \
\
$IMAGE \
postgres \
--timezone=America/Sao_Paulo \
--log_timezone=America/Sao_Paulo \
--max_connections=150 \
--superuser_reserved_connections=3 \
--shared_buffers=384MB \
--effective_cache_size=768MB \
--work_mem=4MB \
--maintenance_work_mem=96MB \
--temp_buffers=8MB \
--wal_buffers=16MB \
--min_wal_size=512MB \
--max_wal_size=2GB \
--checkpoint_completion_target=0.9 \
--checkpoint_timeout=10min \
--wal_compression=on \
--wal_level=replica \
--random_page_cost=1.1 \
--effective_io_concurrency=200 \
--default_statistics_target=100 \
--max_worker_processes=4 \
--max_parallel_workers=2 \
--max_parallel_workers_per_gather=1 \
--max_parallel_maintenance_workers=2 \
--autovacuum=on \
--autovacuum_max_workers=2 \
--autovacuum_naptime=30s \
--autovacuum_vacuum_threshold=50 \
--autovacuum_vacuum_scale_factor=0.05 \
--autovacuum_analyze_threshold=50 \
--autovacuum_analyze_scale_factor=0.05 \
--autovacuum_vacuum_cost_delay=2ms \
--autovacuum_vacuum_cost_limit=400 \
--statement_timeout=120000 \
--idle_in_transaction_session_timeout=300000 \
--lock_timeout=30000 \
--log_destination=stderr \
--logging_collector=off \
--log_min_duration_statement=2000 \
--log_line_prefix="%t [%p] %u@%d " \
--log_checkpoints=on \
--log_connections=off \
--log_disconnections=off \
--log_lock_waits=on \
--log_temp_files=10240 \
--log_autovacuum_min_duration=1000 \
--shared_preload_libraries=pg_stat_statements \
--track_activities=on \
--track_counts=on \
--track_io_timing=on \
--track_functions=pl \
--ssl=off \
--port=5432 \
--listen_addresses="*" \
--max_wal_senders=3 \
--hot_standby=on;
3.3 – Cache Redis/Valkey
O serviço RESP (Redis ou Valkey) serve de cache e mensageria entre workers do Waha. Vou utilizar o Valkey pela superioridade.
O nome do container será “waha-cache“:
# Variaveis
NAME=waha-cache;
# Imagem
IMAGE="valkey/valkey:9.1.0-trixie";
docker pull $IMAGE;
# Pasta de persistencia
DATADIR=/storage/$NAME;
mkdir -p $DATADIR;
# Renovar/rodar
docker rm -f $NAME 2>/dev/null;
docker run \
-d \
--restart always \
--name $NAME \
--hostname $NAME.intranet.br \
\
--tmpfs /run:rw,noexec,nosuid,size=2m \
--tmpfs /tmp:rw,noexec,nosuid,size=2m \
--read-only \
\
--cpus 2.0 \
--cpu-shares 1024 \
--memory 2g \
--memory-swap 2g \
--memory-reservation 1g \
\
--network network_public \
--ip 10.249.130.2 \
\
-v $DATADIR:/data \
\
--health-cmd="redis-cli ping" \
--health-interval=1s \
--health-timeout=3s \
\
$IMAGE \
valkey-server \
--bind '0.0.0.0 ::' \
--port 6379 \
--set-proc-title no \
--tcp-backlog 8192 \
--tcp-keepalive 30 \
--timeout 0 \
\
--databases 16 \
\
--appendonly no \
--dir /run \
--save "" \
--maxmemory-policy allkeys-lru;
3.4 – Storage S3 com Minio
Normalmente cada empresa centraliza o storage S3 na Amazon ou em um Minio unificado, aqui vou colocá-lo dedicado ao Waha.
Se você pretende participar de muitos grupos ou suas conversas envolvem com muitas imagens e videos, recomendo pelo menos 1 Terabyte de espaço para o volume do container. Tenha capacidade para expandir futuramente sem permitir que o serviço S3 fique sem espaço.
Personalize:
- Crie os nomes de DNS (FQDN) para apontar para o IP do seu servidor/VPS:
- Endereço do serviço S3: s3.seudominio.com.br;
- Endereço de administração (console): minio.seudominio.com.br;
- Usuário administrador: admin
- Senha do administrador: tulipa@s3
Script:
# Variaveis
NAME=minio;
TZ="America/Sao_Paulo";
# nomes de dns:
# - s3 para usar
FQDN_WEB="s3.seudominio.com.br";
# - minio para administrar
FQDN_CONSOLE="minio.seudominio.com.br";
# Acesso de administrador
MINIO_ROOT_USER="admin";
MINIO_ROOT_PASSWORD="tulipa@s3";
DATADIR=/storage/minio;
mkdir -p $DATADIR;
# Atualizar/baixar imagem:
IMAGE="quay.io/minio/minio:RELEASE.2025-04-22T22-12-26Z";
docker pull $IMAGE;
# Renovar/Rodar:
docker rm -f $NAME 2>/dev/null;
docker run \
-d \
--restart always \
--name $NAME \
--hostname $NAME.intranet.br \
\
--cpus 2.0 \
--cpu-shares 1024 \
--memory 2g \
--memory-swap 2g \
--memory-reservation 1g \
\
--network network_public \
--ip 10.249.130.3 \
\
--tmpfs /run:rw,noexec,nosuid,size=2m \
--tmpfs /tmp:rw,noexec,nosuid,size=2m \
\
-e TZ=$TZ \
\
-e "MINIO_ROOT_USER=$MINIO_ROOT_USER" \
-e "MINIO_ROOT_PASSWORD=$MINIO_ROOT_PASSWORD" \
-e "MINIO_BROWSER_REDIRECT_URL=https://$FQDN_CONSOLE" \
-e "MINIO_SERVER_URL=https://$FQDN_WEB" \
\
-v $DATADIR:/data \
\
--label "traefik.enable=true" \
\
--label "traefik.http.routers.${NAME}_web.rule=Host(\`$FQDN_WEB\`)" \
--label "traefik.http.routers.${NAME}_web.entrypoints=web,websecure" \
--label "traefik.http.routers.${NAME}_web.tls=true" \
--label "traefik.http.routers.${NAME}_web.tls.certresolver=letsencrypt" \
--label "traefik.http.routers.${NAME}_web.service=${NAME}_web" \
--label "traefik.http.services.${NAME}_web.loadbalancer.server.port=9000" \
--label "traefik.http.services.${NAME}_web.loadbalancer.passHostHeader=true" \
\
--label "traefik.http.routers.${NAME}_con.rule=Host(\`$FQDN_CONSOLE\`)" \
--label "traefik.http.routers.${NAME}_con.entrypoints=web,websecure" \
--label "traefik.http.routers.${NAME}_con.tls=true" \
--label "traefik.http.routers.${NAME}_con.tls.certresolver=letsencrypt" \
--label "traefik.http.routers.${NAME}_con.service=${NAME}_con" \
--label "traefik.http.services.${NAME}_con.loadbalancer.server.port=9001" \
--label "traefik.http.services.${NAME}_con.loadbalancer.passHostHeader=true" \
\
$IMAGE \
server /data --console-address ":9001";
# Acesso:
echo;
echo "Acesso:";
echo "Web......: https://$FQDN_WEB";
echo "Console..: https://$FQDN_CONSOLE";
echo;
Será necessário criar uma chave de acesso e um bucket (balde de arquivos) no S3/Minio para o Waha gravar e consultar objetos (imagens, audios, videos, documentos).
Acesse o endereço de console e siga os procedimentos abaixo:
- No menu Administrator, clique em Buckets -> Create Bucket:
- Preencha o campo Bucket Name com waha;
- Clique no botão Create Bucket;
- No menu User, clique em Access Keys -> Create Access Key:
- Preencha o campo Access Key com waha_s3;
- Preencha o campo Secret Key com um UUID ou senha segura, exemplo:
- Secret Key: fce5f62b-9cb1-11f1-a065-000c2941d8a8
- Preencha o campo Name com Waha API;
- Clique no botão Create;
O Waha vai precisar:
- Da URL do S3 (FQDN_WEB), s3.seudominio.com.br;
- Do Bucket Name, Access Key e Secret Key.
4 – Instalando o Waha
Vamos nos preparar para entender e rodar o WAHA.
Você precisará criar um nome de DNS (FQDN) para acessar o Waha, crie algo como “waha.seudominio.com.br“.
4.1 – Variáveis de ambiente
Precisamos preencher as variáveis de ambiente que controlam o software internamente.
| Variável de ambiente | Descrição |
|---|---|
| TZ | Timezone do ambiente |
| REDIS_URL | URL de acesso ao Redis ou Valkey |
| WHATSAPP_SESSIONS_POSTGRESQL_URL | URL de acesso ao PostgreSQL |
| WAHA_WORKER_ID | Identificador do processo worker |
| WAHA_BASE_URL | URL de acesso HTTPs ao Waha |
| WAHA_PUBLIC_URL | URL de acesso HTTPs ao Waha |
| WAHA_APPS_CHATWOOT_LANGUAGES_FOLDER | Diretório de template de idioma do padrão ChatWoot |
| WAHA_API_KEY_PLAIN | Chave de API em texto plano (Authorization/Bearer) |
| WAHA_API_KEY | Hash Sha512 da chave de API na sintaxe “sha512:hash_sha512_aqui“ |
| WAHA_DASHBOARD_ENABLED | Controle de ativação da dashboard web |
| WAHA_DASHBOARD_USERNAME | Nome de usuário da dashboard |
| WAHA_DASHBOARD_PASSWORD | Senha para o login na dashboard |
| WHATSAPP_API_PORT | Porta HTTP, padrão “3000” |
| WHATSAPP_API_HOSTNAME | Nome de DNS do servidor, “localhost” ou o FQDN “waha.seudominio.com.br” |
| WHATSAPP_API_SCHEMA | Protocolo, padrão “HTTP” |
| WHATSAPP_DEFAULT_ENGINE | Motor (engine) do WhatsApp, opções: “WEBJS”, “GOWS” ou “NOWEB” |
| WHATSAPP_SWAGGER_ENABLED | Ativar página de manual da API usando Swagger |
| WHATSAPP_SWAGGER_USERNAME | Usuário do Swagger |
| WHATSAPP_SWAGGER_PASSWORD | Senha do Swagger |
| WHATSAPP_SWAGGER_TITLE | Título da página Swagger |
| WHATSAPP_SWAGGER_DESCRIPTION | Descrição da página Swagger |
| WHATSAPP_SWAGGER_EXTERNAL_DOC_URL | URL da página Swagger |
| WAHA_MEDIA_STORAGE | Modo de armazenamento de arquivos, opções “S3”, “POSTGRESQL” ou “LOCAL” |
| WHATSAPP_FILES_LIFETIME | TTL dos arquivos, padrão “0” |
| WHATSAPP_FILES_FOLDER | Caminho da pasta para armazenamento tipo “LOCAL” |
| WAHA_S3_REGION | Nome da região S3. |
| WAHA_S3_BUCKET | Nome do bucket (balde de arquivos) |
| WAHA_S3_ACCESS_KEY_ID | Chave de acesso (Access Key) |
| WAHA_S3_SECRET_ACCESS_KEY | Senha da chave de acesso (Secret Key) |
| WAHA_S3_ENDPOINT | URL do servidor S3 (s3.seudominio.com.br) |
| WAHA_S3_FORCE_PATH_STYLE | Usar padrão com pasta, padrão “True” |
| WAHA_S3_PROXY_FILES | Fazer proxy, padrão “False” |
| WAHA_MEDIA_POSTGRESQL_URL | URL de acesso PostgreSQL para armazenamento de arquivos para armazenamento tipo “POSTGRESQL” |
4.2 – Chave de acesso da API Waha
Para usar a API do Waha é importante não errar a chave de acesso ao definir a variável de ambiente, vou dar um exemplo gerando a chave usando UUID:
# Gerar UUID randomico
UUID=$(head -1 /proc/sys/kernel/random/uuid);
echo "UUID gerado: $UUID";
# exemplo de saida:
# UUID gerado: aad8a318-3c2d-4969-ab9e-43c9dcc4ca2a
# Gerar hash SHA512 do UUID:
HASH=$(printf "$UUID" | sha512sum);
echo "Hash: sha512:$HASH";
# exemplo de saida:
# sha512:187863......915d49
No exemplo acima, temos:
- “aad8a318-3c2d-4969-ab9e-43c9dcc4ca2a” é o valor da env WAHA_API_KEY_PLAIN
- “sha512:187863……915d49” (eu cortei parte do hash com esses pontos pois a string é muito grande) é o valor da env WAHA_API_KEY
4.3 – Script para criar o container Waha
O nome do container será “waha-app“.
O controle de acesso por login será:
- Usuário administrador: admin, envs:
- WHATSAPP_SWAGGER_USERNAME
- WAHA_DASHBOARD_USERNAME
- Senha do administrador: Waha@Plus_2026, envs:
- WHATSAPP_SWAGGER_PASSWORD
- WAHA_DASHBOARD_PASSWORD
Script final:
# Variaveis
NAME=waha-app;
LOCAL=$NAME.intranet.br;
FQDN_WEB="waha.seudominio.com.br";
IMAGE="devlikeapro/waha:latest";
# Login de administracao Waha
WAHA_LOGIN="admin";
WAHA_PASSWORD="Waha@Plus_2026";
# Banco de dados Postgres
PG_HOST="waha-database";
PG_PORT="5432";
PG_USER="postgres";
PG_PASS="tulipasql";
PG_DBNAME="waha";
PG_OPT="sslmode=disable";
WHATSAPP_SESSIONS_POSTGRESQL_URL="postgres://$PG_USER:$PG_PASS@$PG_HOST:$PG_PORT/$PG_DBNAME?$PG_OPT";
# Cache em RESP - Redis ou Valkey
REDIS_URL="redis://waha-cache:6379";
# Whara Options
WAHA_WORKER_ID=waha_app;
WAHA_BASE_URL="https://$FQDN_WEB";
WAHA_PUBLIC_URL="https://$FQDN_WEB";
#WAHA_APPS_CHATWOOT_LANGUAGES_FOLDER="/app/.chatwoot-languages";
WAHA_APPS_CHATWOOT_LANGUAGES_FOLDER="";
# Chave de API
# Versao SHA512 da chave de API (echo -n xxxx | sha512sum)
WAHA_API_KEY_PLAIN="aad8a318-3c2d-4969-ab9e-43c9dcc4ca2a";
HASH=$(printf $WAHA_API_KEY_PLAIN | sha512sum | awk '{print $1}');
WAHA_API_KEY="sha512:$HASH";
WAHA_RESTART_ALL_SESSIONS="true";
WAHA_AUTO_START_DELAY_SECONDS="10";
WAHA_PRESENCE_AUTO_ONLINE="True";
WAHA_PRESENCE_AUTO_ONLINE_DURATION_SECONDS="25";
WAHA_DASHBOARD_ENABLED="true"
WAHA_DASHBOARD_USERNAME="$WAHA_LOGIN";
WAHA_DASHBOARD_PASSWORD="$WAHA_PASSWORD";
WAHA_APPS_ENABLED="true";
WAHA_APPS_JOBS_CONCURRENCY="50";
WAHA_APPS_JOBS_REMOVE_ON_COMPLETE_AGE="259200";
WAHA_APPS_JOBS_REMOVE_ON_COMPLETE_COUNT="1000";
WAHA_APPS_JOBS_REMOVE_ON_FAIL_AGE="2678400";
WAHA_APPS_JOBS_REMOVE_ON_FAIL_COUNT="1000";
# Dados de whatsapp
WHATSAPP_API_PORT="3000";
WHATSAPP_API_HOSTNAME="$FQDN_WEB";
WHATSAPP_API_SCHEMA="https";
WHATSAPP_DEFAULT_ENGINE="GOWS";
WHATSAPP_SWAGGER_ENABLED="true";
WHATSAPP_SWAGGER_USERNAME="$WAHA_LOGIN";
WHATSAPP_SWAGGER_PASSWORD="$WAHA_PASSWORD";
WHATSAPP_SWAGGER_TITLE="Sua Empresa - WhatsApp HTTP API";
WHATSAPP_SWAGGER_DESCRIPTION="API de integração WP";
WHATSAPP_SWAGGER_EXTERNAL_DOC_URL="https://$FQDN_WEB";
WHATSAPP_SWAGGER_VIDEO_EXAMPLE_URL="";
WHATSAPP_SWAGGER_OPUS_EXAMPLE_URL="";
WHATSAPP_SWAGGER_JPG_EXAMPLE_URL="";
# Armazenamento S3 Minio
WAHA_MEDIA_STORAGE=S3;
WAHA_S3_REGION=intranet1;
WAHA_S3_BUCKET=waha;
WAHA_S3_ACCESS_KEY_ID="waha_s3";
WAHA_S3_SECRET_ACCESS_KEY="fce5f62b-9cb1-11f1-a065-000c2941d8a8";
WAHA_S3_ENDPOINT="https://s3.seudominio.com.br";
WAHA_S3_FORCE_PATH_STYLE=True;
WAHA_S3_PROXY_FILES=False;
# Baixar imagem:
docker pull $IMAGE;
# Pasta de persistencia
DATADIR=/storage/$NAME;
mkdir -p $DATADIR/sessions;
mkdir -p $DATADIR/media;
mkdir -p $DATADIR/wp-data;
mkdir -p $DATADIR/wp-logs;
# Renovar/rodar
docker rm -f $NAME 2>/dev/null;
docker run \
-d --restart=always \
--name $NAME -h $LOCAL \
--tmpfs /run:rw,noexec,nosuid,size=512m \
--tmpfs /tmp:rw,noexec,nosuid,size=512m \
--read-only \
\
--cpus 8.0 \
--cpu-shares 2048 \
--memory 4g \
--memory-swap 4g \
--memory-reservation 2g \
\
--network network_public \
--ip 10.249.130.101 \
\
-p 3000:3000 \
\
-v $DATADIR/sessions:/app/.sessions \
-v $DATADIR/media:/app/media \
-v $DATADIR/wp-data:/app/waha_whatsapp_data \
-v $DATADIR/wp-logs:/app/waha_whatsapp_logs \
\
-e TZ=America/Sao_Paulo \
\
-e REDIS_URL=$REDIS_URL \
\
-e WAHA_WORKER_ID=$WAHA_WORKER_ID \
\
-e WAHA_BASE_URL=$WAHA_BASE_URL \
-e WAHA_PUBLIC_URL=$WAHA_PUBLIC_URL \
-e WAHA_APPS_CHATWOOT_LANGUAGES_FOLDER=$WAHA_APPS_CHATWOOT_LANGUAGES_FOLDER \
-e WAHA_API_KEY_PLAIN=$WAHA_API_KEY_PLAIN \
-e WAHA_API_KEY=$WAHA_API_KEY \
\
-e WAHA_DASHBOARD_ENABLED=$WAHA_DASHBOARD_ENABLED \
-e WAHA_DASHBOARD_USERNAME=$WAHA_DASHBOARD_USERNAME \
-e WAHA_DASHBOARD_PASSWORD=$WAHA_DASHBOARD_PASSWORD \
\
-e WHATSAPP_SESSIONS_POSTGRESQL_URL=$WHATSAPP_SESSIONS_POSTGRESQL_URL \
\
-e WHATSAPP_API_PORT=$WHATSAPP_API_PORT \
-e WHATSAPP_API_HOSTNAME=$WHATSAPP_API_HOSTNAME \
-e WHATSAPP_API_SCHEMA=$WHATSAPP_API_SCHEMA \
\
-e WHATSAPP_DEFAULT_ENGINE=$WHATSAPP_DEFAULT_ENGINE \
-e WHATSAPP_SWAGGER_ENABLED=$WHATSAPP_SWAGGER_ENABLED \
-e WHATSAPP_SWAGGER_USERNAME=$WHATSAPP_SWAGGER_USERNAME \
-e WHATSAPP_SWAGGER_PASSWORD=$WHATSAPP_SWAGGER_PASSWORD \
-e WHATSAPP_SWAGGER_TITLE="$WHATSAPP_SWAGGER_TITLE" \
-e WHATSAPP_SWAGGER_DESCRIPTION="$WHATSAPP_SWAGGER_DESCRIPTION" \
-e WHATSAPP_SWAGGER_EXTERNAL_DOC_URL=$WHATSAPP_SWAGGER_EXTERNAL_DOC_URL \
-e WHATSAPP_SWAGGER_VIDEO_EXAMPLE_URL=$WHATSAPP_SWAGGER_VIDEO_EXAMPLE_URL \
-e WHATSAPP_SWAGGER_OPUS_EXAMPLE_URL=$WHATSAPP_SWAGGER_OPUS_EXAMPLE_URL \
-e WHATSAPP_SWAGGER_JPG_EXAMPLE_URL=$WHATSAPP_SWAGGER_JPG_EXAMPLE_URL \
\
-e WAHA_RESTART_ALL_SESSIONS=$WAHA_RESTART_ALL_SESSIONS \
-e WAHA_AUTO_START_DELAY_SECONDS=$WAHA_AUTO_START_DELAY_SECONDS \
-e WAHA_PRESENCE_AUTO_ONLINE=$WAHA_PRESENCE_AUTO_ONLINE \
-e WAHA_PRESENCE_AUTO_ONLINE_DURATION_SECONDS=$WAHA_PRESENCE_AUTO_ONLINE_DURATION_SECONDS \
\
-e WAHA_APPS_ENABLED=$WAHA_APPS_ENABLED \
-e WAHA_APPS_JOBS_CONCURRENCY=$WAHA_APPS_JOBS_CONCURRENCY \
-e WAHA_APPS_JOBS_REMOVE_ON_COMPLETE_AGE=$WAHA_APPS_JOBS_REMOVE_ON_COMPLETE_AGE \
-e WAHA_APPS_JOBS_REMOVE_ON_COMPLETE_COUNT=$WAHA_APPS_JOBS_REMOVE_ON_COMPLETE_COUNT \
-e WAHA_APPS_JOBS_REMOVE_ON_FAIL_AGE=$WAHA_APPS_JOBS_REMOVE_ON_FAIL_AGE \
-e WAHA_APPS_JOBS_REMOVE_ON_FAIL_COUNT=$WAHA_APPS_JOBS_REMOVE_ON_FAIL_COUNT \
\
-e WAHA_MEDIA_STORAGE=$WAHA_MEDIA_STORAGE \
-e WAHA_S3_REGION=$WAHA_S3_REGION \
-e WAHA_S3_BUCKET=$WAHA_S3_BUCKET \
-e WAHA_S3_ACCESS_KEY_ID=$WAHA_S3_ACCESS_KEY_ID \
-e WAHA_S3_SECRET_ACCESS_KEY=$WAHA_S3_SECRET_ACCESS_KEY \
-e WAHA_S3_ENDPOINT=$WAHA_S3_ENDPOINT \
-e WAHA_S3_FORCE_PATH_STYLE=$WAHA_S3_FORCE_PATH_STYLE \
-e WAHA_S3_PROXY_FILES=$WAHA_S3_PROXY_FILES \
\
\
--label "traefik.enable=true" \
\
--label "traefik.http.routers.$NAME.rule=Host(\`$FQDN_WEB\`)" \
--label "traefik.http.routers.$NAME.entrypoints=web,websecure" \
--label "traefik.http.routers.$NAME.tls=true" \
--label "traefik.http.routers.$NAME.tls.certresolver=letsencrypt" \
--label "traefik.http.routers.$NAME.service=$NAME" \
\
--label "traefik.http.middlewares.${NAME}sslheader.headers.customrequestheaders.X-Forwarded-Proto=https" \
--label "traefik.http.routers.$NAME.middlewares=${NAME}sslheader@docker" \
\
--label "traefik.http.services.$NAME.loadbalancer.server.port=$WHATSAPP_API_PORT" \
--label "traefik.http.services.$NAME.loadbalancer.passHostHeader=true" \
\
\
$IMAGE \
node ./dist/main.js;
# Acesso:
echo;
echo "Acesso:";
echo "Web......: https://$FQDN_WEB";
echo "Admin....: https://$FQDN_WEB/dashboard/";
echo;
5 – Primeiro acesso
Vamos acessar o Waha e aprender como usar e registrar contas do WhatsApp.
5.1 – Swagger, manual da API
Acesse a URL do Waha (waha.seudominio.com.br), esse primeiro login é o acesso do Swagger (uma página de manual, exemplos de testes da API).

5.2 – Dashboard e gestão
Agora vamos colocar o Waha pra funcionar em uma conta do WhatsApp.
Você precisará acessar o path /dashboard da URL, exemplo https://waha.seudominio.com.br/dashboard
Tela inicial (sem contas ainda, ignore o erro inicial):

5.3 – Configurando o worker
Antes de iniciar uma sessão usando sua conta no WhatsApp, precisamos colocar o Worker padrão online.
Edite o worker padrão clicando no ícone do lápis:

Na edição, informe:
- Em “Name“, preencha com o mesmo valor que você definiu na variável WAHA_WORKER_ID, no nosso exemplo (e pode deixar assim) é waha_app;
- Em “API URL“, defina a URL do nosso servidor (exemplo https://waha.seudominio.com.br);
- Em API Key, preencha com a chave de API que você definiu na variável WAHA_API_KEY_PLAIN, no nosso exemplo é aad8a318-3c2d-4969-ab9e-43c9dcc4ca2a
- Click no botão “Save“

Agora o worker waha_app consegue usar a própria API interna para processar eventos. Observe que o worker fica online. Você pode reiniciar o worker em casos de erros iniciais.

5.4 – Criando uma sessão WhatsApp Web no Waha
Agora que temos o worker pra trabalhar nas sessões, vamos criar uma sessão de WhatsApp Web para que o Waha tenha acesso à nossa conta.
Na parte de “Sessions” não há contas ainda, vamos iniciar uma sessão usando o QR-CODE do WhatsApp Web. Clique no botão “Start New“.

No formulário da sessão, apenas crie-a clicando no botão “Create“. O nome é opcional mas recomendado.
Com a sessão criada, clique no botão de “Start” (ícone de play) para iniciar a conexão com o servidor da Meta.

Quando a conexão inicial da sessão for iniciada com a Meta, a sessão entra em modo “SCAN_QR_CODE“, clique no botão “Screenshot / QR” para exibir o QR-CODE.
Leia-o pelo aplicativo do WhatsApp do seu smartphone.

Ao ler o QR-CODE o Waha iniciará a sincronização da sua conta WhatsApp. Em alguns minutos a sessão estará pronta para uso e com modo “WORKING“:

Pronto! O Waha está captando em tempo real todos os dados de chats, grupos, contatos e totalmente capaz de interagir no WhatsApp.
6 – Webhook
Cada sessão suporta chamadas de webhook para eventos. Se alguem te mandar uma mensagem direta isso dispara a chamada de uma URL de sua escolha.
Sua webhook será o ponto de entrada para que seus agentes de IA e automações possam reagir aos eventos da sessão. Fluxo de tráfego da mensagem:

Para configurar a webhook, vá nas configurações da sessão no botão roxo “Configuration“:

Encontre a parte de “Webhooks” na configuração e informe a URL que será invocada para os “Events” (eventos) selecionados:

Recomendo o N8N para construção do protótipo dos seus agentes, e mais tarde você pode transformá-lo em códigos performáticos (Python, Go, Rust, Node, …).
x
x
(falta:, integração com ChatWoot)
x
Terminamos por hoje!
Patrick Brandão, patrickbrandao@gmail.com
“Todo mundo pensa em mudar o mundo,
mas ninguém pensa em mudar a si mesmo.“
Leon Tolstói
