# Threads Webhook 알림: 키워드·인기 게시물 실시간 수신

Webhook을 사용하면 API를 계속 폴링할 필요가 없습니다. 규칙만 설정해 두면 Threads에 조건에 맞는 게시물이 올라올 때 Throk이 게시물 데이터를 지정한 URL로 `POST`합니다. 주요 활용 예는 다음과 같습니다.

- 브랜드나 제품이 언급되고 반응이 오르기 시작하면 Slack, LINE, 사내 시스템으로 알림 보내기
- 특정 화제에서 좋아요 수, 답글 수, 조회수가 임계값을 넘은 게시물 모니터링
- 「지금 바이럴 중인」 게시물을 데이터베이스나 CRM으로 자동으로 가져오기

:::note[요금제 요구 사항]
Webhook을 사용하려면 **API Standard 이상** 요금제가 필요합니다. 자세한 내용은 [API 요금제](/ko/api/credits/#api-요금제)를 참고하세요.
:::

## 작동 방식

Webhook은 두 부분으로 구성됩니다.

- **엔드포인트(Endpoint)**: 알림을 받을 URL입니다. 예: `https://example.com/throk-webhook`. 엔드포인트마다 고유한 서명 키가 있습니다.
- **규칙(Rule)**: 어떤 게시물을 전송할지 정합니다. 각 규칙은 엔드포인트 하나에 연결되며, 엔드포인트 하나에 여러 규칙을 둘 수 있습니다.

Throk은 **3분**마다 모든 규칙을 확인합니다. 조건에 맞는 게시물은 **게시물 1개당 이벤트 1건**으로 엔드포인트에 전송됩니다. 같은 게시물은 같은 규칙에 대해 한 번만 전송됩니다.

## 규칙 유형

### 키워드 규칙

게시물 내용에 지정한 키워드가 포함되어 있고 **동시에** 설정한 임계값에 도달하면 전송합니다.

- 규칙 하나에 키워드 하나를 지정합니다. 매칭 방식은 [키워드 검색](/ko/api/guides/search-rules/)과 같습니다. 중국어는 글자 단위로, 영어는 완전한 단어 단위로 매칭합니다.
- 확인 대상은 **최근 24시간 이내에 게시된** 게시물입니다.
- 임계값을 하나 이상 설정해야 하며, 최솟값은 좋아요 수 ≥ 10, 답글 수 ≥ 5, 조회수 ≥ 20,000입니다.

### 인기 임계값 규칙

키워드 없이, 지정한 기간 안에 게시되어 임계값에 도달한 게시물을 전송합니다. 지금 바이럴 중인 콘텐츠를 찾을 때 적합합니다.

- 확인 대상은 **지난 1–72시간** 이내에 게시된 게시물입니다(`lookbackHours`로 설정).
- 임계값을 하나 이상 설정해야 하며, 최솟값은 좋아요 수 ≥ 500, 답글 수 ≥ 100, 조회수 ≥ 20,000입니다.

### 두 규칙의 공통점

- **한 규칙 안의 임계값은 「그리고」(AND) 관계입니다.** 예: 좋아요 수 ≥ 100 **그리고** 답글 수 ≥ 10.
- **규칙끼리는 서로 영향을 주지 않습니다.** 게시물 하나가 두 규칙에 맞으면 이벤트 2건이 전송됩니다.
- **지역별로 필터링할 수 있습니다.** `chinese`(모든 중국어, 기본값), `tw`, `hk`, `cn`, `japanese`, `korean`을 사용할 수 있으며, 정의는 [지역과 언어](/ko/api/guides/regions/)와 같습니다.
- **답글도 포함됩니다.** 답글도 규칙을 발동시킬 수 있으며, 이벤트의 `is_reply` 필드로 구분할 수 있습니다.
- **조회수 임계값은 더 늦게 발동합니다.** 게시물의 조회수 데이터는 보통 게시 후 몇 시간이 지나야 집계되므로, 조회수 임계값을 설정한 규칙은 좋아요 수나 답글 수만 보는 규칙보다 늦게 전송됩니다.

## 개발자 플랫폼에서 설정하기

1. [개발자 플랫폼](https://developer.throk.ai/dashboard/webhooks)에 로그인해 **엔드포인트 및 규칙**으로 이동합니다.
2. **엔드포인트 추가**를 누르고 URL을 입력한 뒤 **생성**을 누릅니다.
3. 엔드포인트 아래에서 **+ 규칙 추가**를 누르고 **키워드** 또는 **인기 임계값**을 선택합니다. 언어와 임계값을 설정하고(인기 임계값은 **지난 … 시간**도 설정) **추가**를 누릅니다.
4. 엔드포인트의 **테스트**를 눌러 서버가 이벤트를 받을 수 있는지 확인합니다. 테스트 이벤트는 크레딧이 차감되지 않습니다.
5. 엔드포인트를 펼치면 [서명 검증](#서명-검증)에 사용하는 **Signing Secret**이 표시됩니다.

![개발자 플랫폼의 Webhooks 페이지: 엔드포인트 아래에 키워드 규칙을 추가하고 언어와 좋아요 수, 답글 수, 조회수 임계값을 설정하는 화면](../../../../assets/screenshots/api/webhook-rule.jpg)

전송된 모든 이벤트와 수신 측의 응답 상태는 **전송 기록** 페이지에서 확인할 수 있으며, 실패한 이벤트는 재전송할 수 있습니다.

## API로 설정하기

API로도 엔드포인트와 규칙을 관리할 수 있습니다. 모든 요청에 API 키가 필요합니다.

| 메서드와 경로 | 용도 |
| --- | --- |
| `GET /webhook/endpoints` | 엔드포인트, 서명 키(`secret`), 규칙 목록 조회 |
| `POST /webhook/endpoints` | 엔드포인트 생성 |
| `DELETE /webhook/endpoints/{endpoint_id}` | 엔드포인트 삭제(해당 엔드포인트의 모든 규칙 포함) |
| `POST /webhook/endpoints/{endpoint_id}/rules` | 엔드포인트에 규칙 생성 |
| `DELETE /webhook/rules/{rule_id}` | 규칙 삭제 |
| `POST /webhook/endpoints/{endpoint_id}/test` | 테스트 이벤트 1건 전송(무료) |

엔드포인트 생성:

```bash
curl -X POST 'https://premium-api.throk.ai/webhook/endpoints' \
  -H 'Authorization: Bearer sk-throk-...' \
  -H 'Content-Type: application/json' \
  -d '{"url": "https://example.com/throk-webhook"}'
```

키워드 규칙 생성(좋아요 수 ≥ 100인 대만 게시물):

```bash
curl -X POST 'https://premium-api.throk.ai/webhook/endpoints/{endpoint_id}/rules' \
  -H 'Authorization: Bearer sk-throk-...' \
  -H 'Content-Type: application/json' \
  -d '{"keyword": "珍珠奶茶", "likeCount": 100, "language": "tw"}'
```

인기 임계값 규칙 생성(지난 6시간 이내, 좋아요 수 ≥ 1,000인 게시물):

```bash
curl -X POST 'https://premium-api.throk.ai/webhook/endpoints/{endpoint_id}/rules' \
  -H 'Authorization: Bearer sk-throk-...' \
  -H 'Content-Type: application/json' \
  -d '{"likeCount": 1000, "lookbackHours": 6}'
```

규칙 필드:

| 필드 | 설명 |
| --- | --- |
| `keyword` | 키워드. 비워 두면 인기 임계값 규칙이 됨 |
| `likeCount`, `replyCount`, `viewCount` | 좋아요 수, 답글 수, 조회수 임계값. 하나 이상 필수 |
| `lookbackHours` | 지난 몇 시간 이내에 게시된 게시물을 확인할지 지정, 1–72. 인기 임계값 규칙에서는 필수 |
| `language` | 지역. 기본값 `chinese` |

규칙은 수정할 수 없습니다. 조정하려면 삭제한 뒤 다시 생성하세요(개발자 플랫폼에서는 바로 수정할 수 있습니다).

## 전송 형식

각 이벤트는 `POST`로 엔드포인트에 전송되며, 본문은 JSON입니다.

```json
{
  "post": {
    "url": "https://threads.com/post/DXZoK1VlEvT",
    "code": "DXZoK1VlEvT",
    "caption": "串文內容……",
    "is_reply": false,
    "like_count": 1700,
    "reply_count": 293,
    "repost_count": 40,
    "reshare_count": 180,
    "impression_count": 254300,
    "post_timestamp": 1776760127,
    "media_url": ["https://media01.throk.ai/media/..."]
  },
  "user": {
    "username": "throk.ai",
    "full_name": "Throk｜定義 Threads 數據新標準",
    "profile_picture": "https://media01.throk.ai/profile/77928681697.jpg"
  }
}
```

- 수치는 **전송 시점**의 스냅숏입니다. 이후 게시물의 반응이 계속 늘어나도 업데이트는 다시 전송되지 않습니다.
- `repost_count`는 리포스트와 인용을 포함합니다. `impression_count`는 아직 조회수 데이터가 없으면 `null`입니다.
- 이벤트에는 **규칙 정보가 포함되지 않습니다**. 어떤 규칙이 발동했는지 구분해야 한다면 규칙마다 다른 엔드포인트를 만드세요. 예를 들어 URL에 `https://example.com/throk-webhook?rule=bubble-tea`처럼 매개변수를 붙일 수 있습니다.

## 서명 검증

모든 이벤트에는 서명이 첨부되어 있어, 요청이 실제로 Throk에서 왔고 내용이 변조되지 않았는지 확인할 수 있습니다.

- 서명 키는 엔드포인트의 **Signing Secret**입니다(개발자 플랫폼에서 엔드포인트를 펼치거나 `GET /webhook/endpoints` 응답의 `secret` 필드에서 확인할 수 있습니다).
- 서명은 요청 헤더 `X-Throk-Signature`에 담기며, 형식은 `t=<UNIX 타임스탬프>,v1=<서명>`입니다.
- 검증 방법: Signing Secret을 키로 `<타임스탬프>,<원본 요청 본문>`의 HMAC-SHA256(16진수)을 계산해 `v1`과 비교합니다. 리플레이 공격을 막기 위해 타임스탬프가 몇 분 이내인지도 확인하세요.

Node.js 예시:

```js
import crypto from 'node:crypto';

// rawBody: 원본 요청 본문(문자열), header: X-Throk-Signature 값
function verify(rawBody, header, secret) {
  const fields = header.split(',').map((p) => p.split('='));
  const t = Number(fields.find(([k]) => k === 't')?.[1]);
  if (!t || Math.abs(Date.now() / 1000 - t) > 300) return false; // 5분 이내의 요청만 허용
  const expected = Buffer.from(
    crypto.createHmac('sha256', secret).update(`${t},${rawBody}`).digest('hex'),
  );
  // 키 교체 중에는 v1이 여러 개 있을 수 있으며, 하나라도 일치하면 통과
  return fields
    .filter(([k]) => k === 'v1')
    .some(([, sig]) => {
      const got = Buffer.from(sig);
      return got.length === expected.length && crypto.timingSafeEqual(got, expected);
    });
}
```

**원본 요청 본문**(raw body)으로 계산하세요. JSON으로 파싱한 뒤 다시 문자열로 변환하면 안 됩니다.

## 수신 측 주의 사항

- 가능한 한 빨리 **HTTP 2xx**로 응답하세요. 시간이 오래 걸리는 처리는 백그라운드에서 실행하세요.
- 2xx로 응답하지 않은 이벤트는 **지수 백오프** 방식으로 최대 **10회**까지 자동 재시도됩니다. 개발자 플랫폼의 **전송 기록**에서 수동으로 재전송할 수도 있습니다.
- 엔드포인트 하나당 **60초에 최대 1,000건**의 이벤트를 받으며, 초과분은 나중에 전송됩니다.
- 실제 이벤트에는 `X-Convoy-Idempotency-Key` 헤더가 붙고(테스트 이벤트에는 없음), 같은 이벤트를 재시도할 때는 값이 바뀌지 않습니다. 이 헤더(또는 게시물의 `code`)로 중복을 제거해 두 번 처리하지 않도록 하세요.

## 요금

- 이벤트 1건을 전송할 때마다 **20크레딧**이 차감되며, API 호출과 계정 크레딧을 공유합니다. 같은 게시물은 같은 규칙에 대해 한 번만 차감됩니다. 차감은 이벤트를 **전송하는 시점**에 이루어지며 수신 서버의 응답 결과와는 관계없으므로, 엔드포인트가 정상적으로 수신할 수 있도록 해 주세요.
- 엔드포인트와 규칙의 생성·삭제, 테스트 이벤트는 **크레딧이 차감되지 않습니다**.
- 크레딧이 부족하면 이벤트 전송이 일시 중지됩니다. 크레딧을 보충하면 아직 확인 범위 안에 있는 게시물은 다음 확인 주기에 전송됩니다.
- Webhook이 포함되지 않은 요금제로 다운그레이드하면 기존 규칙은 유지되지만 더 이상 발동하지 않습니다.
- Webhook 사용량은 **Credits 사용 기록**에 API 유형 `webhook`으로 표시됩니다.

## 전송 중지

Webhook에는 일시 중지 스위치가 없습니다. 전송을 멈추려면 규칙이나 엔드포인트를 삭제하세요. 엔드포인트를 삭제하면 그 엔드포인트의 모든 규칙도 함께 삭제됩니다.