Saltar al contenido principal

Webhook de WhatsApp

Recibe los mensajes de WhatsApp en tu servidor,
desde el número que ya usas.

Los webhooks de Meta exigen una app de Meta, un portfolio comercial y un número trasladado a la API. Vincula en cambio tu WhatsApp actual: cada mensaje entrante llega a tu URL como JSON firmado.

¿Con prisa? Resume este artículo con una IA

La respuesta corta

¿Se puede tener un webhook de WhatsApp sin la API Business de Meta?

Sí. Unlimited Messaging vincula tu número de WhatsApp actual como dispositivo vinculado, igual que WhatsApp Web, y envía cada mensaje recibido a tu URL como un evento JSON firmado según Standard Webhooks, llamado message.received. No hay app de Meta que crear, ni verificación de empresa, ni coste por mensaje. Los webhooks están en los planes de pago Medium y Max.

La vía oficial es la WhatsApp Cloud API de Meta. Para recibir sus webhooks creas una app de Meta con el caso de uso de WhatsApp, le asocias un portfolio comercial y una cuenta de WhatsApp Business, respondes a una petición GET de verificación con hub.challenge y sirves un certificado TLS válido: Meta no acepta certificados autofirmados. Un portfolio nuevo solo puede escribir a 250 personas al día (fuera de la ventana de 24 horas) hasta que se verifica, y una empresa que lo construye para clientes necesita además la App Review de Meta.

Unlimited Messaging toma el otro camino: escaneas un código QR desde WhatsApp, Dispositivos vinculados, y el número sigue funcionando en tu móvil. Cada mensaje que llega se guarda y se envía a tu endpoint con el remitente, el texto, la conversación y, para una foto o una nota de voz, una mediaUrl que sirve el archivo. Tu respuesta sale por POST /message desde el mismo número, así que el cliente ve un chat normal.

El precio, con honestidad: es el protocolo no oficial de dispositivos vinculados, no un producto de Meta. Sirve para respuestas y avisos a gente que ya te escribe. Enviar en masa a desconocidos hace que bloqueen el número, sea cual sea la herramienta.

Antes de empezar: las API de WhatsApp gratis comparadas y cómo proteger un número vinculado de un bloqueo.

Ilustración: un teléfono con un chat tipo WhatsApp y una insignia verde, con el titular «Webhook de WhatsApp, sin app de Meta».

Los eventos

¿Qué eventos de WhatsApp puedes recibir por webhook?

Diez tipos de evento, elegidos por endpoint: un endpoint solo recibe lo que está en su lista eventTypes. Estos son los que necesita una bandeja de WhatsApp.

  1. message.received

    Ha llegado un mensaje, en un chat 1:1 o en un grupo: texto, imagen, vídeo, documento, audio, nota de voz (ptt), sticker o ubicación. Se emite una vez por mensaje; un mensaje con archivo se anuncia cuando el archivo está guardado, con mediaUrl.

  2. message.self_sent

    Escribiste un mensaje en el propio móvil, fuera de la API. Misma forma que message.received con direction OUT, para que tu CRM vea los dos lados del chat.

  3. message.reaction, message.edited, message.deleted

    Alguien reaccionó con un emoji (o lo quitó), editó un mensaje o lo eliminó para todos. Cada uno señala su objetivo por externalId, y puede llegar antes que el mensaje al que afecta.

  4. message.sent y message.status

    Un mensaje que enviaste por API llegó a WhatsApp y luego pasó a DELIVERED, READ, FAILED o UNDELIVERABLE. message.status incluye previousStatus para ignorar un acuse antiguo.

  5. account.status_changed

    El número se conectó, se desconectó, se cerró su sesión o WhatsApp lo restringió (BLOCKED, con blockedUntil). Suscríbete para que una bandeja muda nunca pase desapercibida.

