CRM - Agente con IA Developers

Webhooks

Recibí un POST con JSON cuando cambian los datos de tu cuenta. Usá los eventos para activar tu proceso y la API para consultar o reconciliar el estado actual.

Crear una suscripción

Desde el panel: Ajustes → Integraciones → Webhooks → Agregar. Necesitás permisos de administrador.

Por API, usando las variables de la introducción:

curl --fail-with-body --request POST \
  "$CRM_BASE_URL/api/v1/accounts/$CRM_ACCOUNT_ID/webhooks" \
  --header "api_access_token: $CRM_API_TOKEN" \
  --header "Content-Type: application/json" \
  --data '{
    "webhook": {
      "url": "https://tu-sistema.example/hooks/crm/SECRETO_ALEATORIO",
      "subscriptions": ["conversation_created", "conversation_updated",
        "conversation_status_changed", "message_created", "message_updated"]
    }
  }'

El objeto webhook es obligatorio. Reemplazá la URL por tu receptor HTTPS y un secreto aleatorio propio. Para revisar las suscripciones usá GET .../webhooks; para modificar una, PATCH .../webhooks/{id} con el mismo envoltorio; para eliminarla, DELETE .../webhooks/{id}.

Eventos disponibles

Evento Cuándo se emite Recurso
conversation_created Se crea una conversación; una reapertura no es una creación. Conversación.
conversation_updated Cambian atributos observados de la conversación. Conversación y changed_attributes.
conversation_status_changed Cambia status. Conversación y changed_attributes.
message_created Se crea un mensaje entrante, saliente o de tipo template; incluye notas privadas. Mensaje.
message_updated Se actualiza un mensaje enviable por webhook, por ejemplo su contenido o estado. Mensaje.
contact_created / contact_updated Se crea o actualiza un contacto. Contacto.
inbox_created / inbox_updated Se crea o actualiza una bandeja. Bandeja.
webwidget_triggered Se dispara el evento del widget web. Contacto, bandeja e información del evento.

Los mensajes de actividad no se envían por message_created ni message_updated. Para cambios de estado o asignación usá eventos de conversación; para leer las actividades, consultá el historial por API. Algunos conectores guardan cambios sin emitir eventos: programá reconciliaciones si necesitás consistencia.

Ejemplo de conversación

Payload abreviado de conversation_status_changed:

{
  "event": "conversation_status_changed",
  "id": 4821,
  "account": { "id": 123, "name": "Mi empresa" },
  "inbox_id": 12,
  "channel": "Channel::Whatsapp",
  "status": "resolved",
  "labels": ["presupuesto-enviado"],
  "custom_attributes": {},
  "additional_attributes": {},
  "meta": {
    "sender": { "id": 991, "name": "Ana Pérez", "type": "contact" },
    "assignee": { "id": 7, "name": "Lucía", "type": "user" }
  },
  "messages": [],
  "changed_attributes": [
    { "status": { "previous_value": "open", "current_value": "resolved" } }
  ],
  "created_at": 1788357600
}

changed_attributes es un array de objetos, no un objeto único. created_at es la fecha de creación de la conversación; no identifica cuándo ocurrió cada actualización. messages contiene como máximo un mensaje del chat, no el historial completo.

meta.assignee es el responsable actual, no necesariamente quien hizo el cambio. El actor de un cambio no está garantizado como campo estructurado del webhook.

Ejemplo de mensaje

{
  "event": "message_created",
  "id": 88210,
  "account": { "id": 123, "name": "Mi empresa" },
  "inbox": { "id": 12, "name": "Atención" },
  "conversation": { "id": 4821, "status": "open", "inbox_id": 12 },
  "content": "Hola, necesito un presupuesto",
  "content_type": "text",
  "content_attributes": {},
  "message_type": "incoming",
  "private": false,
  "status": "sent",
  "sender": { "id": 991, "name": "Ana Pérez", "phone_number": "+5491155551234" },
  "created_at": "2026-09-02T14:00:00.000Z"
}

