API y webhooks

Webhooks: recibir eventos en tiempo real

Recibe en tu URL, en tiempo real, los eventos de WhatsApp y los comentarios y DM de Instagram, verifica la firma y entiende los reintentos.

Actualizado el

Con el alcance Recibir eventos (comentarios y DM) por webhook (webhooks:manage), registras una URL de tu sistema y XBASE le envía, en tiempo real, los comentarios y los DM que llegan a las cuentas de Instagram del workspace.

Registrar el webhook

PUT https://api.xbase.app/api/external/v1/webhook
curl -X PUT https://api.xbase.app/api/external/v1/webhook \
  -H "Authorization: Bearer $XBASE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://misistema.com/xbase/webhook", "events": ["instagram.comment", "instagram.message"] }'

Respuesta 200:

{
  "url": "https://misistema.com/xbase/webhook",
  "events": ["instagram.comment", "instagram.message"],
  "secretLast4": "Q2w9",
  "updatedAt": "2026-11-04T16:10:00.000Z",
  "secret": "whsec_…"
}

El secret aparece solo en esta respuesta: guárdalo para verificar la firma. Cada clave tiene un webhook. Llamar al PUT de nuevo cambia la URL y los eventos y genera un secreto nuevo.

La URL tiene que ser https y pública.

Consultar y desactivar

  • GET /webhook devuelve la URL, los eventos, los 4 últimos caracteres del secreto (secretLast4) y updatedAt. Sin webhook registrado, responde 200 con el cuerpo vacío.
  • DELETE /webhook desactiva el webhook y responde 204, sin cuerpo.
  • Revocar la clave también desactiva su webhook.

Eventos

EventoCuándo
instagram.commentAlguien comenta en un post de una cuenta del workspace
instagram.messageLlega un DM a una cuenta del workspace

Cada entrega es un POST a tu URL:

POST https://misistema.com/xbase/webhook
Content-Type: application/json
x-xbase-Signature: t=1793808600,v1=5d41402abc4b2a76b9719d911017c592…
x-xbase-Delivery: 0b9f7c1e-…
x-xbase-Event: instagram.comment
{
  "id": "0b9f7c1e-…",
  "type": "instagram.comment",
  "occurredAt": "2026-11-04T16:10:00Z",
  "workspaceId": "8f0c2d4e-…",
  "account": { "connectionId": "6d1f…", "instagramAccountId": "1784…", "username": "miempresa" },
  "comment": {
    "id": "17900000000000000",
    "text": "¿Cuánto cuesta?",
    "mediaId": "18010000000000000",
    "parentId": null,
    "from": { "id": "…", "username": "fulano" }
  }
}

En el evento instagram.message, en lugar de comment viene message: { "mid", "text", "isEcho", "from": { "id" }, "attachments": [{ "type", "url" }] }.

El webhook de la clave envía los eventos de Instagram. Los de WhatsApp salen por los webhooks del workspace.

Webhooks del workspace: WhatsApp e Instagram

Para recibir los eventos de WhatsApp, registra el webhook en Integraciones → Webhooks (o con las herramientas create-webhook y update-webhook del MCP). Necesita el permiso de gestionar integraciones. Son hasta 10 webhooks por workspace, y cada uno elige:

  • Números: todos los números de WhatsApp del workspace o solo los elegidos.
  • Eventos, de la tabla de abajo.
  • Formato: XBASE (estándar), firmado.
EventoCuándo
whatsapp.message.receivedLlega un mensaje a un número del workspace, incluido el botón tocado, la fila elegida en una lista y la respuesta de un Flow
whatsapp.message.sent · .delivered · .read · .failedUn mensaje enviado cambia de estado
instagram.comment · instagram.messageLos mismos de esta página

La entrega usa los mismos encabezados, la misma firma y los mismos reintentos de esta página. El cuerpo trae el número y, en payload, el evento en el formato del webhook de Meta, con un solo ítem (messages[0] o statuses[0]):

{
  "id": "3c2a…",
  "type": "whatsapp.message.delivered",
  "occurredAt": "2026-11-04T16:10:00Z",
  "workspaceId": "8f0c2d4e-…",
  "connection": { "id": "6d1f…", "provider": "CLOUD", "appName": null, "number": "+55 11 99999-0000" },
  "payload": {
    "object": "whatsapp_business_account",
    "entry": [{
      "id": "102290129340398",
      "changes": [{
        "field": "messages",
        "value": {
          "messaging_product": "whatsapp",
          "metadata": { "display_phone_number": "5511999990000", "phone_number_id": "106540352242922" },
          "statuses": [{ "id": "wamid.…", "status": "delivered", "timestamp": "1793808600", "recipient_id": "5521999990000" }]
        }
      }]
    }]
  }
}

connection.id es el id del número en GET /whatsapp/numbers. El id del ítem (messages[0].id o statuses[0].id) es el messageId de la API de WhatsApp: el de las respuestas de envío y el que va en la reacción y en la lectura.

El secreto de firma aparece una vez, en la pantalla, justo después de crear. La misma entrega puede llegar más de una vez: ignora las repetidas por el id del ítem.

Verificar la firma

El encabezado x-xbase-Signature tiene la hora (t, en segundos) y la firma (v1): el HMAC-SHA256, en hexadecimal, de "<t>.<cuerpo>" con tu secret. Rechaza la entrega si la firma no coincide o si t tiene más de 5 minutos. Ejemplo en Node.js:

import { createHmac, timingSafeEqual } from 'node:crypto';

// rawBody: el cuerpo exactamente como llegó, antes de cualquier JSON.parse.
function isValidSignature(rawBody, header, secret) {
  const { t, v1 } = Object.fromEntries(header.split(',').map((part) => part.split('=')));
  if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false; // hasta 5 minutos
  const expected = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
  return v1.length === expected.length && timingSafeEqual(Buffer.from(v1), Buffer.from(expected));
}

Entrega y reintentos

  • La entrega cuenta como hecha cuando tu URL responde 2xx en hasta 10 segundos. Responde rápido y procesa después.
  • Sin 2xx, XBASE lo intenta 5 veces más: después de 1 minuto, 5 minutos, 30 minutos, 2 horas y 6 horas. Después de eso, desiste.
  • La misma entrega puede llegar más de una vez. Ignora las repetidas por x-xbase-Delivery, o por comment.id y message.mid.

Preguntas frecuentes

Ver también

En esta página