웹훅

수신 웹훅은 다른 시스템이 비밀 URL로 JSON을 보내어 채널에 게시할 수 있게 합니다. 송신 웹훅은 그 반대입니다. 트리거 단어로 시작하는 메시지나 메시지 메뉴에서 사용자가 선택한 메시지를 사용자의 URL로 보내고, 사용자의 답변을 게시합니다.

웹훅 관리 위치

오른쪽 상단의 아바타를 클릭한 후 통합을 선택합니다. 현재 커뮤니티의 통합 페이지에는 전체 Incoming Webhook과 전체 Outgoing Webhook가 나열됩니다. 각 웹훅은 하나의 커뮤니티에 속합니다.

By default, community admins and system admins can create webhooks. A system admin can give the right to other roles in the permission settings of the System Console. A system admin can also turn each kind off in System Console › Integrations › Integration Management: Enable Incoming Webhooks and Enable Outgoing Webhooks are both on by default.

A channel with messages from a CI bot and from GitHub, shown as cards with fields, pipeline stages and a button
카드로 렌더링된 연결 메시지: 필드, 파이프라인 단계 및 작업 버튼.

수신 웹훅 생성

  1. 통합에서 전체 Incoming Webhook을 선택한 후 Incoming Webhook 추가하기를 클릭합니다.
  2. 제목과 설명을 입력하세요: 이들은 연결 페이지에만 표시됩니다.
  3. 메시지가 기본적으로 전송될 채널을 선택하세요. 비공개 채널의 경우 해당 채널의 멤버여야 합니다.
  4. 발신자가 다른 곳에 게시할 수 없도록 해야 하는 경우 이 채널로 고정을 선택합니다.
  5. 선택적으로 해당 메시지의 사용자 이름과 프로필 사진 URL을 설정할 수 있습니다(참조: 이름과 아이콘).
  6. 저장을 선택하세요. 표시되는 URL을 복사하세요: https://chat.example.com/hooks/<key>.
URL은 유일한 비밀입니다: 이를 가진 사람은 누구나 채널에 게시할 수 있습니다. 공개 저장소에 노출하지 마시고, 유출된 경우 웹훅을 삭제하세요.

API를 통해: POST /api/v4/hooks/incoming에 {"channel_id", "display_name", "description", "username", "icon_url", "channel_locked"}를 보내세요; 응답의 id가 키입니다. 명령줄에서: amctl webhook create-incoming --channel <channel id> --user <user> --display-name "CI".

수신 웹훅에 메시지 보내기

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:"}'

서버는 본문 ok와 함께 200으로 응답합니다. 또한 Slack의 웹훅처럼 JSON을 payload 필드에 담아 application/x-www-form-urlencoded도 허용하므로, Slack용으로 만든 도구는 변경 없이 사용할 수 있습니다.

