Webhooks

Un webhook de entrada permite que otro sistema publique en un canal enviando JSON a una URL secreta. Un webhook de salida hace lo contrario: envía mensajes a tu URL, aquellos que empiezan con una palabra que dispara la acción o aquellos para los que las personas lo eligen en el menú del mensaje, y publica lo que respondas.

Dónde gestionar webhooks

Abre el menú del equipo, luego Configuración del equipo, y haz clic en Integraciones al final de sus pestañas. Las páginas de integraciones del equipo actual listan Webhooks de Entrada y Webhooks de Salida. Cada webhook pertenece a un equipo.

Por defecto, los administradores de la comunidad y los administradores de sistema pueden crear webhooks. Un administrador de sistema puede otorgar este permiso a otros roles en la configuración de permisos de la Consola de sistema. Un administrador de sistema también puede desactivar cada tipo en Consola de sistema › Integraciones › Gestión de Integraciones: Habilitar Webhooks de Entrada y Habilitar Webhooks de Salida están ambos habilitados por defecto.

A channel with messages from a CI bot and from GitHub, shown as cards with fields, pipeline stages and a button
Mensajes de integración representados como tarjetas: campos, etapas de la canalización y un botón de acción.

Crear un webhook entrante

  1. En Integraciones, selecciona Webhooks de Entrada y luego Agregar Webhook de Entrada.
  2. Completa un Título y una Descripción: solo se muestran en las páginas de integraciones.
  3. Selecciona el Channel al que van los mensajes por defecto. Para un canal privado, debes ser miembro de él.
  4. Marca Fijar a este canal si los remitentes no deben poder publicar en otros lugares.
  5. Opcionalmente, configura una URL para el Nombre de usuario y la Foto del Perfil de sus mensajes (ver Nombre e icono).
  6. Selecciona Guardar. Copia la URL mostrada: https://chat.example.com/hooks/<key>.
La URL es el único secreto: cualquiera que la tenga puede publicar en el canal. Manténla fuera de repositorios públicos y elimina el webhook si se filtra.

Con la API: POST /api/v4/hooks/incoming con {"channel_id", "display_name", "description", "username", "icon_url", "channel_locked"}; el id de la respuesta es la clave. Desde la línea de comandos: amctl webhook create-incoming --channel <channel id> --user <user> --display-name "CI".

Enviar un mensaje a un webhook entrante

curl -X POST https://chat.example.com/hooks/xgh5ycrx1jf7mbs9w8z4c8e7ho \
  -H 'Content-Type: application/json' \
  -d '{"text": "Deploy of **api 2.4.0** finished :white_check_mark:"}'

El servidor responde 200 con el cuerpo ok. También acepta application/x-www-form-urlencoded con el JSON en un campo payload, como hacen los webhooks de Slack, por lo que las herramientas hechas para Slack suelen funcionar sin cambios.

