> ## Documentation Index
> Fetch the complete documentation index at: https://docs.querying.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# 모니터 이벤트와 알림: 웹훅과 이메일 알림

> 모니터의 답변이 바뀌면 서명된 웹훅을 받고, 언급률이 임계값 아래로 떨어지면 이메일을 받습니다.

모니터는 무언가 움직이면 알려 주므로 리포트를 폴링하지 않아도 됩니다.

* **변화 이벤트**는 프롬프트의 답변이 바뀔 때 `webhookUrl`로 갑니다. 내 브랜드가 나타나거나 사라질 때, 경쟁사가 앞설 때,
  사이트가 처음 인용될 때입니다.
* **알림**은 최근 7일 브랜드 언급률이 `alertBelowPct` 아래로 떨어지면 계정 관리자에게 이메일을 보냅니다.

## 변화 이벤트

모니터를 [만들](/ko/monitors.md#모니터-만들기) 때나 수정할 때 `webhookUrl`을 설정하세요.

```bash theme={"theme":"css-variables"}
curl -X PATCH https://api.querying.ai/v1/monitors/$MONITOR_ID \
  -H "Authorization: Bearer $QUERYING_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "webhookUrl": "https://hooks.example.com/querying/monitors" }'
```

URL은 공개 호스트의 HTTPS여야 합니다. API 키로 설정하세요. 이벤트는 이 값을 설정한 키로 서명하므로, 키 없는
요청(대시보드 세션)은 `400 VALIDATION_ERROR`를 반환합니다. `webhookUrl: null`은 이벤트를 끄고 모니터의 이벤트 상태를
버립니다. 다시 켜면 이력에서 시작합니다.

### 이벤트 유형

| 이벤트 | 보내는 때 |
| - | - |
| `monitor.mention.started` | 내 브랜드가 프롬프트의 최근 답변 5개 중 3개 이상에 나옵니다. 직전에는 그보다 적었습니다. |
| `monitor.mention.stopped` | 내 브랜드가 프롬프트의 최근 답변 5개 중 2개 이하로 떨어집니다. |
| `monitor.competitor.ahead` | 경쟁사가 프롬프트의 최근 답변 5개 중 3개 이상에 나오고, 내 브랜드보다 많은 답변에 나옵니다. |
| `monitor.source.first_cited` | 모니터의 답변이 한 번도 인용하지 않은 도메인을 답변이 인용합니다. |

브랜드 이벤트는 프롬프트를 엔진별로, 그리드 모니터에서는 지점별로 따로 추적합니다. 상태는 최근 답변 5개로 읽으므로
`samples: 5`이면 실행 한 번으로 상태가 채워집니다.

* 이벤트는 상태가 바뀔 때 한 번 보냅니다. 답변에서 계속 빠져 있는 브랜드는 `monitor.mention.stopped`를 한 번 보내고,
  돌아올 때까지 더 보내지 않습니다.
* 프롬프트는 답변 5개가 쌓이면 상태가 생깁니다. 그 첫 상태가 기준이 되며 아무것도 보내지 않습니다.
* 카테고리 모니터는 자체 브랜드가 없으므로 `monitor.source.first_cited`만 보냅니다.

이벤트가 시작되는 시점은 다음과 같습니다.

* **이미 답변이 있는 모니터에 `webhookUrl`을 켤 때**: 각 프롬프트의 상태를 최근 30일 중 마지막 답변 5개로 다시 만들고,
  이미 인용된 모든 도메인을 알려진 도메인으로 셉니다. 이벤트는 다음 답변부터 시작됩니다.
* **`webhookUrl`과 함께 모니터를 만들거나, 답변이 생기기 전에 켤 때**: 첫 실행이 알려진 도메인을 정하고,
  `monitor.source.first_cited`는 그 실행이 모두 제출된 뒤에 만들어진 태스크의 답변부터 셉니다. 브랜드 이벤트는 프롬프트에
  답변 5개가 쌓이면 시작됩니다.

### 페이로드

각 이벤트는 JSON 본문의 `POST`입니다. 예를 들면 다음과 같습니다.

```json theme={"theme":"css-variables"}
{
  "event": "monitor.mention.stopped",
  "id": "fd61d8f6-ebdf-4162-8b55-fd052c8502a9",
  "createdAt": "2026-10-10T03:12:44.120Z",
  "monitor": { "id": "d39b8de0-b159-4229-bf58-7064e5369db1", "name": "Earbud brand tracking" },
  "data": {
    "engine": "CHATGPT",
    "prompt": "best wireless earbuds for commuting",
    "location": null,
    "taskId": "863edb44-fc62-40dd-a5be-2af9409d59b6",
    "answers": 5,
    "mentions": 2
  }
}
```

| 필드 | 의미 |
| - | - |
| `event` | 이벤트 유형. |
| `id` | 이벤트 id. `querying-webhook-id` 헤더로도 보냅니다. 이 값으로 중복을 거르세요. |
| `monitor` | 모니터의 `id`와 `name`. |
| `data.engine`, `data.prompt` | 답변이 속한 엔진과 프롬프트. |
| `data.location` | 답변 지점의 `{ latitude, longitude }`. 위치가 없으면 `null`. |
| `data.taskId` | 이벤트를 일으킨 답변. [`GET /v1/monitors/{id}/answers/{taskId}`](/ko/monitors/evidence#답변-하나-읽기)로 여세요. |
| `data.answers`, `data.mentions` | 상태에 든 답변 수(5)와 그중 내 브랜드를 언급한 수. 언급 이벤트와 경쟁사 이벤트에만 있습니다. |
| `data.competitor`, `data.competitorMentions` | 경쟁사와 그 경쟁사를 언급한 답변 수. `monitor.competitor.ahead`에만 있습니다. |
| `data.domain`, `data.url`, `data.label` | 새로 인용된 도메인, 인용된 페이지, 그 레이블. `monitor.source.first_cited`에만 있으며 개수 대신 들어갑니다. |

### 서명과 재시도

이벤트는 태스크 웹훅과 같은 방식으로 서명하고 재시도합니다. 같은 세 가지 `querying-webhook-*` 헤더, 같은 HMAC-SHA256
방식, 같은 재시도 일정입니다. [웹훅](/ko/concepts/webhooks.md#서명-검증)의 코드로 검증하세요. 두 가지가 다릅니다.

* `querying-webhook-id`는 이벤트 `id`입니다. 이 값으로 중복을 거르세요.
* HMAC 키는 태스크의 키가 아니라 `webhookUrl`을 설정한 API 키의 SHA-256 다이제스트입니다.

키를 교체한 뒤 새 키로 `webhookUrl`을 다시 보내면 이후 이벤트는 새 키로 서명합니다. `webhookUrl`을 설정한 키가 폐기되거나
만료되면 이벤트가 멈춥니다. 각 이벤트는 `delivery.lastError`에 이유를 담아 `failed`로 표시되며, 서명 없이 보내는 일은
없습니다.

### 이벤트 목록과 다시 보내기

`GET /v1/monitors/{id}/events`([레퍼런스](/ko/api-reference/monitors/list-events.md))는 이벤트를 최신순으로 나열합니다.

| 파라미터 | 설명 |
| - | - |
| `limit` | 1–100, 기본값 50. |
| `type` | 이벤트 유형 하나. |
| `cursor` | 이전 페이지의 `nextCursor`. |

응답에는 `webhookUrl`, `nextCursor`(마지막 페이지에서 `null`), `events`가 있습니다. 각 이벤트에는 `id`, `type`,
`createdAt`, `data`(페이로드와 같음), `delivery`가 있습니다.

| 필드 | 의미 |
| - | - |
| `delivery.status` | `pending`(첫 시도나 재시도 대기), `delivered`, `failed`(재시도 소진 또는 전달 불가). |
| `delivery.attempts` | 시도 횟수. |
| `delivery.deliveredAt` | `2xx`를 받은 시각, 또는 `null`. |
| `delivery.lastError` | 마지막 실패(예: `HTTP 500`), 또는 `null`. |

`POST /v1/monitors/{id}/events/{eventId}/redeliver`
([레퍼런스](/ko/api-reference/monitors/redeliver-event.md))는 이벤트 하나를 현재 `webhookUrl`로 지금 다시 보내고, 재시도를
처음부터 세며, 갱신된 `delivery`와 함께 이벤트를 반환합니다. 이미 전달된 이벤트도 다시 보낼 수 있습니다. 모니터에
`webhookUrl`이 없으면 `409 WEBHOOK_NOT_SET`, 알 수 없는 이벤트는 `404 NOT_FOUND`를 반환합니다.

이벤트는 30일 동안 보관합니다. 재시도 중인 이벤트는 재시도가 끝날 때까지 보관합니다.

## 알림

브랜드 모니터에 `alertBelowPct`(1–100의 정수 퍼센트)를 설정하면 브랜드 언급률이 그 아래로 떨어질 때 이메일을 받습니다.

```bash theme={"theme":"css-variables"}
curl -X PATCH https://api.querying.ai/v1/monitors/$MONITOR_ID \
  -H "Authorization: Bearer $QUERYING_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "alertBelowPct": 40 }'
```

알림은 다음과 같이 판단합니다.

* **기간**: 모니터의 모든 프롬프트와 엔진에 걸친 최근 7일의 채점된 답변. [리포트](/ko/monitors/reports.md)의 기본값인 30일은
  경고하기에는 너무 느리게 움직입니다.
* **시점**: 예약 실행이 시작될 때마다. 이미 채점된 답변을 읽으므로 이전 실행들을 반영합니다.
* **최소 표본**: 기간의 채점된 답변이 5개 미만이면 발송하지 않습니다. 새 모니터나 엔진이 실패 중인 모니터는 조용합니다.
* **상태가 아니라 교차**: 비율이 임계값 아래이고 알림이 활성 상태이면 발송한 뒤 비활성화합니다. 비율이 임계값 이상으로
  돌아오면 다시 활성화되므로, 계속 낮은 모니터는 실행마다가 아니라 한 번만 이메일을 보냅니다. `alertBelowPct`를 바꾸면
  다시 활성화됩니다.

이메일은 모니터 비용을 내는 계정(하위 계정이면 상위 계정)의 모든 관리자에게 갑니다. 반올림한 비율, 임계값, 기간, 채점된
답변 수를 알리고 대시보드의 모니터로 연결합니다.

카테고리 모니터에는 브랜드 비율이 없으므로 `alertBelowPct`를 `400 VALIDATION_ERROR`로 거절합니다.
`alertBelowPct: null`은 알림을 끕니다.

### 알림 이력

`GET /v1/monitors/{id}/alerts`([레퍼런스](/ko/api-reference/monitors/get-alerts.md))는 `alertBelowPct`, `armed`,
`deliveries`(테스트를 포함한 모니터의 최근 알림 이메일 20건)를 반환합니다. 각 전달에는 `id`, `status`(`pending`, `sent`,
`failed`), `attempts`, `createdAt`, `sentAt`, `lastError`, `payload`(`monitorId`, `name`, `ratePct`, `threshold`,
`windowDays`, `runs`)가 있습니다. 전달 기록은 90일 동안 보관합니다.

### 테스트 알림 보내기

`POST /v1/monitors/{id}/alerts/test`([레퍼런스](/ko/api-reference/monitors/test-alert.md))는 실제 알림과 같은 전달 경로로
모니터 이름 뒤에 "(test)"를 붙인 테스트 이메일을 큐에 넣고 `data.queued: true`를 반환합니다. 결과는 알림 이력에서
확인하세요. 테스트 이메일은 모니터당 5분에 3번까지 보낼 수 있고, 넘으면 `429 RATE_LIMITED`를 반환합니다. 카테고리 모니터는
`400 VALIDATION_ERROR`를 반환합니다.

## 다음 단계

> **[웹훅](/ko/concepts/webhooks.md)**
>
> 모든 웹훅의 서명, 재시도, 안전한 핸들러.

> **[출처와 답변](/ko/monitors/evidence.md)**
>
> 이벤트 뒤의 답변을 엽니다.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.