필드의미
textMarkdown 형식의 메시지입니다. attachments가 없는 경우 필수입니다. 서버의 메시지 길이 제한을 초과하는 텍스트는 여러 메시지로 나뉩니다.
channel웹훅 커뮤니티의 다른 채널을 이름(ops-alerts 또는 #ops-alerts)으로 지정하거나, 웹훅 소유자의 다이렉트 메시지의 경우 @username를 사용할 수 있습니다. 웹훅이 해당 채널에 잠금되어 있는 경우 거부됩니다. 이전 이름 town-square는 이제 general이라고 불리는 커뮤니티의 기본 채널에 여전히 도달합니다.
username, icon_url, icon_emoji서버가 오버라이드를 허용하는 경우 표시할 이름과 프로필 사진입니다.
attachments카드(아래)로 렌더링되는 메시지 첨부 파일입니다.
props이러한 속성을 읽는 앱용으로 메시지에 저장되는 추가 속성입니다.
type앱이 렌더링하는 custom_poll과 같은 사용자 정의 게시물 유형입니다. system_로 시작하는 유형은 거부됩니다.
root_id해당 글타래에 답글을 보내기 위한 글타래의 첫 번째 메시지 ID입니다.
priority메시지 우선순위, 예: {"priority": "urgent"}.
silenttrue로 설정하면 푸시 알림 없이 메시지를 전송합니다.

웹훅이 게시하는 모든 메시지는 이름 옆에 BOT 태그가 붙습니다. 생성자의 이름으로 표시되는 경우에도 마찬가지입니다. 이를 통해 실제 사람의 메시지와 구별할 수 있습니다. 웹훅 메시지는 송신 웹훅을 절대 트리거하지 않습니다.

이름과 아이콘

서버가 재정을 허용하지 않는 한, 웹훅은 생성한 사람의 이름으로 게시됩니다. 관리자 도구 › 통합 › 통합관리의 두 가지 설정(기본적으로 모두 비활성화됨)이 이를 변경합니다:

  • 통합을 활성화하여 사용자 아이디를 재정의합니다 (ServiceSettings.EnablePostUsernameOverride): 웹훅의 사용자 이름 또는 요청의 username이 대신 표시됩니다. 둘 다 없으면 이름은 webhook으로 표시됩니다.
  • 프로필 사진 아이콘을 재정의할 수 있도록 통합을 활성화합니다 (ServiceSettings.EnablePostIconOverride): 웹훅의 프로필 사진 또는 요청의 icon_url 또는 icon_emoji가 표시됩니다.

요청의 값이 웹훅에 저장된 값보다 우선합니다.

첨부 파일

첨부 파일은 텍스트 아래에 구조화된 콘텐츠를 추가합니다. 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
  }]
}
필드의미
fallback카드를 표시할 수 없는 곳(알림 등)을 위한 일반 텍스트입니다.
color색상 바: 16진 색상 코드 또는 good, warning, danger.
pretext카드 위쪽의 텍스트입니다.
author_name, author_link, author_icon작은 헤더 줄입니다.
title, title_link카드 제목, 선택적으로 링크가 될 수 있습니다.
textMarkdown 형식의 카드 본문입니다.
fields{"title", "value", "short"} 목록; short 필드는 나란히 배치됩니다.
image_url, thumb_url아래의 큰 이미지 또는 옆의 작은 이미지입니다.
footer, footer_icon, ts푸터 줄과 시간(Unix 초)입니다.
actions버튼과 메뉴: 대화형 메시지를 참조하세요.

카드: 단계와 차트

Antimatter는 기본 인터페이스가 렌더링하는 첨부 파일에 두 가지 필드를 추가합니다:

  • stages: 파이프라인의 단계가 최대 20개까지 필(pill) 형태로 표시됩니다. 각 단계는 {"name", "status"} 형식이며, 상태는 passed, failed, running, pending, skipped 또는 canceled 중 하나입니다.
  • chart: 최근 값의 작은 라인 차트, {"values": [2 to 200 numbers], "threshold": number, "label": "…"}. 임계값은 점선으로 그려지며, 알림의 한계값을 나타냅니다.
{
  "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"}
  }]
}

클래식 인터페이스 및 기타 클라이언트는 이 두 필드를 무시하므로, 필수 정보는 text 또는 fields에도 함께 입력하세요.

아웃고잉 웹훅 만들기

송신 웹훅은 커뮤니티의 공개 채널을 감시합니다. 메시지의 첫 번째 단어가 트리거 단어와 일치하거나, 누군가가 메시지의 메뉴에서 이를 선택(메시지 작업)할 때 메시지를 사용자의 URL로 보냅니다.

  1. 통합에서 전체 Outgoing Webhook을 선택한 후 Outgoing Webhook 추가하기를 클릭합니다.
  2. 제목과 설명을 입력하세요.
  3. 요청의 콘텐츠 형식을 선택합니다: application/x-www-form-urlencoded 또는 application/json.
  4. 채널을 선택하거나 트리거 단어 (줄 당 하나씩 입력합니다)를 입력하거나, 둘 다 수행합니다. 채널만 있고 트리거 단어가 없으면 해당 채널의 모든 메시지가 전송됩니다. 둘 다 있는 경우, 메시지는 둘 다와 일치해야 합니다.
  5. 트리거 조건에서 첫 번째 단어가 트리거 단어와 정확히 일치할 때, 첫 번째 단어가 트리거 단어로 시작할 때, 또는 메시지 메뉴에서를 선택합니다. 메시지 메뉴에서를 선택하면 트리거 단어가 사라지고, 채널은 선택 사항입니다(지정하지 않으면 커뮤니티의 모든 공개 채널에서 작업이 제공됨), 제목은 필수입니다: 이는 메뉴에서 작업의 이름입니다.
  6. 콜백 URL (한 줄에 하나 씩)을 입력합니다. 각 URL은 일치하는 모든 메시지를 수신합니다.
  7. 답글에 사용할 사용자 이름과 프로필 사진을 선택적으로 설정할 수 있습니다. 메시지 메뉴에서 실행되는 작업의 경우, 아이콘 필드가 프로필 사진을 대체합니다: .png 또는 .jpg 이미지의 URL 또는 Antimatter의 기본 인터페이스에서 업로드된 이미지입니다. 메뉴에서 이는 회색으로 표시됩니다. 지정하지 않으면 작업에 중립적인 아이콘이 부여됩니다.
  8. 저장을 선택하고 표시되는 토큰을 복사하세요. 서비스는 이 토큰을 사용하여 요청이 사용자의 서버에서 온 것인지 확인합니다.