CampoSignificado
textEl mensaje, en Markdown. Obligatorio, salvo que haya attachments. Un texto más largo que el límite de mensajes del servidor se divide en varios mensajes.
channelOtro canal del equipo del webhook, por nombre (ops-alerts o #ops-alerts), o @username para un mensaje directo del propietario del webhook. Se rechaza cuando el webhook está bloqueado en su canal. El nombre antiguo town-square sigue llegando al canal predeterminado del equipo, ahora llamado general.
username, icon_url, icon_emojiEl nombre y la imagen que se mostrarán, si el servidor permite reemplazos.
attachmentsAdjuntos del mensaje, representados como tarjetas (abajo).
propsPropiedades adicionales almacenadas en el mensaje, para aplicaciones que las leen. Publicar en un canal de foro requiere props.am_thread_title (de 1 a 100 caracteres): el webhook se rechaza sin uno (consulta Los foros solo aceptan temas).
typeUn tipo de mensaje personalizado, como custom_poll, para una app que lo represente. Se rechazan los tipos que comienzan por system_.
root_idEl ID del primer mensaje de un hilo, para responder en ese hilo.
priorityPrioridad del mensaje, por ejemplo {"priority": "urgent"}.
silenttrue envía el mensaje sin notificaciones push.

Cada mensaje que publica un webhook lleva una etiqueta BOT junto a su nombre, incluso cuando aparece bajo el nombre de su creador, para que las personas puedan distinguirlo de un mensaje de una persona real. Los mensajes de webhook nunca activan webhooks de salida.

Nombre e icono

Un webhook publica como la persona que lo creó, a menos que el servidor permita reemplazos. Dos ajustes en Consola de sistema › Integraciones › Gestión de integraciones, ambos desactivados por defecto, cambian esto:

  • Permitir a las integraciones reescribir nombres de usuario (ServiceSettings.EnablePostUsernameOverride): se muestra el Nombre de usuario del webhook o el parámetro username de la solicitud; si no hay ninguno, el nombre es webhook.
  • Permitir a las integraciones reescribir imágenes de perfil (ServiceSettings.EnablePostIconOverride): se muestra la Foto del Perfil del webhook, o el parámetro icon_url o icon_emoji de la solicitud.

Un valor en la solicitud tiene prioridad sobre el guardado en el webhook.

Adjuntos

Los adjuntos añaden contenido estructurado debajo del texto. Siguen el formato de adjuntos de mensajes de Slack:

{
  "text": "Build failed on `main`",
  "attachments": [{
    "fallback": "main #1902 failed",
    "color": "#d24b4e",
    "author_name": "GitHub Actions",
    "author_icon": "https://chat.example.com/static/ci.png",
    "title": "main #1902 failed",
    "title_link": "https://ci.example.com/runs/1902",
    "text": "Commit `0f4d8e2` by Jonas Weber",
    "fields": [
      {"title": "Branch", "value": "zephyr-3.7", "short": true},
      {"title": "Duration", "value": "3m 40s", "short": true}
    ],
    "footer": "Lumen CI",
    "ts": 1760000000
  }]
}
CampoSignificado
fallbackTexto plano para lugares que no pueden mostrar la tarjeta, como las notificaciones.
colorLa barra de color: un color hexadecimal, o good, warning, danger.
pretextTexto sobre la tarjeta.
author_name, author_link, author_iconUna pequeña línea de encabezado.
title, title_linkEl título de la tarjeta, opcionalmente un enlace.
textEl cuerpo de la tarjeta, en Markdown.
fieldsUna lista de {"title", "value", "short"}; los campos short se colocan uno al lado del otro.
image_url, thumb_urlUna imagen grande abajo, o una pequeña al lado.
footer, footer_icon, tsUna línea de pie de página y una hora (segundos Unix).
actionsBotones y menús: ver Mensajes interactivos.

Tarjetas: etapas y gráficos

Antimatter añade dos campos a los adjuntos, que la interfaz predeterminada representa:

  • stages: los pasos de un pipeline como pastillas, hasta 20. Cada uno es {"name", "status"}, con un estado de passed, failed, running, pending, skipped o canceled.
  • chart: un pequeño gráfico de líneas de valores recientes, {"values": [2 to 200 numbers], "threshold": number, "label": "…"}. El umbral se dibuja como una línea discontinua, para el límite de una alerta.
{
  "attachments": [{
    "color": "danger",
    "title": "main #1902 failed",
    "stages": [
      {"name": "build", "status": "failed"},
      {"name": "unit", "status": "skipped"},
      {"name": "publish", "status": "skipped"}
    ]
  }, {
    "color": "warning",
    "title": "API latency above 400 ms",
    "chart": {"values": [210, 230, 260, 390, 450, 470], "threshold": 400, "label": "p95 latency, ms"}
  }]
}

La interfaz clásica y otros clientes ignoran estos dos campos, así que también incluye lo esencial en text o fields.

Crear un webhook saliente

Un webhook de salida observa los canales Público de un equipo. Envía un mensaje a tu URL ya sea cuando la primera palabra del mensaje coincide con una de sus palabras que disparan la acción, o cuando alguien lo elige en el menú del mensaje (una acción de mensaje).

  1. En Integraciones, selecciona Webhooks de Salida y luego Agregar Webhook de Salida.
  2. Completa el Título y la Descripción.
  3. Selecciona el Tipo de contenido de la solicitud: application/x-www-form-urlencoded o application/json.
  4. Selecciona un Canal, ingresa las Palabras que disparan acciones (Una por Línea), o ambos. Con un canal y sin palabras que disparan la acción, se envía cada mensaje de ese canal. Con ambos, el mensaje debe coincidir con ambos.
  5. En Disparar Cuando, elige La primera palabra coincide exactamente con una palabra que dispara la acción, La primera palabra empieza con una palabra que dispara la acción, o Desde el menú del mensaje. Con Desde el menú del mensaje, las palabras que disparan la acción desaparecen, el Canal es opcional (sin uno, la acción se ofrece en todos los canales públicos del equipo), y el Título es obligatorio: es el nombre de la acción en el menú.
  6. Ingresa las Callback URLs (Uno por Línea). Cada URL recibe cada mensaje coincidente.
  7. Opcionalmente, establece el Nombre de usuario y la Foto del Perfil que se usarán en las respuestas. Para una acción del menú del mensaje, el campo Icono sustituye a Foto del Perfil: la URL de una imagen .png o .jpg o, en la interfaz predeterminada de Antimatter, una imagen subida. El menú la muestra en gris; si no hay ninguna, la acción obtiene un icono neutro.
  8. Selecciona Guardar y copia el token mostrado. Tu servicio lo utiliza para verificar que las solicitudes provienen de tu servidor.

Con la API: POST /api/v4/hooks/outgoing con {"team_id", "channel_id", "trigger_words", "trigger_when", "callback_urls", "content_type", "display_name"} (trigger_when: 0 para una coincidencia exacta, 1 para "empieza con", 2 para "desde el menú del mensaje"). Un webhook con trigger_when 2 no admite palabras de activación y requiere un display_name. Sube su icono con POST /api/v4/hooks/outgoing/{hook_id}/icon (multipart, campo image: PNG, JPEG o GIF, almacenado como un PNG de 128 px); su icon_url apuntará entonces a GET /api/v4/hooks/outgoing/{hook_id}/icon.

The outgoing webhook form with Trigger When set to From the message menu, and the Icon field below it
Disparador cuando se establece en Desde el menú del mensaje, con el campo Icono.
Si tu servicio está en una red privada, un administrador del sistema debe permitir su dirección en Permitir conexiones internas no son de confianza (ServiceSettings.AllowedUntrustedInternalConnections). De lo contrario, el servidor no llamará a direcciones privadas.

La solicitud saliente

Antimatter envía un POST con estos campos, como JSON o codificado en formulario según el tipo de contenido:

{
  "token": "6kd1ofo5ojr5zgu5ipfipybgnc",
  "team_id": "…",
  "team_domain": "lumen-labs",
  "channel_id": "…",
  "channel_name": "ops-alerts",
  "timestamp": 1760010000000,
  "user_id": "…",
  "user_name": "priya",
  "post_id": "…",
  "text": "deploy api 2.4.0",
  "trigger_word": "deploy",
  "file_ids": ""
}

Compara token con el token del webhook antes de hacer nada. En la versión codificada en formulario, timestamp está en segundos en lugar de milisegundos. El servidor espera tu respuesta durante el tiempo que permita Tiempo de espera de solicitud de integración (30 segundos por defecto, ServiceSettings.OutgoingIntegrationRequestsTimeout).

Responder a un webhook saliente

Para publicar una respuesta, responde con JSON. Para no publicar nada, responde con un cuerpo vacío.

{
  "text": "Deploying **api 2.4.0** to staging…",
  "response_type": "comment",
  "username": "deploy-bot",
  "icon_url": "https://chat.example.com/static/deploy.png"
}
  • text y attachments: la respuesta. Sin ninguno de los dos, no se publica nada.
  • response_type: comment publica la respuesta en el hilo del mensaje que la activó; de lo contrario, se publica en el canal.
  • username, icon_url: se muestran cuando el servidor permite sobrescribirlos; en caso contrario, se usan los valores propios del webhook.
  • props, type, priority: como en los webhooks entrantes.

La respuesta se publica como el creador del webhook, bajo el nombre sobrescrito si lo hay. Para cualquier cosa más larga que una respuesta rápida, responde de inmediato y publica después con un webhook entrante o la API.

Acciones de mensaje

Una acción de mensaje es un webhook saliente con Disparar Cuando establecido en Desde el menú del mensaje. Nunca se activa con los mensajes publicados. En su lugar, las personas la ven en el menú de un mensaje: Acciones de mensajes (⋯) › Más Acciones, bajo el encabezado Integraciones, con su icono. La interfaz clásica no muestra las acciones de mensajes. Al seleccionarla, se envía ese mensaje concreto a las URL de devolución de llamada, y un aviso breve indica Enviado a el nombre de la acción, o muestra tu ephemeral_text.

  • Dónde se muestra: en el canal del webhook o, si no hay canal, en todos los canales públicos de su comunidad. Solo los canales públicos tienen acciones de mensajes.
  • Los Invitados solo reciben las acciones vinculadas a un canal en el que se encuentran, no las de toda la comunidad.
  • Canales archivados y de solo lectura: el mensaje aún puede enviarse. Archivar un canal elimina los webhooks vinculados a él, por lo que un canal archivado solo conserva las acciones de toda la comunidad. Una respuesta que la persona no pudo publicar allí se le muestra solo a ella.
  • Límite de frecuencia: cada persona puede ejecutar 10 acciones de mensajes por minuto, tras una ráfaga de 5. Por encima de eso, el servidor responde con 429.
  • Redes privadas: al igual que con otros webhooks salientes, las direcciones internas deben estar permitidas en Permitir conexiones internas no son de confianza.

La solicitud

La carga útil se envía como JSON o codificada en formulario, según el tipo de contenido del webhook:

{
  "token": "6kd1ofo5ojr5zgu5ipfipybgnc",
  "trigger": "message_action",
  "team_id": "…",
  "team_domain": "lumen-labs",
  "channel_id": "…",
  "channel_name": "ops-alerts",
  "timestamp": 1760010000000,
  "user_id": "…",
  "user_name": "priya",
  "post_id": "…",
  "post_root_id": "",
  "post_create_at": 1760009000000,
  "post_user_id": "…",
  "post_user_name": "jonas",
  "permalink": "https://chat.example.com/lumen-labs/pl/…",
  "text": "The staging database is full again",
  "files": [{"id": "…", "name": "df.txt", "link": "https://chat.example.com/api/v4/files/…"}],
  "priority": "",
  "requested_ack": false,
  "burn_on_read": false
}
  • user_id y user_name son la persona que seleccionó la acción; post_user_id y post_user_name son el autor del mensaje.
  • Solo se envía ese mensaje, nunca el resto del hilo.
  • files enumera los archivos del mensaje solo si la persona que seleccionó la acción puede descargarlos. Para descargar un link se necesita una sesión o un token, como con cualquier archivo de la API.
  • Un mensaje de lectura única se envía sin su texto ni sus archivos, con burn_on_read establecido en true.
  • Con codificación de formulario, los archivos se envían como campos repetidos file_id, file_name y file_link, en el mismo orden.

La respuesta

Responde como lo harías con cualquier webhook saliente (consulta Responder a un webhook saliente): text o attachments publican una respuesta en el canal, y "response_type": "comment" la publica en el hilo del mensaje. También puedes responder con ephemeral_text (limitado a 300 caracteres): se muestra únicamente a la persona que seleccionó la acción, en la notificación. Un cuerpo vacío no publica nada.

{"ephemeral_text": "Ticket OPS-412 created"}

Con la API

  • GET /api/v4/channels/{channel_id}/message_actions: las acciones que puedes seleccionar en un canal, con id, display_name, description y icon_url. No se devuelven ni tokens ni URLs de devolución de llamada.
  • POST /api/v4/posts/{post_id}/message_actions/{hook_id}: ejecuta una acción en un mensaje que puedes leer. Responde con {"ephemeral_text"}.

Cuando un webhook no funciona

  • 501 desde la URL del webhook: los webhooks entrantes están desactivados en el servidor.
  • 400 "Failed to decode the payload…": el JSON no es válido, o el campo del formulario no se llama payload. "No text specified." significa que la solicitud no tiene ni text ni attachments.
  • 403: el webhook está bloqueado a otro canal, o su propietario ya no puede leer el canal.
  • Un webhook saliente nunca se activa: el canal es privado, el disparador no es la primera palabra, el mensaje proviene de un webhook o el webhook está configurado para activarse Desde el menú del mensaje.
  • Una acción de mensaje no aparece en el menú: el canal es privado, la acción está vinculada a otro canal, la persona es un invitado y la acción no tiene canal, o los webhooks salientes están desactivados.
  • 404 al ejecutar una acción de mensaje: la acción no existe o no cubre el canal de ese mensaje para esa persona. 429: la persona ejecutó más de 10 acciones en un minuto. 502: no se pudo acceder a ninguna de las URLs de devolución de llamada (el registro indica el motivo).
  • Se rechaza una publicación en un foro: el mensaje del webhook necesita un título (props.am_thread_title); el error indica el motivo, como app.post.forum.title_required.app_error, en lugar de un error genérico (consulta Tipos de canal).
  • Registros: con Habilitar Depuración de Webhook activado (LogSettings.EnableWebhookDebugging) y el nivel de registro en DEBUG, el servidor registra las cargas de las solicitudes entrantes fallidas. Las salidas fallidas se registran como Outgoing Webhook POST failed.