POST https://example.com/webhooks/umJSON
{
  "type": "message.received",
  "eventId": "whd_6f1c2a9e-1b7d-4c55-9a43-2f0e8b7d3c11",
  "occurredAt": "2026-11-09T10:00:01.000Z",
  "data": {
    "message": {
      "id": "msg_0e55ff33-854a-482c-8510-68226e09cdcb",
      "externalId": "3EB0A1C2D3E4F5061728",
      "direction": "IN",
      "fromMe": false,
      "content": "Hi! Is my order ready for pickup?",
      "sentAt": "2026-11-09T10:00:00.000Z",
      "receivedAt": "2026-11-09T10:00:01.000Z",
      "sender": "+447700900123",
      "senderId": "[email protected]",
      "senderName": "Lea",
      "participant": null,
      "replyTo": null,
      "transcript": null
    },
    "channel": {
      "type": "WHATSAPP",
      "account": { "id": "acc_373bc415-447a-4813-9b61-a3a09ea9aaf3", "name": "Support" },
      "conversation": {
        "id": "[email protected]",
        "isGroup": false,
        "address": "+447700900123"
      }
    }
  }
}
Un cuerpo message.received real, construido a partir del esquema publicado. sender va en formato +E.164, o null cuando WhatsApp oculta el número: entonces senderId identifica a la persona. Los eventos no llegan en orden: ordena por sentAt.

Puesta en marcha

¿Cómo recibir los mensajes de WhatsApp entrantes en Node.js?

Tres pasos: vincular el número, registrar un endpoint, verificar y procesar cada POST. Responde en menos de 10 segundos y haz el trabajo después.

  1. 01

    Vincula tu WhatsApp

    En la aplicación web, añade una cuenta de WhatsApp y escanea el código QR desde WhatsApp, Ajustes, Dispositivos vinculados. El número sigue en tu móvil.

  2. 02

    Registra el endpoint

    POST /webhooks con tu URL y tus eventTypes, o añádelo en la página Webhooks del panel. El secreto (whsec_...) se muestra una sola vez.

  3. 03

    Verifica, confirma, actúa

    Comprueba la cabecera webhook-signature, devuelve un 2xx y deduplica por eventId: la entrega es «al menos una vez».

POST /webhookscurl
curl https://api.unlimitedmessaging.app/webhooks \
  -H "Authorization: Bearer $UM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/webhooks/um",
    "eventTypes": ["message.received", "account.status_changed"],
    "description": "Incoming WhatsApp"
  }'

# The response carries "secret": "whsec_..." once. Store it as UM_WEBHOOK_SECRET.
accountIds es opcional: sin él, el endpoint cubre todas tus cuentas, incluidos los números que vincules más adelante. PATCH /webhooks/{id} sustituye la lista eventTypes.
handler del webhookNode.js / Express
import crypto from 'node:crypto';
import express from 'express';
import { UnlimitedMessagingApiClient } from '@unlimited-messaging/sdk';

const um = new UnlimitedMessagingApiClient({ token: process.env.UM_API_KEY! });
const key = Buffer.from(process.env.UM_WEBHOOK_SECRET!.replace(/^whsec_/, ''), 'base64');
const seen = new Set<string>(); // use your database in production

// Standard Webhooks: HMAC-SHA256 of "id.timestamp.rawBody", base64.
function verify(raw: string, id: string, ts: string, header: string) {
  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
  const expected = crypto.createHmac('sha256', key).update(`${id}.${ts}.${raw}`).digest('base64');
  return header.split(' ').some((entry) => {
    const sig = entry.startsWith('v1,') ? entry.slice(3) : '';
    return sig.length === expected.length &&
      crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
  });
}