API를 통해: POST /api/v4/hooks/outgoing를 호출하고 {"team_id", "channel_id", "trigger_words", "trigger_when", "callback_urls", "content_type", "display_name"}를 전달합니다 (trigger_when: 0은 정확한 일치, 1은 "시작 부분 일치", 2는 "메시지 메뉴에서"). trigger_when이 2인 웹훅은 트리거 단어가 없으며 display_name이 필요합니다. 아이콘은 POST /api/v4/hooks/outgoing/{hook_id}/icon로 업로드합니다 (multipart, 필드 image: PNG, JPEG 또는 GIF, 128 px PNG로 저장). 이후 icon_url은 GET /api/v4/hooks/outgoing/{hook_id}/icon를 가리킵니다.

서비스가 사설 네트워크에 있는 경우, 시스템 관리자가 신뢰할 수 없는 내부 연결을 허용 (ServiceSettings.AllowedUntrustedInternalConnections)에서 해당 주소를 허용해야 합니다. 그렇지 않으면 서버가 사설 주소를 호출하지 않습니다.

아웃고잉 요청

Antimatter는 콘텐츠 유형에 따라 JSON 또는 폼 인코딩 형식으로 다음 필드를 포함하여 POST 요청을 보냅니다:

{
  "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": ""
}

처리하기 전에 token를 웹훅의 토큰과 비교하세요. form-encoded 버전에서는 timestamp이 밀리초가 아닌 초 단위입니다. 서버는 통합 요청 시간 초과 허용 시간(기본값 30초, ServiceSettings.OutgoingIntegrationRequestsTimeout) 동안 응답을 기다립니다.

외부 웹훅에 대한 응답

답글을 게시하려면 JSON으로 응답하세요. 아무것도 게시하지 않으려면 빈 본문으로 응답하세요.

{
  "text": "Deploying **api 2.4.0** to staging…",
  "response_type": "comment",
  "username": "deploy-bot",
  "icon_url": "https://chat.example.com/static/deploy.png"
}
  • text 및 attachments: 답글입니다. 둘 다 없으면 아무것도 게시되지 않습니다.
  • response_type: comment는 트리거 메시지의 글타래에 답글을 게시하며, 그 외의 경우 채널에 게시됩니다.
  • username, icon_url: 서버가 오버라이드를 허용하는 경우 표시되며, 허용하지 않으면 웹훅 자체의 값이 사용됩니다.
  • props, type, priority: 수신 웹훅과 동일합니다.

답글은 웹훅의 생성자로 게시되며, 오버라이드된 이름이 있는 경우 해당 이름으로 표시됩니다. 간단한 답변보다 긴 내용은 즉시 응답하고, 수신 웹훅 또는 API를 통해 나중에 게시하세요.

메시지 작업

메시지 작업은 트리거 조건이 메시지 메뉴에서로 설정된 아웃바운드 웹훅입니다. 게시된 메시지에 대해 절대 트리거되지 않습니다. 대신, 사용자는 메시지 메뉴: 메시지 작업 (⋯) › 더 많은 작업에서 통합 섹션 아래에 해당 아이콘과 함께 이를 볼 수 있습니다. 클래식 인터페이스에서는 메시지 작업이 표시되지 않습니다. 선택하면 해당 메시지가 콜백 URL로 전송되며, 짧은 알림에 작업 이름이 전송됨으로 표시되거나 ephemeral_text가 표시됩니다.

  • 표시 위치: 웹훅이 연결된 채널, 또는 채널이 없으면 해당 커뮤니티의 모든 공개 채널. 메시지 작업은 공개 채널에만 있습니다.
  • 게스트는 자신이 속한 채널에 연결된 작업만 볼 수 있으며, 커뮤니티 전체의 작업은 볼 수 없습니다.
  • 아카이브 및 읽기 전용 채널: 메시지는 여전히 전송될 수 있습니다. 채널을 아카이브하면 해당 채널에 연결된 웹훅이 삭제되므로, 아카이브된 채널에는 커뮤니티 전체의 작업만 유지됩니다. 사용자가 해당 채널에 게시할 수 없는 답변은 해당 사용자에게만 표시됩니다.
  • 요청 제한: 각 사용자는 5개의 버스트 후 분당 10개의 메시지 작업을 실행할 수 있습니다. 이를 초과하면 서버가 429로 응답합니다.
  • 사설 네트워크: 다른 아웃바운드 웹훅과 마찬가지로, 내부 주소는 신뢰할 수 없는 내부 연결을 허용에 허용되어야 합니다.

