이벤트 API

재생, 참여 및 매출 신호를 NU로 전송합니다. 검증된 매출 이벤트는 정산에 반영됩니다. events:write가 필요합니다.

엔드포인트

메서드경로성공용도
POST/events200단일 이벤트 전송
POST/events/batch207최대 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_idevent_type가 필요합니다. occurred_at은 선택이며 서버 수신 시각이 기본값입니다. 타입별 필드는 위 표를 참고하세요.

  • event_id는 조직별로 고유하며 멱등성을 제공합니다. 중복은 무연산으로 409 duplicate_event_id를 반환하고 두 번 집계하지 않습니다.
  • completion_rate[0, 1] 범위여야 합니다.
  • 매출 타입에는 title_id, revenue_amount, ISO 4217 currency가 필요하며 그렇지 않으면 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_idstring1–200자(필수)
event_typestring1–64자(필수)
title_idstring최대 64자
episode_idstring최대 64자
playback_session_idstring최대 64자
viewer_id_hashstring최대 128자, 해시만 허용
countrystring최대 8자
currencystring최대 8자
devicestring최대 64자
completion_ratenumber0–1
payloadobject자유 형식 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)입니다. 각 항목의 statusaccepted | duplicated | failed 중 정확히 하나입니다. 항목에는 error_code 필드가 없습니다.

멱등성

서버가 event_id로 중복 제거하므로 안전하게 재시도할 수 있습니다. 재시도에는 같은 event_id를 사용하고 HTTP 시도마다가 아니라 실제 이벤트에 대해 생성하세요. 응답과 요청 로그에서 수집 상태를 확인하세요. 허용된 이벤트는 VALIDATED로 저장되고 반복 ID는 duplicated 무연산이 됩니다. 매출 이벤트는 정산에 반영됩니다.