const app = express();
app.post('/webhooks/um', express.raw({ type: 'application/json' }), async (req, res) => {
  const raw = req.body.toString('utf8');
  const ok = verify(raw, req.get('webhook-id') ?? '', req.get('webhook-timestamp') ?? '',
    req.get('webhook-signature') ?? '');
  if (!ok) return res.sendStatus(401);
  res.sendStatus(200); // answer within 10 s, work afterwards

  const event = JSON.parse(raw);
  if (seen.has(event.eventId)) return; // at-least-once delivery
  seen.add(event.eventId);

  if (event.type === 'message.received' && event.data.channel.type === 'WHATSAPP') {
    const { id, content } = event.data.message;
    if (content?.toLowerCase().includes('order')) {
      // Answers in the same chat, from the same linked number.
      await um.messages.messageSend({ replyToMessageId: id, text: 'Checking your order now.' });
    }
  }
});
app.listen(3000);
La verificación sigue el esquema documentado: HMAC-SHA256 sobre id.timestamp.rawBody con el secreto decodificado en base64, rechazando marcas de tiempo de más de 5 minutos. Cualquier librería de Standard Webhooks hace lo mismo. replyToMessageId responde en el mismo chat.

Vibe coding

¿Programas con Cursor, Claude Code, Lovable o Bolt? Pega esto

El prompt le da a tu editor con IA el endpoint, el esquema de firma y la forma de los eventos, para que escriba la ruta del webhook sin adivinar.

Prompt para copiar
Add an Unlimited Messaging webhook to this app so it receives incoming WhatsApp messages from my own number.

1. Create a POST route at /webhooks/um that reads the RAW request body (no JSON parsing before verification).
2. Verify the Standard Webhooks signature: key = base64-decode(UM_WEBHOOK_SECRET without its "whsec_" prefix); expected = base64(HMAC-SHA256(key, `${webhook-id}.${webhook-timestamp}.${rawBody}`)); accept if any space-separated entry of the webhook-signature header equals `v1,${expected}` (constant-time compare); reject timestamps more than 5 minutes off. Return 401 if invalid.
3. Return 200 at once, then process. Deduplicate on body.eventId.
4. On type "message.received" with data.channel.type "WHATSAPP", read data.message.content, data.message.sender (+E164 or null), data.message.senderName and data.message.mediaUrl, and save them.
5. To reply, install @unlimited-messaging/sdk, read UM_API_KEY from env, and call `new UnlimitedMessagingApiClient({ token }).messages.messageSend({ replyToMessageId: data.message.id, text })`.
6. Add UM_API_KEY and UM_WEBHOOK_SECRET to .env and .env.example, never hardcode them.

Docs: https://docs.unlimitedmessaging.app (Webhooks section). Register the URL with POST https://api.unlimitedmessaging.app/webhooks and eventTypes ["message.received"].

Lo que se construye

¿Qué puedes hacer con los mensajes de WhatsApp entrantes?

Todo lo que empieza por «cuando un cliente escribe». Algunos usos que encajan bien con el modelo de número vinculado.

Un contestador con IA en tu número real

Pasa content a Claude o GPT y devuelve la respuesta con replyToMessageId. Tus clientes siguen escribiendo al número que tienen guardado, y tú tomas el control desde el móvil cuando quieras.

WhatsApp en tu CRM o tu helpdesk

Guarda cada message.received y message.self_sent en la ficha del contacto, por sender o senderId, para que toda la conversación esté junto a la oportunidad o el ticket.

  1. Consultas de pedidos y reservas

    Detecta una palabra clave o un número de pedido en el texto, búscalo y responde en segundos. Los archivos llegan como fichero guardado que puedes descargar.

  2. Seguimiento de grupos

    En un grupo, participant indica quién escribió y channel.conversation.participants lista los miembros, actualizados cuando cambia el grupo.

  3. Alertas para el equipo

    Reenvía un mensaje urgente a Slack o por email, o avisa a alguien cuando account.status_changed informa de una desconexión.

  4. Flujos sin código

    Apunta el webhook a n8n, Make o Zapier y ramifica según type y channel.type sin escribir un servidor.

La tabla

Webhooks de WhatsApp entrantes: Cloud API de Meta, Twilio y Unlimited Messaging

Meta y Twilio son la plataforma Business oficial, con sus aprobaciones y su precio por mensaje. Unlimited Messaging vincula el número que ya tienes.

