1msg official logo

WhatsApp Business API para aclaración de método de pago

El escenario envía al cliente una plantilla de WhatsApp personalizada cuando facturación necesita conocer el método de pago.

Descripción del caso de uso

El escenario envía al cliente una plantilla de WhatsApp personalizada cuando facturación necesita conocer el método de pago. El mensaje incluye el nombre del cliente y monto adeudado. Dos botones quick-reply permiten elegir tarjeta o transferencia bancaria; el webhook entrega la elección a tu backend.

Ejemplo de plantilla

Hola, {{1}}! Elige cómo pagarás {{2}}:

[Tarjeta]

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.

Variables y propósito

  • {{1}} — nombre del cliente
  • {{2}} — monto del pago

Ejemplo completado

Hola, Alex! Elige cómo pagarás 150.00 USD:

[Tarjeta]

Cuándo usarlo

  • facturación y checkout
  • facturación b2b
  • integradores

Valor para el negocio

  • Billing detects that payment method is missing for an invoice or checkout
  • Template is sent with customer name and payment amount
  • Customer taps card or bank transfer on the quick-reply buttons
  • Webhook delivers the structured choice to billing for the next payment step

Flujo de trabajo

  1. Facturación detecta que falta el método de pago y dispara un evento.
  2. El sistema obtiene el teléfono del cliente y el monto del pago.
  3. Se construye un mensaje de plantilla personalizado con dos variables en el cuerpo y dos botones quick-reply.
  4. El cliente recibe el mensaje de WhatsApp y toca tarjeta o transferencia bancaria.
  5. El webhook entrega la elección estructurada a facturación para el siguiente paso de pago.
  6. El progreso de entrega se reporta de forma asíncrona — típicamente sent, luego delivered (o failed/undelivered).
  7. Tu sistema recibe el estado vía webhook (hooks[]) o consulta GET …/hookInfo?messageId=<id> y maneja fallos si es necesario.

Implementación técnica

Requisitos previos

  • Cuenta 1MSG con WhatsApp Business API conectada y plantilla de mensaje aprobada con dos botones quick-reply.
  • Número de teléfono del cliente en formato internacional (sin + ni espacios).
  • Contexto de pago: nombre del cliente y monto adeudado.
  • Endpoint webhook HTTPS para recibir eventos de botones quick-reply.

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_PAYMENTAMOUNT = "___";    // {{2}} payment amount

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, paymentAmount }) {
  assertConfigured({
    CHANNEL_ID,
    API_TOKEN,
    TEMPLATE_NAME,
    TEMPLATE_NAMESPACE,
    TEMPLATE_LANGUAGE,
    phone,
    customerName,
    paymentAmount,
  });

  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(paymentAmount) }, // {{2}} payment amount
        ],
      },
    ],
  };

  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) "pay_by_card"
  if (text === "Картой") {
    console.log("Reply received: pay_by_card");
    return { status: "pay_by_card" };
  }
  // Meta quick_reply label (from template.txt) → route key (code_contract.ref) "pay_by_bank"
  if (text === "Банковский перевод") {
    console.log("Reply received: pay_by_bank");
    return { status: "pay_by_bank" };
  }
  console.log("Free-text reply — handle separately.");
  return { status: "other" };
}

if (require.main === module) {
  sendTemplateMessage({
    phone: TEST_PHONE,
    customerName: TEST_CUSTOMERNAME,
    paymentAmount: TEST_PAYMENTAMOUNT,
  }).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": true significan 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 message y description — 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: true solo confirma aceptación. Rastrea la entrega vía webhook hooks[] o GET …/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 método de pago? 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.

Try the demo →