웹훅
Settings → Developers → Webhooks(설정 → 개발자 → 웹훅)에서 엔드포인트를 추가합니다(소유자와 관리자만 가능). 엔드포인트는 공개된 HTTPS 주소여야 합니다. 받을 이벤트를 선택하세요. All events를 켜 두거나(나중에 Pellio에 추가되는 이벤트도 포함), 끄고 원하는 이벤트를 고를 수 있습니다. Pellio는 엔드포인트의 서명 시크릿을 한 번만 보여 줍니다.
각 엔드포인트에는 수신하는 이벤트 목록과 함께 다음 작업이 표시됩니다.
- Edit events: 수신할 이벤트를 변경합니다. Save events를 누르면 즉시 적용됩니다.
- Send test: 수신 이벤트 설정과 관계없이 해당 엔드포인트로
webhook.test이벤트를 보냅니다. - Deliveries: 최근 50번의 전송 시도(대기 중, 전송됨, 실패)와 응답을 보여 줍니다.
- Rotate secret: 서명 시크릿을 교체합니다. 새 시크릿은 한 번만 표시되고 기존 시크릿은 즉시 무효화되므로, 엔드포인트를 바로 업데이트하세요.
- Remove: 엔드포인트로 전송을 중단합니다.
API에서는 POST /v1/webhooks가 url과 events(빈 목록은 모든 이벤트)를 받고, PATCH /v1/webhooks/{id}로 events를 변경하며, POST /v1/webhooks/{id}/rotate-secret은 새 secret을 반환합니다.
이벤트
모든 요청 본문은 { "id", "event", "createdAt", "data" } 형식입니다.
| event | 발생 시점 | data |
|---|---|---|
video.created |
업로드, 녹화, URL 가져오기로 동영상이 생성되었을 때 | id, title |
video.ready |
동영상 처리가 끝났을 때(교체나 자르기 후 포함) | id, title, status, version, durationSeconds, width, height, errorMessage |
video.failed |
새 동영상을 처리하지 못했을 때 | video.ready와 동일 |
video.deleted |
동영상이 휴지통으로 이동(trashed: true)되거나 영구 삭제되었을 때 |
id, title, trashed |
video.watched |
식별된 시청자(이메일 양식, ?email= 링크, WordPress 사이트를 통해 식별)가 동영상을 시작하거나, 25%, 50%, 75%를 지나거나, 끝까지 시청했을 때(여러 번 방문한 시청을 합쳐 90%). 시청자, 동영상, 마일스톤별로 한 번씩 발생합니다. |
video(id, title), viewer(email, name), progress(0, 25, 50, 75, 100), milestone(started, 25%, 50%, 75%, completed), completed |
lead.captured |
누군가 이메일 양식을 제출했을 때 | id, email, name, fields, video(id, title), createdAt |
전송
Pellio는 User-Agent: Pellio-Webhooks/1 헤더와 함께 POST 요청을 보내고 최대 10초 동안 기다립니다. 2xx 응답은 모두 전송 성공으로 처리합니다. 리디렉션은 따라가지 않으므로 3xx는 실패로 처리됩니다. 실패한 전송은 총 6번까지 시도하며, 첫 재시도 전에 20초를 기다리고 이후 대기 시간을 두 배씩 늘려 최대 320초까지 기다립니다.
서명 확인하기
모든 요청에는 엔드포인트의 시크릿으로 만든 Pellio-Signature 헤더가 포함됩니다: t=<unix time>,v1=<hex HMAC-SHA256 of "t.body">. 가공하지 않은 원본 요청 본문으로 서명을 확인하세요.
import { createHmac, timingSafeEqual } from 'node:crypto';
function verify(header, rawBody, secret) {
const { t, v1 } = Object.fromEntries(header.split(',').map((p) => p.split('=')));
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false; // 5-minute tolerance
const expected = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
return timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}
이 글이 도움이 되었나요?
관련 글