Webhooks de WhatsApp entrantes: Cloud API de Meta, Twilio y Unlimited Messaging
Meta Cloud APIOficial, directoTwilio WhatsAppOficial, vía proveedorUnlimited MessagingDispositivo vinculado, planes de pago
Qué configuras primeroApp de Meta, portfolio comercial, cuenta de WhatsApp BusinessCuenta de Twilio, portfolio de Meta Business, WABA creada desde TwilioEscanear un código QR desde tu móvil
Tu número actualRegistrado en la plataformaNo puede estar ya registrado en WhatsAppSe conserva y sigue funcionando en tu móvil
Aprobación y límites250 destinatarios al día iniciados por la empresa hasta verificar; App Review para tech providersVerificación de empresa de Meta antes de producciónNinguna de Meta; se aplican las reglas antispam de WhatsApp
Verificación del endpointGET de verificación con hub.challenge, TLS válido, sin autofirmadosURL de webhook configurada en el remitenteNinguna: registras la URL y recibes
FirmaX-Hub-Signature-256, HMAC-SHA256 con el secreto de la appX-Twilio-Signature, HMAC-SHA1 con el auth tokenStandard Webhooks, HMAC-SHA256 con un secreto por endpoint
Formato del cuerpoJSON, anidado en entry/changesForm-encoded (application/x-www-form-urlencoded)JSON, el mismo sobre para email y SMS
ReintentosFrecuencia decreciente durante un máximo de 7 díasNo se indica en la documentación de webhooks8 intentos en algo más de 3 días
Coste de recibir y responderRespuestas de servicio gratis hasta 1.000 por número al mes, luego de pago; plantillas de pago0,005 $ por mensaje, entrante o saliente, más las tarifas de MetaSin coste por mensaje; webhooks con Medium o Max

Comprobado el 9 de noviembre de 2026 en la documentación de Meta (webhooks, límites de mensajes, precios) y en las páginas de Twilio (alta de WhatsApp, precios, seguridad de webhooks). Enlaces en las fuentes.

La letra pequeña

¿Qué límites tiene un webhook de WhatsApp con número vinculado?

Prescindir de Meta elimina las aprobaciones. No elimina las reglas de WhatsApp ni las realidades de un dispositivo vinculado.

  1. Los webhooks son de pago

    El plan Free envía y muestra los mensajes recibidos en la aplicación web, pero enviarlos a tu servidor requiere Medium (19 € al mes, o 17 € al mes con pago anual) o Max. Sin coste por mensaje en ninguno.

  2. No es oficial

    El protocolo de dispositivos vinculados es el de WhatsApp Web, no una API de Meta. WhatsApp puede restringir un número que hace spam o recibe denuncias: account.status_changed te avisa, con blockedUntil cuando se conoce.

  3. Un dispositivo vinculado sigue las reglas de WhatsApp

    WhatsApp cierra la sesión de los dispositivos vinculados si el móvil principal pasa 14 días sin conexión. Abre WhatsApp en el móvil de vez en cuando y el vínculo funciona aunque el móvil esté apagado.

  4. El orden y los duplicados son cosa tuya

    La entrega es «al menos una vez» y sin orden garantizado: un texto enviado justo después de una foto suele llegar antes, porque la foto espera a que su archivo se guarde. Deduplica por eventId y ordena por sentAt.

  5. El historial es opcional

    Solo se anuncian los mensajes recibidos después de vincular, salvo que la cuenta se vinculara con syncHistory: los chats antiguos llegan entonces en lotes message.history de hasta 100 mensajes (archivos descritos, no guardados).

FAQ

Preguntas sobre los webhooks de WhatsApp

Ilian, ingeniero de software senior

Escrito por

· Ingeniero de software senior

Ingeniero de software senior, funda y dirige varias empresas tecnológicas. Diseña productos en torno a las API de mensajería, la automatización y la integración de la IA, y comparte aquí lo que aprende construyendo.

Ver el perfil de LinkedInActualizado el

Tus mensajes de WhatsApp, en tu servidor.

Crea una cuenta, vincula tu número con un código QR y activa los webhooks con Medium o Max. Enviar sigue siendo gratis en todos los planes.