요청

페이로드는 웹훅의 콘텐츠 타입에 따라 JSON 또는 폼 인코딩으로 전송됩니다:

{
  "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와 user_name는 작업을 선택한 사용자이며, post_user_id와 post_user_name는 메시지의 작성자입니다.
  • 해당 메시지만 전송되며, 그 글타래의 나머지 메시지는 절대 전송되지 않습니다.
  • files는 작업을 선택한 사용자가 파일을 다운로드할 수 있는 경우에만 메시지의 파일 목록을 포함합니다. link를 다운로드하려면 API의 모든 파일과 마찬가지로 세션 또는 토큰이 필요합니다.
  • 읽으면 소멸하는 메시지는 텍스트와 파일이 포함되지 않은 상태로 전송되며, burn_on_read가 true로 설정됩니다.
  • Form-encoded 형식에서는 파일이 동일한 순서로 반복되는 file_id, file_name, file_link 필드로 전송됩니다.

응답

외부 웹훅의 응답과 동일한 방식으로 답변합니다(외부 웹훅에 대한 응답 참고): text 또는 attachments를 사용하면 채널에 답글이 게시되고, "response_type": "comment"를 사용하면 해당 메시지의 글타래에 게시됩니다. ephemeral_text(300자로 잘림)로 답변할 수도 있으며, 이는 해당 작업을 선택한 사용자에게만 알림에 표시됩니다. 본문이 비어 있으면 아무것도 게시되지 않습니다.

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

API를 통해

  • GET /api/v4/channels/{channel_id}/message_actions: 채널에서 선택할 수 있는 작업 목록으로, id, display_name, description, icon_url를 반환합니다. 토큰이나 콜백 URL은 반환되지 않습니다.
  • POST /api/v4/posts/{post_id}/message_actions/{hook_id}: 읽을 수 있는 메시지에 작업을 실행합니다. {"ephemeral_text"}를 반환합니다.

웹훅이 작동하지 않을 때

  • 훅 URL에서 501: 서버에서 수신 웹훅이 비활성화되어 있습니다.
  • 400 "Failed to decode the payload…": JSON이 유효하지 않거나, form 필드 이름이 payload가 아닙니다. "No text specified."는 요청에 text와 attachments가 모두 없다는 뜻입니다.
  • 403: 웹훅이 다른 채널에 고정되어 있거나, 소유자가 더 이상 해당 채널을 읽을 수 없는 경우입니다.
  • 외부 웹훅이 절대 트리거되지 않는 경우: 채널이 비공개인 경우, 트리거가 첫 번째 단어가 아닌 경우, 메시지가 웹훅에서 온 경우, 또는 웹훅이 메시지 메뉴에서 트리거되도록 설정된 경우.
  • 메시지 작업이 메뉴에 표시되지 않는 경우: 채널이 비공개인 경우, 작업이 다른 채널에 바인딩된 경우, 사용자가 게스트이고 작업에 채널이 없는 경우, 또는 외부 웹훅이 꺼져 있는 경우.
  • 메시지 작업 실행 시 404 오류: 작업이 존재하지 않거나, 해당 사용자에게 해당 메시지의 채널을 포함하지 않는 경우. 429: 사용자가 1분 안에 10개 이상의 작업을 실행한 경우. 502: 콜백 URL에 접근할 수 없는 경우(로그에 원인이 기록됨).
  • 로그: Webhook 디버깅 활성화를 켜고(LogSettings.EnableWebhookDebugging) 로그 수준을 DEBUG로 설정하면, 서버가 실패한 수신 요청의 페이로드를 로그에 기록합니다. 실패한 발신 호출은 Outgoing Webhook POST failed로 기록됩니다.