WhatsApp Business API para aclaración de necesidades del cliente
El escenario envía al lead una plantilla de WhatsApp personalizada pidiendo aclarar su propósito.
Descripción del caso de uso
El escenario envía al lead una plantilla de WhatsApp personalizada pidiendo aclarar su propósito. El mensaje incluye su nombre y el producto o tema de interés. Tres botones quick-reply permiten elegir uso personal, uso empresarial o solo navegación; los toques llegan vía webhook para enrutamiento en CRM.
Ejemplo de plantilla
Hola, {{1}}! Para encontrar la mejor opción para "{{2}}", aclara: ¿con qué objetivo consideras esta solución? Elige una opción adecuada abajo.
[Para mí]
Las etiquetas de botones quick-reply están fijadas en la plantilla de Meta — solo las variables del cuerpo se envían vía API; los toques regresan vía webhook.
Variables y propósito
{{1}}— nombre del lead o cliente{{2}}— producto, servicio o tema de interés
Ejemplo completado
Hola, Alexey! Para encontrar la mejor opción para "CRM para equipos", aclara: ¿con qué objetivo consideras esta solución? Elige una opción adecuada abajo.
[Para mí]
Cuándo usarlo
- leads entrantes
- product-led growth
- agencias
Valor para el negocio
- CRM or form capture flags a lead with unclear need profile
- System resolves lead phone and product context
- Needs-clarification template is sent with three quick-reply options
- Lead taps a button — webhook delivers the choice for CRM routing
- Sales or automation continues with the matched need segment
Flujo de trabajo
- El CRM marca un lead cuyo perfil de necesidad está incompleto tras la captura.
- Se obtienen teléfono del lead y contexto del producto desde el payload.
- Se envía una plantilla personalizada con dos variables en el cuerpo y tres botones quick-reply.
- El lead toca «Para mí», «Para empresa» o «Solo navegando» — el evento llega vía webhook.
- El CRM enruta el lead a la pista de ventas o nutrición correspondiente.
- El progreso de entrega se reporta de forma asíncrona — típicamente
sent, luegodelivered(o failed/undelivered). - Tu sistema recibe el estado vía webhook (
hooks[]) o consultaGET …/hookInfo?messageId=<id>y maneja fallos si es necesario.
Implementación técnica
Requisitos previos
- Plantilla de WhatsApp aprobada con dos variables en el cuerpo y tres botones quick-reply.
- Cuenta 1MSG con API de envío de plantillas y webhook configurado para mensajes entrantes.
- Integración CRM para mapear elecciones de botones a reglas de enrutamiento o campos del lead.
Ejemplos de código
Node.js
#!/usr/bin/env node
// === Configuration (replace "___" placeholders) ===
const API_BASE_URL = "https://api.1msg.io"; // production 1MSG API base URL
const CHANNEL_ID = "___"; // channel ID from 1MSG dashboard
const API_TOKEN = "___"; // channel JWT token (Bearer)
const TEMPLATE_NAME = "___"; // approved template name
const TEMPLATE_NAMESPACE = "___"; // template namespace (422 without it)
const TEMPLATE_LANGUAGE = "___"; // template language code, e.g. "en"
// === Test data ===
const TEST_PHONE = "___"; // client phone in international format
const TEST_CUSTOMERNAME = "___"; // {{1}} customer name
const TEST_PRODUCTORSERVICENAME = "___"; // {{2}} product or service name
function normalizePhone(phone) {
return String(phone).replace(/\D/g, "");
}
function assertConfigured(values) {
for (const [key, value] of Object.entries(values)) {
if (value === "___" || value === "" || value === undefined || value === null) {
throw new Error(`Missing configuration value: ${key}`);
}
}
}
async function sendTemplateMessage({ phone, customerName, productOrServiceName }) {
assertConfigured({
CHANNEL_ID,
API_TOKEN,
TEMPLATE_NAME,
TEMPLATE_NAMESPACE,
TEMPLATE_LANGUAGE,
phone,
customerName,
productOrServiceName,
});
const url = `${API_BASE_URL}/${CHANNEL_ID}/sendTemplate`;
// params carries body and button blocks (dynamic buttons).
const requestBody = {
phone: normalizePhone(phone),
template: TEMPLATE_NAME,
namespace: TEMPLATE_NAMESPACE,
language: {
policy: "deterministic",
code: TEMPLATE_LANGUAGE,
},
params: [
{
type: "body",
parameters: [
{ type: "text", text: String(customerName) }, // {{1}} customer name
{ type: "text", text: String(productOrServiceName) }, // {{2}} product or service name
],
},
],
};
const res = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${API_TOKEN}`,
},
body: JSON.stringify(requestBody),
});
const raw = await res.text();
let data;
try {
data = JSON.parse(raw);
} catch {
data = null;
}
if (!res.ok || !data || data.sent !== true) {
console.error("Send failed. API response:");
console.error(raw);
process.exit(1);
}
console.log("Message sent to client.");
console.log("API response:", raw);
return data;
}
function handleIncomingMessage(message) {
const text = (message && (message.text || message.body || "")).trim();
// Meta quick_reply label (from template.txt) → route key (code_contract.ref) "for_self"
if (text === "Для себя") {
console.log("Reply received: for_self");
return { status: "for_self" };
}
// Meta quick_reply label (from template.txt) → route key (code_contract.ref) "for_business"
if (text === "Для бизнеса") {
console.log("Reply received: for_business");
return { status: "for_business" };
}
// Meta quick_reply label (from template.txt) → route key (code_contract.ref) "just_browsing"
if (text === "Просто смотрю") {
console.log("Reply received: just_browsing");
return { status: "just_browsing" };
}
console.log("Free-text reply — handle separately.");
return { status: "other" };
}
if (require.main === module) {
sendTemplateMessage({
phone: TEST_PHONE,
customerName: TEST_CUSTOMERNAME,
productOrServiceName: TEST_PRODUCTORSERVICENAME,
}).catch((err) => {
console.error("Execution failed:", err.message);
process.exit(1);
});
}
module.exports = { sendTemplateMessage, handleIncomingMessage };
Respuesta inmediata de la API (síncrona)
- HTTP 2xx y JSON
"sent": truesignifican que 1MSG aceptó el mensaje para envío — no que ya llegó al teléfono del cliente. - Guarda el campo `id` de la respuesta (valor tipo
wamid.…). Úsalo para correlacionar callbacks de entrega o polling. - La respuesta también puede incluir
messageydescription— solo informativos.
Estado de entrega (asíncrono)
- Registra un webhook (
POST …/webhook) para que 1MSG envíe actualizaciones de entrega a tu endpoint HTTPS en un payload `hooks[]` separado (sent,delivered,read, o failed/undelivered cuando aplique). - Opcionalmente consulta:
GET {base}/{channel}/hookInfo?messageId=<id de sendTemplate>. - En la práctica, la entrega suele completarse en pocos segundos — pero eso no está garantizado por el contrato de la API.
Errores frecuentes
- Número de teléfono inválido o no normalizado
- Nombre de plantilla / namespace no aprobado o ausente
- Sin opt-in del cliente para mensajes comerciales de WhatsApp
- Cantidad de variables de plantilla incorrecta (422 de la API)
- Fallo de entrega — revisa el webhook de estado y la política de reintentos
Preguntas frecuentes
- ¿Necesito una plantilla aprobada? Sí — los mensajes cold-start de WhatsApp requieren una plantilla aprobada por Meta.
- ¿Puedo personalizar el texto? Las variables del cuerpo son dinámicas; el texto fijo y las etiquetas de botones se definen en la plantilla de Meta.
- ¿Cómo verifico la entrega?
sent: truesolo confirma aceptación. Rastrea la entrega vía webhookhooks[]oGET …/hookInfo?messageId=<id>. - ¿Qué pasa si no se entrega? Registra el hook failed/undelivered, verifica opt-in y estado de la plantilla, luego reintenta o usa otro canal.
- ¿Puedo conectarlo a mi CRM o backend? Sí — dispara la llamada a la API desde el webhook de tu plataforma o manejador de eventos.
CTA
¿Listo para usar aclaración de necesidades del cliente? Conecta tu canal 1MSG y ejecuta los ejemplos de código de arriba.
Recursos relacionados
Build WhatsApp automation in minutes
Use 1MSG to automate this workflow and try it with our free demo.
