TL;DR: Cree un módulo personalizado en Drupal 10, inyecte `@http_client`, almacene el token en el módulo Key y valide la configuración con un solo comando Drush que llame a `POST /messages/text`. Realice esto antes de implementar webhooks, colas o una interfaz de usuario de administración. Un sandbox gratuito de Whapi.Cloud es suficiente para validar la arquitectura.
Cuándo crear un módulo personalizado de WhatsApp en Drupal 10
Si su objetivo es realizar envíos salientes reutilizables de WhatsApp dentro de Drupal 10, comience con un módulo personalizado. Los módulos de widgets y las pantallas contribuidas exclusivas para administración resuelven un problema diferente.
Una integración de WhatsApp nativa de Drupal comienza con un servicio, no con un widget. Esa es la bifurcación arquitectónica que decide si su primer éxito se convierte en código mantenible o en otra pantalla de administración que no puede reutilizar desde un suscriptor de eventos, un trabajador de cola o un comando.
| Opción | Ideal para | Envío saliente programático | Reutilización nativa en Drupal | Señal de mantenimiento | Elíjalo cuando |
|---|---|---|---|---|---|
| Módulos de interfaz de usuario como `whatsapp_button` o `whatsapp_bubble` | Puntos de entrada de clic para chatear | Sin capa de transporte para la lógica de su módulo | Baja | Instalación rápida, alcance limitado | Solo necesita un botón de chat en el front-end |
| Módulo contribuido `whatsapp_cloud_api` | Experimentos basados en la administración | Limitado y orientado a pantallas | Media en el mejor de los casos | Proyecto visible en Drupal.org, pero el módulo dedicado más citado se actualizó por última vez en 2022 | Está evaluando ideas, no diseñando una capa de servicio reutilizable |
| Acciones de Brevo | Acciones de campaña o flujo de trabajo desde otra plataforma | Posible, pero fuera del propio contenedor de servicios de Drupal | Baja dentro de PHP personalizado | Bueno para automatizaciones de marketing, más débil para la propiedad del código en Drupal | Desea automatización externa más que código de módulo de Drupal |
| Módulo personalizado de Drupal | Mensajes salientes desde la lógica del sitio | Sí, desde servicios, comandos, controladores y colas | Alta | Más configuración el primer día, pero una reutilización mucho mejor después | Necesita una ruta de envío que pertenezca a Drupal |
Esa discrepancia es visible en los resultados de búsqueda actuales. La mayoría de las páginas sobre Drupal y WhatsApp cubren burbujas de chat, flujos de inicio de sesión o acciones activadas por el administrador. Rara vez muestran el patrón centrado en el contenedor de servicios que usted necesita cuando un evento de pedido, un evento de cliente potencial o un controlador personalizado debe realizar un envío desde el código de Drupal.
Módulos de interfaz de usuario
`whatsapp_button` y `whatsapp_bubble` son adecuados cuando la tarea del lector es un simple acceso al chat. No le proporcionan un servicio de transporte inyectable, un generador de solicitudes o una ruta de manejo de errores para la lógica saliente de WhatsApp dentro de Drupal.
Módulos API contribuidos
La señal del módulo dedicado `whatsapp_cloud_api` en el ecosistema de Drupal es útil principalmente como un indicio de mantenimiento. Su centro de gravedad son los formularios de configuración, y la señal actual más clara es una última actualización en septiembre de 2022. Eso ofrece poca tranquilidad cuando su requerimiento es un código de servicio reutilizable para Drupal 10.
Cuándo la opción personalizada es la correcta
Opte por un desarrollo personalizado cuando Drupal ya sepa por qué debe salir el mensaje. Hemos visto a equipos de Drupal Commerce comenzar con una sola notificación de pedido desde la lógica del sitio, no desde una plataforma de bots. Los flujos de seguimiento inmobiliario y de admisión en el sector salud suelen comenzar de la misma manera: primero un mensaje saliente útil, la orquestación después.
Cómo elegir su backend de la API de WhatsApp
Elija el backend que le permita realizar un primer envío real sin ocultar las limitaciones de producción. Para el objetivo de este artículo, Whapi.Cloud es la ruta más corta.
Whapi.Cloud le ofrece el camino más corto desde un módulo vacío hasta el primer envío real: conexión por QR, token, POST y listo. La API de Meta Cloud puede ser la ruta de cumplimiento adecuada a largo plazo en algunas organizaciones, pero añade más peso al proceso de integración antes de que un desarrollador principiante de Drupal vea salir el primer mensaje exitoso del sitio.
| Ruta del backend | Tiempo para el primer envío de prueba | Filtro de producción | Reglas de salida que afectan al MVP | Esfuerzo de integración en Drupal 10 |
|---|---|---|---|---|
| API de Meta Cloud | El mismo día si sus activos de Meta ya están listos; de lo contrario, días | A menudo días o semanas debido a la acumulación de pasos de verificación comercial, configuración de teléfono, suscripciones a webhooks y aprobaciones | Los flujos oficiales introducen reglas de plantillas y la ventana de servicio de 24 horas en el diseño de producción | Mayor, porque las limitaciones de integración y políticas llegan antes de que la ruta de código se sienta estable |
| Whapi.Cloud | Aproximadamente 2 minutos después de la conexión por QR | Sin verificación comercial de Meta para la ruta de envío del MVP | Sin restricciones de plantillas para un primer mensaje de prueba saliente, lo que permite validar el transporte antes | Menor, porque Drupal puede enfocarse primero en un único patrón de integración HTTP |
Ruta de la API de Meta Cloud
La ruta oficial merece una distinción clara entre prueba y producción. Es posible realizar pruebas antes de lo que many teams asumen, pero la producción sigue moviéndose más lento debido a que la verificación comercial, la configuración del número y la configuración de webhooks se introducen en el proyecto antes de que la integración sea algo habitual. No cubriremos el flujo completo de Verificación Comercial de Meta aquí porque es un proceso de incorporación independiente, no la forma más rápida de validar un módulo saliente de Drupal.
Ruta de la API Gateway
Whapi.Cloud se adapta a esta guía porque el MVP es un único mensaje de texto saliente desde Drupal, no un programa de cumplimiento regulatorio. La ruta de configuración de conexión por QR y el sandbox gratuito para siempre le ofrecen 5 chats activos al mes, 150 mensajes al día y 1,000 solicitudes de API al mes. Eso es suficiente para validar el diseño del servicio, el almacenamiento de tokens, el registro de logs y las pruebas con Drush antes de conectar la ruta de envío a eventos de negocio.
Criterios de selección
Use Meta cuando los requisitos oficiales de la plataforma sean parte del proyecto desde el primer día. Use Whapi.Cloud cuando la tarea inmediata sea un módulo personalizado de Drupal 10 funcional con un primer envío fácil de probar. Si se siente tentado a alojar usted mismo un wrapper de cliente web, recuerde lo que eso suele acarrear: cambios constantes en el protocolo ascendente, errores inesperados de tipo 500 y un trabajo de depuración que no tiene nada que ver con Drupal.
Estructura del módulo: servicio, configuración e inyección de dependencias
Su módulo debe verse como una integración estándar de Drupal, porque eso es lo que es. Mantenga el código de transporte en un solo servicio y permita que todo lo demás lo invoque.
Inyecte `@http_client` una vez, y cada llamada de WhatsApp se convertirá en código de Drupal reutilizable. Esa única decisión permite que el mismo método de envío funcione desde Drush, controladores, suscriptores de eventos, trabajadores de cola y pruebas sin tener que reescribir la lógica de transporte.
Estructura de archivos
Comience con algo pequeño. Necesita una definición de módulo, una definición de servicio, un esquema de configuración, una clase de cliente y una clase de comando Drush. Eso es suficiente para lograr el primer envío de manera limpia.
name: Whapi Drupal
type: module
description: Drupal 10 custom module for outbound WhatsApp messaging.
core_version_requirement: ^10 || ^11
package: Custom
dependencies:
- key:key
services.yml y WhatsappApiClient
La definición del servicio es donde el estilo de Drupal se vuelve explícito. Vincula el cliente HTTP, la fábrica de configuración, el repositorio Key y el canal de log en una sola clase de transporte que puede expandirse según la documentación de la API de Whapi.Cloud sin alterar la estructura del 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,
) {}
}
Inyección de http_client frente a llamada estática
Drupal ya envuelve Guzzle en el contenedor de servicios. Utilice eso en lugar de fragmentos de cURL puros o búsquedas estáticas en el contenedor. Esto mantiene el cliente comprobable, evita la duplicación y se alinea con las convenciones del framework en las que se apoyará el resto de su módulo.
Almacenamiento seguro de credenciales de API en Drupal
Separe el valor secreto del resto de los ajustes del módulo. La configuración de Drupal es para referencias e indicadores; el módulo Key es para el token en sí.
Almacene el ID de la clave en la configuración y el valor del token en el módulo Key; nunca guarde el token directamente en el código del módulo o en la configuración exportada. Esta es la diferencia entre un tutorial que sobrevive al relevo del equipo y uno que filtra credenciales en el historial de git.
Configuración del módulo Key
Cree una entidad Key en Drupal y utilice ese ID de clave en los ajustes de su módulo. El patrón seguro habitual consiste en permitir que el módulo Key obtenga el valor desde un proveedor respaldado por variables de entorno, y luego dejar que su módulo personalizado solicite el valor resuelto a través de `key.repository`.
Esquema de configuración
Su esquema de configuración debe describir claramente los ajustes que no son secretos: el identificador del canal o del remitente, el ID de la clave y cualquier valor predeterminado opcional que desee reutilizar. El valor del token en sí nunca debe aparecer aquí.
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'
Lo que nunca debe ir en los archivos .module
El token de transporte no pertenece a los archivos `.module`, fragmentos de blog copiados o valores predeterminados codificados de forma fija. El primer fallo aquí rara vez es la llamada a la API. Es un secreto que se filtra en el historial de git después de la demostración.
Cómo enviar su primer mensaje saliente
Una vez que la estructura del módulo y el almacenamiento del token están listos, la ruta de envío funcional es sencilla. Construya un payload, envíelo mediante POST al endpoint verificado y lea la respuesta como datos estructurados.
Un solo POST exitoso a `/messages/text` es suficiente para validar la arquitectura. No necesita webhooks, colas o una interfaz de administración completa antes de este punto. Necesita un método de envío reproducible que funcione desde el código de Drupal.
Construcción del payload de la solicitud
El endpoint verificado de envío de texto de Whapi.Cloud es `POST /messages/text`. Los campos requeridos del payload son `to` y `body`, lo que se mapea perfectamente a un método de servicio mínimo en Drupal.
POST mediante el cliente HTTP inyectado
Este es el método de transporte principal. Obtiene el token del módulo Key, envía el JSON a través del cliente HTTP inyectado de Drupal, registra los fallos del servidor ascendente y devuelve los datos de respuesta decodificados al invocador.
<?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' => [
// Si omite esta cabecera Bearer, Whapi.Cloud devolverá 401 y el envío nunca saldrá de 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;
}
}
Lectura de la respuesta de la API
Lea la respuesta JSON y muestre el ID del mensaje o el estado al invocador. En el modo de prueba, `402` es la señal de límite importante. `401` generalmente significa que el token faltaba o era incorrecto, y `403` suele significar que el chat o destinatario objetivo no puede recibir el envío bajo el estado actual del canal.
Ese límite es importante porque las restricciones del sandbox son suficientes para validar el diseño del módulo. No representan un punto de referencia de rendimiento para producción. En esta etapa, está validando la arquitectura, no el volumen.
Prueba de la integración desde Drupal
Pruebe el transporte donde el fallo sea visible. Drush le ofrece una retroalimentación más rápida que una página de administración y mantiene pequeño el primer ciclo de validación.
Pruebe desde Drush antes de construir una pantalla de administración. Verá la excepción, las entradas del payload y los datos devueltos más rápido, lo que hará que su primer ciclo de depuración sea más corto y mucho menos ruidoso.
Enfoque con comandos Drush
Exponga el servicio a través de un comando. Eso le dará la prueba más rápida de que Drupal puede resolver el cliente, cargar el token y enviar un mensaje real. Hemos visto que esto ahorra horas en desarrollos de Drupal Commerce porque la primera comprobación útil es el transporte, no la interfaz de usuario de administración.
<?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,
) {}
/*
* Envía un mensaje de prueba de WhatsApp a través de 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'));
}
}
Ejecútelo con un ID de chat o número de teléfono de destino conocido, luego compare el resultado con la colección de Postman de Whapi.Cloud si algo no funciona correctamente. Esa comprobación cruzada es más rápida que adivinar si el error reside en Drupal, en el token o en el payload.
Enfoque de controlador de administración mínimo
Una vez que Drush funcione, añada una pequeña ruta interna o un controlador de administración si su equipo necesita una prueba de humo basada en el navegador. Manténgalo simple: recopile la entrada, llame al mismo servicio y muestre el resultado. No duplique la lógica de transporte.
Manejo de errores de API al estilo de Drupal
Los fallos de transporte son normales. Lo que importa es si Drupal los convierte en señales sobre las que su equipo pueda actuar.
El registro de logs de Drupal junto con Messenger convierte un fallo silencioso del servidor ascendente en un evento depurable. Capture la excepción de transporte una vez, registre el contexto del servidor ascendente una vez y muestre un mensaje corto orientado al usuario en lugar de una página en blanco o un error omitido.
Captura de RequestException
Capture `RequestException` alrededor de la llamada de envío real, no alrededor de todo el controlador o la clase de comando. Esto mantiene estrecho el límite del fallo y le permite registrar el destinatario objetivo, el síntoma HTTP y la acción que desencadenó el envío.
Registro de logs con logger factory
Utilice un canal dedicado como `whapi_drupal` para que sus eventos operativos sean fáciles de filtrar en los mensajes de log recientes. Esto es fundamental en el momento en que un envío en cola, un suscriptor de eventos y una llamada manual de Drush utilicen el mismo cliente.
Mensajes de error orientados al usuario
Los controladores y formularios de administración deben convertir la excepción en un mensaje de error corto de `Messenger`: el envío falló y el operador debe revisar los logs. No muestre el JSON sin procesar del servidor ascendente en la interfaz de usuario. La entrada de log es para los desarrolladores; el texto de Messenger es para los operadores.
Si experimenta un comportamiento inesperado, comuníquese con el equipo de soporte de Whapi.Cloud a través del widget de chat en whapi.cloud. Un contacto de soporte directo es más útil aquí que buscar en hilos de problemas aleatorios que describen el entorno de otra persona.
Qué construir a continuación: webhooks, colas y acciones de ECA
Expándase solo después de que el primer mensaje saliente funcione de manera confiable. El siguiente nivel se centra en la resiliencia y el estado entrante, no en validar la integración básica.
El mejor MVP envía un mensaje de WhatsApp útil antes de automatizar flujos de clientes completos. Una vez que se valida el transporte, puede añadir webhooks entrantes, reintentos y acciones amigables para el editor sin tener que rediseñar el cliente principal.
Esqueleto del controlador de webhook
Mantenga el primer controlador de webhook simple: acepte la solicitud, verifíquela, extraiga el tipo de evento del formato de payload de webhook y entregue el payload a un servicio. La configuración de webhooks se vuelve compleja cuando la validación, la lógica de negocio y los efectos secundarios residen en un solo controlador. La validación de firmas es el siguiente paso de seguridad después de que la ruta saliente funcione.
Queue API
Utilice la Queue API de Drupal cuando el envío deba sobrevivir a reintentos, picos de tráfico o flujos de trabajo no bloqueantes. Esto es especialmente útil para notificaciones de comercio, seguimiento de clientes potenciales y recordatorios programados, donde el evento del sitio debe encolar el trabajo en lugar de esperar la llamada remota en el hilo de la solicitud.
Acción de envío de WhatsApp de ECA
Una vez que el servicio sea estable, puede envolverlo en una acción de ECA para la automatización gestionada por el editor. Ahí es donde los usuarios de negocio obtienen valor sin heredar la complejidad del almacenamiento de tokens o del transporte. El transporte centrado en servicios sigue siendo la parte fundamental.
No cubriremos aquí el manejo profundo de firmas de webhooks, la ramificación de bots o un manual de aprobación de producción completo de Meta. Esos son temas de seguimiento para cuando su módulo de Drupal ya pueda enviar un mensaje verificado a través de un canal real.
Una integración de WhatsApp mantenible para Drupal 10 se mantiene pequeña a propósito: un servicio, una referencia de clave, un POST saliente y un comando de prueba Drush. Eso es suficiente para completar un primer envío real con una prueba de Whapi.Cloud y ofrece suficiente estructura para expandirse sin tener que reescribir el transporte más adelante.
El siguiente paso más rápido es práctico. Conecte un número de sandbox, almacene el token en el módulo Key, ejecute el comando Drush y confirme que un mensaje sale de Drupal con éxito. Los límites del sandbox son intencionados, pero 5 chats activos al mes, 150 mensajes al día y 1,000 llamadas de API son más que suficientes para validar la arquitectura antes de vincular eventos, colas o automatización entrante.









