TL;DR: Crie um módulo personalizado no Drupal 10, injete o `@http_client`, armazene o token no Key e valide a configuração com um único comando Drush que chama `POST /messages/text`. Faça isso antes de implementar webhooks, filas ou interfaces administrativas. Um sandbox gratuito da Whapi.Cloud é suficiente para validar a arquitetura.
Quando Criar um Módulo Personalizado de WhatsApp no Drupal 10
Se o seu objetivo é realizar envios reutilizáveis de mensagens de WhatsApp dentro do Drupal 10, comece com um módulo personalizado. Módulos de widgets e telas de contribuição apenas para administração resolvem problemas diferentes.
Uma integração de WhatsApp nativa do Drupal começa com um serviço, não com um widget. Essa é a bifurcação arquitetônica que decide se o seu primeiro sucesso se transformará em código sustentável ou em apenas mais uma tela administrativa que você não poderá reutilizar a partir de um event subscriber, queue worker ou comando.
| Opção | Ideal para | Envio programático de saída | Reutilização nativa no Drupal | Sinal de manutenção | Escolha quando |
|---|---|---|---|---|---|
| Módulos de UI como `whatsapp_button` ou `whatsapp_bubble` | Pontos de entrada click-to-chat | Sem camada de transporte para a lógica do seu módulo | Baixa | Instalação rápida, escopo limitado | Você precisa apenas de um botão de chat no front-end |
| `whatsapp_cloud_api` contrib | Experimentos baseados no painel administrativo | Limitado e focado em telas | Média, na melhor das hipóteses | Projeto visível no Drupal.org, mas o módulo dedicado mais citado foi atualizado pela última vez em 2022 | Você está avaliando ideias, não projetando uma camada de serviço reutilizável |
| Ações do Brevo | Campanhas ou ações de fluxo de trabalho de outra plataforma | Possível, mas fora do container de serviços do Drupal | Baixa dentro de PHP personalizado | Bom para automações de marketing, mais fraco para a autonomia de código do Drupal | Você quer automação externa em vez de código de módulo do Drupal |
| Módulo Drupal personalizado | Mensagens de saída originadas da lógica do site | Sim, a partir de serviços, comandos, controllers e filas | Alta | Mais configuração no primeiro dia, reutilização muito superior depois | Você precisa de um caminho de envio que pertença ao Drupal |
Essa incompatibilidade é visível nos resultados de busca atuais. A maioria das páginas sobre Drupal e WhatsApp aborda botões flutuantes de chat, fluxos de login ou ações disparadas pelo painel administrativo. Elas raramente mostram o padrão focado no container de serviços de que você precisa quando um evento de pedido, um evento de lead ou um controller personalizado precisa realizar envios a partir do código do Drupal.
Módulos de UI
Os módulos `whatsapp_button` e `whatsapp_bubble` funcionam bem quando a necessidade do leitor é apenas um botão simples de chat. No entanto, eles não fornecem um serviço de transporte injetável, um construtor de requisições ou um fluxo de tratamento de erros para a lógica de saída do WhatsApp no Drupal.
Módulos de API Contrib
O sinal do módulo dedicado `whatsapp_cloud_api` no ecossistema Drupal serve principalmente como um alerta de manutenção. Seu foco principal são formulários de configuração, e o indicador mais claro é que sua última atualização ocorreu em setembro de 2022. Essa é uma garantia muito frágil quando o seu requisito é um código de serviço do Drupal 10 reutilizável.
Quando a solução personalizada é a escolha certa
Opte pelo desenvolvimento personalizado quando o Drupal já souber o motivo pelo qual a mensagem deve ser enviada. Vimos equipes do Drupal Commerce começarem com uma única notificação de pedido a partir da lógica do site, em vez de uma plataforma de chatbot. Fluxos de acompanhamento imobiliário e triagem de saúde geralmente começam da mesma forma: uma mensagem de saída útil primeiro, a orquestração depois.
Escolhendo o seu Backend de API do WhatsApp
Escolha o backend que leve você ao primeiro envio real sem ocultar as restrições de produção. Para o objetivo deste artigo, a Whapi.Cloud é o caminho mais curto.
A Whapi.Cloud oferece o caminho mais rápido de um módulo vazio ao primeiro envio real: conexão via QR code, token, POST e pronto. A API Cloud da Meta pode ser a escolha certa para conformidade a longo prazo em algumas organizações, mas ela adiciona muito peso ao processo de integração antes que um desenvolvedor Drupal iniciante veja a primeira mensagem bem-sucedida sair do site.
| Caminho do Backend | Tempo até o primeiro envio de teste | Barreira de Produção | Regras de saída que afetam o MVP | Esforço de integração no Drupal 10 |
|---|---|---|---|---|
| API Cloud da Meta | No mesmo dia se os seus ativos da Meta já estiverem configurados; caso contrário, dias | Geralmente dias ou semanas, pois se acumulam etapas de verificação de empresa, configuração de telefone, assinaturas de webhook e aprovações | Os fluxos oficiais trazem regras de modelos de mensagem (templates) e a janela de atendimento de 24 horas para o design de produção | Maior, pois as restrições de onboarding e políticas surgem antes que o código pareça estável |
| Whapi.Cloud | Cerca de 2 minutos após conectar via QR code | Sem necessidade de verificação de empresa na Meta para o caminho de envio do MVP | Sem barreira de modelos para a primeira mensagem de teste de saída, permitindo que você valide o transporte mais cedo | Menor, pois o Drupal pode se concentrar primeiro em um único padrão de integração HTTP |
Caminho da API Cloud da Meta
O caminho oficial merece uma distinção justa entre teste e produção. É possível testar antes do que muitas equipes imaginam, mas a produção ainda avança mais devagar devido à verificação de empresa, configuração de número e parametrização de webhooks que entram no projeto antes que a integração pareça rotineira. Não abordaremos o fluxo completo de Verificação de Empresa da Meta aqui, pois se trata de uma etapa de onboarding separada, e não do caminho mais rápido para validar um módulo de saída do Drupal.
Caminho da API Gateway
A Whapi.Cloud se encaixa perfeitamente neste guia porque o MVP consiste em uma única mensagem de texto enviada a partir do Drupal, e não em um programa de conformidade corporativa. O processo de configuração via QR code e o sandbox gratuito vitalício oferecem 5 chats ativos por mês, 150 mensagens por dia e 1.000 requisições de API por mês. Isso é suficiente para validar o design do serviço, o armazenamento de tokens, o log e os testes com o Drush antes de vincular o envio a eventos de negócios.
Critérios de seleção
Utilize a Meta quando os requisitos oficiais da plataforma fizerem parte do escopo desde o primeiro dia. Use a Whapi.Cloud quando o objetivo imediato for um módulo personalizado funcional no Drupal 10 com um primeiro envio simples para testes. Se você se sentir tentado a hospedar por conta própria um wrapper de cliente web, lembre-se do que isso costuma trazer: instabilidade de protocolo upstream, erros 500 inesperados e um trabalho de depuração que não tem relação alguma com o Drupal.
Estrutura do Módulo: Serviço, Configuração e Injeção de Dependência
O seu módulo deve se parecer com uma integração padrão do Drupal, porque é exatamente isso que ele é. Mantenha o código de transporte em um único serviço e permita que todo o resto faça chamadas para ele.
Injete o `@http_client` uma única vez, e cada chamada de WhatsApp se tornará um código Drupal reutilizável. Essa decisão permite que o mesmo método de envio funcione a partir do Drush, controllers, event subscribers, queue workers e testes, sem a necessidade de reescrever a lógica de transporte.
Estrutura de arquivos (Scaffold)
Comece pequeno. Você precisa de uma definição de módulo, uma definição de serviço, um schema de configuração, uma classe de cliente e uma classe de comando Drush. Isso é suficiente para realizar o primeiro envio de forma limpa.
name: Whapi Drupal
type: module
description: Módulo personalizado do Drupal 10 para envio de mensagens de saída do WhatsApp.
core_version_requirement: ^10 || ^11
package: Custom
dependencies:
- key:key
services.yml e WhatsappApiClient
A definição do serviço é onde o padrão do Drupal se torna explícito. Ela vincula o cliente HTTP, a config factory, o repositório Key e o canal de log em uma única classe de transporte que pode evoluir de acordo com a documentação da API da Whapi.Cloud sem alterar a estrutura do módulo.
services:
logger.channel.whapi_drupal:
parent: logger.channel_base
arguments: ['whapi_drupal']
whapi_drupal.client:
class: Drupal\whapi_drupal\Service\WhatsappApiClient
arguments:
- '@http_client'
- '@config.factory'
- '@key.repository'
- '@logger.channel.whapi_drupal'
<?php
namespace Drupal\whapi_drupal\Service;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\key\KeyRepositoryInterface;
use GuzzleHttp\ClientInterface;
use Psr\Log\LoggerInterface;
final class WhatsappApiClient {
public function __construct(
private ClientInterface $httpClient,
private ConfigFactoryInterface $configFactory,
private KeyRepositoryInterface $keyRepository,
private LoggerInterface $logger,
) {}
}
Injetando o http_client vs Chamada Estática
O Drupal já envelopa o Guzzle no container de serviços. Utilize essa abordagem em vez de trechos brutos de cURL ou consultas estáticas ao container. Isso mantém o cliente testável, evita duplicações e segue as convenções do framework nas quais o restante do seu módulo se apoiará.
Armazenando Credenciais de API com Segurança no Drupal
Separe o valor confidencial do restante das configurações do módulo. A configuração do Drupal serve para referências e flags; o módulo Key serve para o token em si.
Armazene o ID da chave na configuração e o valor do token no módulo Key; nunca salve o token diretamente no código do módulo ou nas configurações exportadas. Essa é a diferença entre um tutorial que sobrevive à entrega para a equipe e um que vaza credenciais no histórico do git.
Configuração do módulo Key
Crie uma entidade Key no Drupal e use o ID dessa chave nas configurações do seu módulo. O padrão seguro mais comum é permitir que o módulo Key obtenha o valor a partir de um provedor baseado em variáveis de ambiente e, em seguida, fazer com que o seu módulo personalizado solicite o valor resolvido por meio do `key.repository`.
Schema de configuração
O seu schema de configuração deve descrever claramente as definições não confidenciais: identificador do canal ou remetente, ID da chave e quaisquer padrões opcionais que você queira reutilizar. O valor do token em si nunca deve constar aqui.
whapi_drupal.settings:
type: config_object
label: 'Whapi Drupal settings'
mapping:
channel_id:
type: string
label: 'Connected WhatsApp channel ID'
token_key:
type: string
label: 'Key entity ID for the Whapi token'
default_country_code:
type: string
label: 'Default country code for test sends'
O que nunca deve ir em arquivos .module
O token de transporte não pertence a arquivos `.module`, trechos de código copiados de blogs ou valores padrão hardcoded. A primeira falha aqui raramente é na chamada da API; costuma ser uma credencial confidencial que vaza no histórico do git logo após a demonstração.
Enviando a sua Primeira Mensagem de Saída
Assim que a estrutura do módulo e o armazenamento do token estiverem prontos, o caminho de envio funcional é simples. Monte o payload, envie um POST para o endpoint verificado e leia a resposta como dados estruturados.
Um único POST bem-sucedido para `/messages/text` é suficiente para comprovar a arquitetura. Você não precisa de webhooks, filas ou de uma interface administrativa completa antes disso. Você precisa de um método de envio reproduzível que funcione a partir do código do Drupal.
Montando o payload da requisição
O endpoint verificado de envio de texto da Whapi.Cloud é o `POST /messages/text`. Os campos obrigatórios do payload são `to` (destinatário) e `body` (corpo da mensagem), o que se mapeia perfeitamente em um método de serviço minimalista do Drupal.
POST via cliente HTTP injetado
Este é o método de transporte principal. Ele recupera o token a partir do módulo Key, envia o JSON por meio do cliente HTTP injetado do Drupal, registra falhas de upstream e retorna os dados de resposta decodificados para quem realizou a chamada.
<?php
use GuzzleHttp\Exception\RequestException;
public function sendText(string $to, string $body): array {
$config = $this->configFactory->get('whapi_drupal.settings');
$keyId = $config->get('token_key');
$token = $this->keyRepository->getKey($keyId)?->getKeyValue();
if (!$token) {
throw new \RuntimeException('Missing Whapi token in Key module.');
}
try {
$response = $this->httpClient->request('POST', 'https://gate.whapi.cloud/messages/text', [
'headers' => [
// Se você omitir este cabeçalho Bearer, a Whapi.Cloud retornará 401 e o envio nunca sairá do Drupal.
'Authorization' => 'Bearer ' . $token,
'Content-Type' => 'application/json',
],
'json' => [
'to' => $to,
'body' => $body,
],
'timeout' => 15,
]);
return json_decode((string) $response->getBody(), TRUE, 512, JSON_THROW_ON_ERROR);
}
catch (RequestException $exception) {
$this->logger->error('Whapi send failed for {recipient}: {message}', [
'recipient' => $to,
'message' => $exception->getMessage(),
]);
throw $exception;
}
}
Lendo a resposta da API
Leia a resposta JSON e retorne o ID ou o status da mensagem para quem realizou a chamada. No modo de testes, o código `402` é o sinal de limite importante. O erro `401` geralmente significa que o token estava ausente ou incorreto, e o `403` costuma indicar que o chat ou destinatário de destino não pode receber o envio sob o estado atual do canal.
Essa distinção é importante porque os limites do sandbox são suficientes para validar o design do módulo. Eles não representam um benchmark de desempenho de produção. Nesta fase, você está validando a arquitetura, não o volume.
Testando a Integração a partir do Drupal
Teste o transporte onde as falhas sejam visíveis. O Drush oferece um feedback muito mais rápido do que uma página administrativa e mantém o ciclo inicial de validação curto.
Teste pelo Drush antes de criar uma tela administrativa. Você visualizará exceções, os dados de entrada do payload e o retorno da API muito mais rápido, tornando o seu primeiro ciclo de depuração mais ágil e com menos ruído.
Abordagem com comando Drush
Exponha o serviço por meio de um comando. Isso fornece a prova mais rápida de que o Drupal consegue resolver o cliente, carregar o token e enviar uma mensagem real. Vimos isso economizar horas em projetos do Drupal Commerce, pois a primeira verificação útil é o transporte, não a interface administrativa.
<?php
namespace Drupal\whapi_drupal\Commands;
use Drupal\whapi_drupal\Service\WhatsappApiClient;
use Drush\Commands\DrushCommands;
final class WhapiDrupalCommands extends DrushCommands {
public function __construct(
private WhatsappApiClient $client,
) {}
/*
* Envia uma mensagem de teste do WhatsApp através da Whapi.Cloud.
*
* @command whapi:send-test
*/
public function sendTest(string $chatId, string $message): void {
$result = $this->client->sendText($chatId, $message);
$this->output()->writeln('Message sent. Remote id: ' . ($result['messages'][0]['id'] ?? 'n/a'));
}
}
Execute-o com um ID de chat de destino conhecido ou número de telefone e, em seguida, compare o resultado com a coleção do Postman da Whapi.Cloud caso algo pareça incorreto. Essa verificação cruzada é mais rápida do que tentar adivinhar se o problema está no Drupal, no token ou no payload.
Abordagem com controller administrativo minimalista
Depois que o Drush estiver funcionando, adicione uma rota interna simples ou um controller administrativo se a sua equipe precisar de um teste rápido pelo navegador. Mantenha-o enxuto: receba a entrada, chame o mesmo serviço e exiba o resultado. Não duplique a lógica de transporte.
Tratando Erros de API no Padrão do Drupal
Falhas de transporte são normais. O que realmente importa é se o Drupal transforma essas falhas em sinais acionáveis para a sua equipe.
O log do Drupal combinado com o serviço Messenger transforma uma falha silenciosa de upstream em um evento depurável. Capture a exceção de transporte uma vez, registre o contexto do upstream uma vez e exiba uma mensagem curta para o usuário em vez de uma página em branco ou um erro omitido.
Capturando a RequestException
Capture a `RequestException` em torno da chamada de envio real, não de toda a classe do controller ou de comando. Isso mantém o escopo da falha restrito e permite registrar o destinatário de destino, o sintoma HTTP e a ação que disparou o envio.
Registrando logs com o Logger Channel
Utilize um canal dedicado como `whapi_drupal` para que os eventos operacionais sejam fáceis de filtrar nas mensagens de log recentes. Isso faz toda a diferença no momento em que um envio enfileirado, um event subscriber e uma chamada manual do Drush utilizam o mesmo cliente.
Mensagens de erro voltadas para o usuário
Controllers e formulários administrativos devem converter a exceção em uma mensagem de erro curta do `Messenger`: o envio falhou e o operador deve verificar os logs. Não exiba JSON bruto do upstream na interface de usuário. O registro de log é para desenvolvedores; o texto do Messenger é para operadores.
Se você encontrar comportamentos inesperados, entre em contato com a equipe de suporte da Whapi.Cloud por meio do widget de chat em whapi.cloud. Um contato direto com o suporte é muito mais útil aqui do que vasculhar tópicos de fóruns aleatórios que descrevem o ambiente de outra pessoa.
O que Criar a Seguir: Webhooks, Filas e Ações ECA
Expanda apenas depois que a primeira mensagem de saída funcionar de forma confiável. A próxima camada diz respeito à resiliência e ao estado de entrada, e não mais à validação da integração básica.
O melhor MVP envia uma única mensagem útil de WhatsApp antes de automatizar jornadas completas de clientes. Assim que o transporte for validado, você poderá adicionar webhooks de entrada, tentativas de envio (retries) e ações amigáveis para editores sem precisar reprojetar o cliente principal.
Esqueleto do controller de webhook
Mantenha o primeiro controller de webhook restrito: receba a requisição, valide-a, extraia o tipo de evento do formato do payload do webhook e passe o payload para um serviço. A configuração de webhooks torna-se complexa quando validação, lógica de negócios e efeitos colaterais residem em um único controller. A validação de assinaturas é a próxima etapa de segurança após o funcionamento do caminho de saída.
Queue API (API de Filas)
Utilize a Queue API do Drupal quando o envio precisar sobreviver a tentativas, picos de tráfego ou fluxos de trabalho não bloqueantes. Isso é especialmente útil para notificações de e-commerce, acompanhamento de leads e lembretes agendados, onde o evento do site deve enfileirar o trabalho em vez de aguardar a chamada remota na thread da requisição.
Ação ECA de Envio de WhatsApp
Depois que o serviço estiver estável, você poderá envolvê-lo em uma ação ECA para automação gerenciada por editores. É aí que os usuários de negócios obtêm valor sem herdar a complexidade de transporte ou armazenamento de tokens. O transporte focado em serviços continua sendo a parte estrutural mais importante.
Não abordaremos o tratamento avançado de assinaturas de webhook, ramificações de bots ou o manual completo de aprovação de produção da Meta aqui. Esses são tópicos de acompanhamento para quando o seu módulo Drupal já for capaz de enviar uma mensagem verificada por meio de um canal real.
Uma integração de WhatsApp sustentável no Drupal 10 permanece pequena de propósito: um serviço, uma referência de chave, um POST de saída e um comando de teste Drush. Isso é suficiente para concluir um primeiro envio real com a avaliação da Whapi.Cloud e oferece estrutura suficiente para crescer sem a necessidade de reescrever o transporte posteriormente.
O próximo passo mais rápido é prático. Conecte um número de sandbox, armazene o token no módulo Key, execute o comando Drush e confirme que a mensagem sai do Drupal com sucesso. Os limites do sandbox são intencionais, mas 5 chats ativos por mês, 150 mensagens por dia e 1.000 chamadas de API são mais do que suficientes para comprovar a arquitetura antes de vincular eventos, filas ou automação de entrada.