El ejemplo recorta los objetos anidados. En eventos de mensaje, message_type es texto; por API y dentro de conversation.messages es numérico. El sender de un contacto no incluye necesariamente type: para reconocer mensajes del cliente usá message_type: "incoming". Usuarios y bots pueden incluir sender.type: "user" o "agent_bot"; una integración que usa un token de usuario figura como ese usuario.

Para evitar bucles, un receptor que responde al cliente debe filtrar por event === "message_created", message_type === "incoming" y private === false. No respondas a tus propios mensajes salientes.

Entrega y reintentos

Respondé con 2xx después de guardar el evento en una cola o almacenamiento duradero, y procesalo en segundo plano. El timeout predeterminado es de 5 segundos y puede variar por instalación.

Resultado del receptor Política actual
2xx Entrega aceptada.
502, 503, 504, timeout de conexión, conexión rechazada y ciertos errores de red Hasta 7 reintentos, con esperas base de 5, 10, 20, 40, 80, 120 y 120 segundos. La cola puede agregar demora.
Timeout de lectura (no llega la respuesta) Un reintento corto; después no se vuelve a enviar automáticamente. El receptor pudo haber procesado el primer intento.
400, 401, 403, 404, 405, URL inválida o ciertos fallos de resolución Se descarta sin reintentar.
Otros errores, como 500, 422, 429 Cola general con espera creciente, limitada por el máximo del job (7 reintentos) y la configuración del servidor.

Estas esperas no son un SLA de entrega. Un webhook puede agotar sus intentos: no lo trates como una copia infalible de todos los cambios. Usá la API para recuperar y reconciliar datos.

Duplicados y orden

Los eventos pueden llegar repetidos y fuera de orden. No hay un identificador único de entrega documentado.

  • Para creaciones de mensajes, podés registrar (account.id, event, id) como clave de procesamiento.
  • Para actualizaciones, no dedupliques de forma permanente por id + event: el mismo mensaje puede pasar de sent a delivered y a read; la misma conversación puede abrirse y resolverse varias veces.
  • Para mantener una copia de recursos, usá el webhook como aviso, agrupá avisos cercanos y consultá el estado actual por API antes de persistirlo.
  • Un hash temporal del payload puede reducir entregas idénticas, pero no representa una versión del recurso ni distingue todos los cambios legítimos.

No ordenes actualizaciones por created_at: esa fecha corresponde al recurso. Si ejecutás acciones irreversibles a partir de eventos, definí tu propia idempotencia de negocio y verificá el estado.

Seguridad del receptor

Estos webhooks no incluyen una firma criptográfica verificable. Un secreto en la URL reduce accesos no autorizados, pero no equivale a una firma del contenido.

Usá HTTPS, compará el secreto recibido y evitá registrar la URL completa. Validá account.id y el tipo de evento. Antes de una acción sensible, confirmá los datos con tu token a través de la API. El receptor puede recibir conversaciones, datos de contacto y notas privadas: limitá quién puede acceder a ellos.

Probar antes de conectar tu sistema

  1. Registrá el webhook con una URL de prueba controlada por vos.
  2. Enviá un mensaje desde un contacto de prueba y verificá message_created.
  3. Respondé desde el CRM y comprobá que tu filtro ignore el mensaje saliente.
  4. Cambiá el estado y verificá el array changed_attributes.
  5. Reproducí el mismo payload dos veces en tu receptor y verificá que no duplique la acción.
  6. Simulá un error temporal del receptor y comprobá la recuperación.

Usá datos ficticios si inspeccionás eventos con un servicio externo de captura de webhooks.

¿Falta algo en la documentación?

Contanos qué intentabas hacer y qué información necesitás. El equipo revisa cada reporte para mejorar estas guías.

La página se incluye en el reporte. No necesitás una cuenta de Monday.