이벤트 API
재생, 참여 및 매출 신호를 NU로 전송합니다. 검증된 매출 이벤트는 정산에 반영됩니다. events:write가 필요합니다.
엔드포인트
| 메서드 | 경로 | 성공 | 용도 |
|---|---|---|---|
| POST | /events | 200 | 단일 이벤트 전송 |
| POST | /events/batch | 207 | 최대 500개 이벤트를 전송하고 항목별 결과 반환 |
이벤트 타입
다음 event_type 값만 허용됩니다. 알 수 없는 타입은 validation_failed를 반환합니다.
| event_type | 의미 | 필수 필드 | 정산 |
|---|---|---|---|
IMPRESSION | 타이틀 또는 포스터 노출 | — | 아니오 |
TITLE_VIEW | 타이틀 상세 열림 | title_id | 아니오 |
EPISODE_STARTED | 재생 시작 | title_id, episode_id | 아니오 |
PLAYBACK_PROGRESS | 하트비트 또는 사분위 진행 | episode_id, completion_rate | 아니오 |
EPISODE_COMPLETED | 재생 완료 | episode_id, completion_rate | 아니오 |
EPISODE_UNLOCKED | 유료 잠금 해제 부여 | episode_id | 지표 전용 |
PAYMENT_COMPLETED | 매출 | title_id, revenue_amount, currency | 예 |
REFUND | 환불 또는 취소 | title_id, revenue_amount, currency | 예(음수) |
SUBSCRIPTION_RENEWAL | 반복 매출 | title_id, revenue_amount, currency | 예 |
AD_IMPRESSION | 광고 또는 참여 신호 | — | 아니오 |
OTHER | 비표준 | — | 아니오 |
정산 대상 여부는 수집 파이프라인이 타입으로부터 도출하며 파트너 제공 플래그로 결정하지 않습니다.
필수 필드 및 검증 규칙
모든 이벤트에는 event_id와 event_type가 필요합니다. occurred_at은 선택이며 서버 수신 시각이 기본값입니다. 타입별 필드는 위 표를 참고하세요.
event_id는 조직별로 고유하며 멱등성을 제공합니다. 중복은 무연산으로409 duplicate_event_id를 반환하고 두 번 집계하지 않습니다.completion_rate은[0, 1]범위여야 합니다.- 매출 타입에는
title_id,revenue_amount, ISO 4217currency가 필요하며 그렇지 않으면validation_failed를 반환합니다. 매출은 대사를 위해 타이틀에 귀속되어야 합니다. occurred_at은 미래일 수 없습니다. 미래 이벤트는failed로 거부되며occurred_at_in_future가 표시됩니다. 24시간보다 오래된 이벤트는 허용되지만payload.late = true로 표시됩니다.viewer_id_hash는 해시된 식별자여야 하고 원시 PII를 포함하지 않아야 하며 그렇지 않으면validation_failed를 반환합니다.title_id,episode_id,playback_session_id를 보내면 키 환경에서 조회 가능하고 귀하의 조직에 속해야 합니다. 참조 실패는unknown_title_for_environment,unknown_episode_for_environment,playback_session_mismatch,license_not_active,episode_not_licensed같은 상세와 함께validation_failed를 반환합니다.
필드 제한
문자열 필드에는 길이 제한이 있으며 초과하면 validation_failed를 반환합니다:
| 필드 | 타입 | 제약 |
|---|---|---|
event_id | string | 1–200자(필수) |
event_type | string | 1–64자(필수) |
title_id | string | 최대 64자 |
episode_id | string | 최대 64자 |
playback_session_id | string | 최대 64자 |
viewer_id_hash | string | 최대 128자, 해시만 허용 |
country | string | 최대 8자 |
currency | string | 최대 8자 |
device | string | 최대 64자 |
completion_rate | number | 0–1 |
payload | object | 자유 형식 JSON, 직렬화 시 최대 4KB |
payload는 파트너 메타데이터용 선택적 자유 형식 JSON 객체입니다. 직렬화 크기는 최대 4,096바이트(4KB)여야 하며 초과하면 값이 유효하지 않습니다.과 함께 validation_failed를 반환합니다.
단일 이벤트 전송
curl -X POST "https://signal-partners.newunivers.ai/v1/events" \
-H "Authorization: Bearer nsp_live_xxx" \
-H "X-NU-Partner-Id: org_acme" \
-H "Accept-Language: ko" \
-H "Content-Type: application/json" \
-d '{
"event_id": "evt_acme_0001",
"event_type": "PAYMENT_COMPLETED",
"title_id": "ttl_abc",
"episode_id": "ep_001",
"viewer_id_hash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
"country": "KR",
"device": "web",
"revenue_amount": 3.99,
"currency": "USD",
"occurred_at": "2026-06-24T00:00:00Z"
}'{ "data": { "event_id": "evt_acme_0001", "status": "validated", "received_at": "2026-06-24T00:00:05.123Z" } }단일 이벤트 수집 성공 시 HTTP 200, status: "validated", ISO-8601 received_at 타임스탬프를 반환합니다.
중복
같은 event_id를 다시 보내면 다음을 반환합니다:
{
"error": {
"code": "duplicate_event_id",
"message": "이미 처리된 이벤트 ID입니다.",
"request_id": "req_..."
}
}검증 오류
{
"error": {
"code": "validation_failed",
"message": "요청 검증에 실패했습니다.",
"request_id": "req_...",
"details": [
{
"field": "currency",
"issue": "required",
"message": "필수 값이 누락되었습니다."
}
]
}
}배치 이벤트
요청당 최대 500개 이벤트를 보낼 수 있습니다. 각 항목은 독립 검증되며 일부가 실패해도 요청은 성공할 수 있도록 항목별 결과가 담긴 HTTP 207을 반환합니다.
curl -X POST "https://signal-partners.newunivers.ai/v1/events/batch" \
-H "Authorization: Bearer nsp_live_xxx" \
-H "X-NU-Partner-Id: org_acme" \
-H "Accept-Language: ko" \
-H "Content-Type: application/json" \
-d '{
"events": [
{ "event_id": "evt_1", "event_type": "EPISODE_STARTED", "title_id": "ttl_abc", "episode_id": "ep_001", "occurred_at": "2026-06-24T00:00:00Z" },
{ "event_id": "evt_1", "event_type": "EPISODE_STARTED", "title_id": "ttl_abc", "episode_id": "ep_001", "occurred_at": "2026-06-24T00:00:01Z" },
{ "event_id": "evt_3", "event_type": "PAYMENT_COMPLETED", "occurred_at": "2026-06-24T00:00:02Z" }
]
}'{
"data": {
"received": 3,
"accepted": 1,
"duplicated": 1,
"failed": 1,
"results": [
{ "event_id": "evt_1", "status": "accepted" },
{ "event_id": "evt_1", "status": "duplicated" },
{ "event_id": "evt_3", "status": "failed" }
]
}
}received는 제출 수(1–500)입니다. 각 항목의 status는 accepted | duplicated | failed 중 정확히 하나입니다. 항목에는 error_code 필드가 없습니다.
멱등성
서버가 event_id로 중복 제거하므로 안전하게 재시도할 수 있습니다. 재시도에는 같은 event_id를 사용하고 HTTP 시도마다가 아니라 실제 이벤트에 대해 생성하세요. 응답과 요청 로그에서 수집 상태를 확인하세요. 허용된 이벤트는 VALIDATED로 저장되고 반복 ID는 duplicated 무연산이 됩니다. 매출 이벤트는 정산에 반영됩니다.