Webhook
최종 수정: 2026년 6월 22일
Webhook은 Space에서 일이 일어났을 때(예: Content 생성·발행) 미리 지정한 외부 URL로 HTTP 요청을 보내는 설정입니다. 외부 시스템 연동이나 자동화에 씁니다. 예를 들어 상품 Content가 발행될 때마다 사내 알림 서버를 호출하거나, 외부 API를 호출하도록 구성할 수 있습니다.
Webhook은 요청을 보내는 데서 그치지 않고, 그 응답을 받아 다시 Content나 Media에 도로 쓰는 WriteBack까지 설정할 수 있습니다. 외부 API의 결과를 Space 안의 데이터로 흡수하는 비동기 작업 흐름을 이렇게 구성합니다. Webhook은 CMA에서 Space 하위 리소스이며, 경로는 /spaces/{spaceId}/webhooks를 기준으로 합니다.
리소스 구조
다음은 Webhook "상품 변경 알림"의 단일 조회 응답입니다. sys(시스템 속성)와 함께 전송 대상·구독 이벤트·트리거 조건 같은 설정 필드를 가집니다.
{
"sys": {
"id": "3trmXRM3RqbgSnifyg7PWhk01Examp",
"type": "Webhook",
"space": { "sys": { "id": "HnQ32YiH", "type": "Refer", "targetType": "Space" } },
"createdBy": { "sys": { "id": "3p4tcFbQRwz503VXdtHXNI5dZH5TVB", "type": "Refer", "targetType": "User" } },
"createdAt": "2026-06-18T11:30:00.000Z",
"updatedBy": { "sys": { "id": "3p4tcFbQRwz503VXdtHXNI5dZH5TVB", "type": "Refer", "targetType": "User" } },
"updatedAt": "2026-06-18T11:30:00.000Z",
"version": 1
},
"name": "상품 변경 알림",
"filters": [
{ "doc": "sys.contentType.sys.id", "op": "EQ", "value": "3trmXRLdJF4GBlAjtcuoZ7Pnxj8dlA" }
],
"headers": [
{ "key": "X-Source", "value": "weegloo", "secret": false }
],
"httpBasicUsername": "dailywear",
"topics": ["Content.Create", "Content.Publish"],
"transformation": { "method": "POST", "contentType": "application/json", "includeBody": true },
"url": "https://api.dailywear.example/webhooks/products",
"activate": true
}주요 키:
sys.id: Webhook의 고유 식별자입니다. 단일 조회·수정·삭제 경로의{webhookId}에 들어갑니다.url: 이벤트가 발생했을 때 호출할 외부 대상 URL입니다.topics: 어떤 이벤트를 구독할지 정한 배열입니다. 아래 topics에서 형식을 설명합니다.filters: 구독한 이벤트 중 실제로 트리거할 조건입니다. 아래 filters에서 설명합니다.transformation: 나가는 요청의 모양(메서드·본문 등)을 바꾸는 설정입니다. 아래 transformation에서 설명합니다.writeBacks: 외부 응답을 받아 Content나 Media에 도로 쓰는 작업의 배열입니다. 위 예시에는 없습니다. 아래 writeBacks에서 설명합니다.
시스템 속성 (sys)
모든 Webhook은 공통 시스템 속성을 sys 객체에 담습니다. space·createdBy·updatedBy는 Refer 모양({ "sys": { "id", "type": "Refer", "targetType" } })으로 들어갑니다.
| 속성 | 타입 | 설명 |
|---|---|---|
id | string | 리소스 고유 식별자. |
type | string | 리소스 종류. Webhook은 항상 "Webhook". |
space | Refer<Space> | 이 Webhook이 속한 Space. |
createdBy | Refer<User> | 생성한 사용자. |
createdAt | string (date-time) | 생성 시각. |
updatedBy | Refer<User> | 마지막으로 수정한 사용자. |
updatedAt | string (date-time) | 마지막 수정 시각. |
version | integer (≥1) | 리소스 버전. 수정마다 1씩 올라갑니다. |
Webhook은 설정 리소스이므로 발행이라는 개념이 없습니다. Content나 Content Type과 달리 publish·archive·status 같은 발행 상태 속성을 가지지 않고, 변경 추적용 version만 가집니다. 켜고 끄는 것은 발행이 아니라 본문 필드 activate로 제어합니다.
본문 속성
Webhook의 본문(생성·수정 시 보내고, 응답으로 돌아오는 설정 값)은 다음 필드로 이루어집니다.
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
name | string (1~64) | ✅ | Webhook 이름. |
url | string (url) | ✅ | 이벤트 발생 시 호출할 외부 대상 URL. |
activate | boolean | ✅ | 켜짐 여부. false면 이벤트가 발생해도 요청을 보내지 않습니다. |
topics | string[] | ✅ | 구독할 이벤트 배열. 아래 topics 참조. |
filters | Filter[] | ✅ | 트리거 조건 배열. 비우면 구독한 모든 이벤트가 트리거합니다. 아래 filters 참조. |
headers | WebhookHeader[] (0~30) | ✅ | 요청에 실어 보낼 HTTP 헤더 배열. |
httpBasicUsername | string (1~32) | HTTP Basic 인증 사용자명. | |
httpBasicPassword | string (1~32) | HTTP Basic 인증 비밀번호. 쓰기 전용입니다. 응답에는 나오지 않습니다. | |
transformation | Transformation | ✅ | 나가는 요청 커스터마이즈. 아래 transformation 참조. |
writeBacks | WriteBack[] | 응답을 받아 수행할 쓰기 작업 배열. 아래 writeBacks 참조. |
headers의 각 항목은 key(필수)·value(필수)·secret(선택, boolean)로 이루어집니다. secret이 true인 헤더는 응답에서 값이 가려집니다. API 키처럼 노출되면 안 되는 값은 secret: true 헤더에 둡니다.
topics
topics의 각 항목은 {리소스}.{액션} 형식입니다. 예: Content.Create, Content.Publish, Media.Create.
액션은 다음 중 하나이거나, 리소스의 모든 액션을 뜻하는 *입니다(예: Content.*).
| 액션 | 의미 |
|---|---|
All | 모든 액션. |
Create | 생성. |
Read | 조회. |
Edit | 편집. |
Save | 저장(수정). 수정 이벤트는 Save입니다. Update가 아닙니다. |
Delete | 삭제. |
Publish | 발행. |
Unpublish | 발행취소. |
Archive | 보관. |
Unarchive | 보관해제. |
filters
filters는 구독한 topics 중 실제로 Webhook을 트리거할 조건을 좁히는 배열입니다. 각 필터는 다음 모양입니다.
{ "doc": "sys.contentType.sys.id", "op": "EQ", "value": "3trmXRLdJF4GBlAjtcuoZ7Pnxj8dlA" }doc: 비교할 필드 경로.sys.id·sys.contentType.sys.id·sys.createdBy.sys.id·sys.updatedBy.sys.id중 하나입니다.op: 비교 연산자.EQ·NE·IN·NOT_IN·REGEX·NOT_REGEX중 하나입니다.value: 비교 값.EQ·NE·REGEX·NOT_REGEX에는 문자열을,IN·NOT_IN에는 문자열 배열을 줍니다.
여러 필터를 두면 모두 만족해야 트리거합니다(AND). filters를 비우면 구독한 topics의 모든 이벤트가 트리거합니다.
transformation
transformation은 나가는 HTTP 요청의 모양을 바꿉니다. 지정하지 않으면 리소스 페이로드 전체가 기본 POST로 그대로 나갑니다.
| 키 | 타입 | 설명 |
|---|---|---|
method | string | HTTP 메서드. GET·POST·PUT·DELETE·PATCH 중 하나. |
contentType | string | 요청 본문의 Content-Type. |
body | object | 보낼 본문을 JSON Pointer 템플릿으로 구성하는 객체. |
includeBody | boolean | 트리거 리소스의 본문을 함께 보낼지 여부. |
writeBacks
writeBacks는 Webhook이 받은 외부 응답을 가지고 Content나 Media에 도로 쓰는 작업의 순서 있는 배열입니다. 외부 API가 2xx로 응답했을 때만 순서대로 실행됩니다. 각 항목은 $content(WriteBackContent) 또는 $media(WriteBackMedia)를 하나 가집니다.
WriteBackContent ($content)의 키:
| 키 | 타입 | 설명 |
|---|---|---|
action | string | Create·Update·Delete·Publish·Unpublish·Archive·Unarchive 중 하나. |
contentType | Refer<ContentType> | Create 시 만들 Content Type. sys.id만 주면 됩니다. |
target | string | Update·Delete 등에서 대상 Content의 sys.id를 가리키는 JSON Pointer 템플릿(예: { /response/id }). { }로 감싸야 하며, 감싸지 않으면 리터럴로 취급합니다. 생략하면 Webhook을 트리거한 리소스를 대상으로 삼습니다. |
locale | string | Create·Update 시 값을 쓸 로케일. 로케일 코드나 포인터 템플릿. 생략하면 Space 기본 로케일. |
fields | object | Create·Update 시 대상 필드 키 → 소스 표현식 맵. 키는 대상 Content 필드의 apiName입니다. |
publish | boolean | Create·Update 후 발행할지 여부. 기본값 true. |
unpublish | boolean | Delete 시 삭제 전 발행취소할지 여부. 기본값 true. |
WriteBackMedia ($media)의 키:
| 키 | 타입 | 설명 |
|---|---|---|
action | string | Create·Delete·Publish·Unpublish·Archive·Unarchive 중 하나. |
source | string | Create 시 Media로 가져올 값의 포인터 템플릿(예: { /response/data/0/url }). { }로 감싸야 합니다. |
encoding | string | Create 시 source를 해석하는 방식. Url·Base64·Binary 중 하나. |
locale | string | Create 시 파일·제목·설명을 쓸 로케일. 생략하면 Space 기본 로케일. |
title | string | Create 시 Media 제목(소스 표현식 또는 리터럴). |
description | string | Create 시 Media 설명. |
target | string | Delete 등에서 대상 Media의 sys.id를 가리키는 포인터 템플릿. 생략하면 트리거 리소스가 대상. |
publish | boolean | Create 시 처리 완료 후 발행할지 여부. 기본값 true. |
unpublish | boolean | Delete 시 삭제 전 발행취소할지 여부. 기본값 true. |
다음은 외부 응답 JSON에서 값을 뽑아 Content 하나를 만드는 writeBacks 예시입니다.
"writeBacks": [
{
"$content": {
"action": "Create",
"contentType": { "sys": { "id": "3trmXRLdJF4GBlAjtcuoZ7Pnxj8dlA" } },
"locale": "ko-KR",
"fields": {
"productName": "{ /response/title }",
"price": "{ /response/price }"
},
"publish": true,
"unpublish": true
}
}
]{ /response/... }는 Webhook이 받은 응답 JSON에서 값을 뽑는 JSON Pointer 템플릿입니다. fields의 키(productName·price)는 대상 Content 필드의 apiName입니다. 위 예시는 응답의 title을 Content의 productName에, price를 price에 채워 Content를 만든 뒤 발행합니다.
API
아래 모든 엔드포인트의 기준 URL은 https://cma.weegloo.com/v1이며, Authorization 헤더에 CMA를 인증하는 Bearer 토큰이 필요합니다. 수정(PUT)과 부분 수정(PATCH)은 낙관적 동시성 제어를 위해 X-Weegloo-Version 헤더(현재 리소스의 sys.version)를 함께 보내야 합니다.
