재생 API

한 시청자가 한 에피소드를 보도록 인가하고 즉시 WebView에서 재생할 호스팅 웹뷰 링크와 자체 플레이어용 동등한 서명 HLS/DASH 매니페스트를 받습니다. 선택적 비PII 환경설정으로 웹뷰를 개인화할 수 있습니다. playback:token가 필요합니다.

엔드포인트

메서드경로용도
POST/playback/tokens인가된 에피소드 → 웹뷰 링크 + 서명 매니페스트
GET/playback/sessions/{session_id}재생 세션 조회
POST/playback/sessions/{session_id}/revoke활성 세션 종료

토큰 요청

curl -X POST "https://signal-partners.newunivers.ai/v1/playback/tokens" \
  -H "Authorization: Bearer nsp_live_xxx" \
  -H "X-NU-Partner-Id: org_acme" \
  -H "X-NU-Request-Id: req_playback_0001" \
  -H "Content-Type: application/json" \
  -d '{
    "title_id": "ttl_abc",
    "episode_id": "ep_001",
    "viewer_id_hash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
    "country": "KR",
    "device": "web",
    "origin": "https://app.acme.example",
    "preferences": {
      "preferred_languages": ["ko", "en"],
      "preferred_genres": ["romance", "thriller"],
      "subtitle_language": "ko",
      "audio_language": "ko",
      "autoplay_next": true,
      "maturity_rating": "15"
    },
    "expires_in": 1800
  }'
필드필수비고
title_id
episode_id해당 타이틀에 속해야 함
viewer_id_hash파트너 측 SHA-256(stable_viewer_id + salt). Production은 정확히 64자 소문자 16진수를 요구하고 Sandbox는 기존 opaque ID를 허용합니다. 원시 PII 금지.
countryProduction 예 / Sandbox 아니오ISO 3166-1 alpha-2. Production에서 필수이며 계약 지역과 대조합니다. Sandbox에서는 선택이며 전달하면 노출된 권리 지역과 대조합니다.
device아니오예: web, ios, android
origin조건부키에 allowed_origins가 있으면 필수이며 그중 하나와 일치해야 합니다.
preferences아니오호스팅 웹뷰용 비PII 시청자 취향 신호. 아래 참고.
expires_in아니오토큰 TTL(초). 기본 1,800, 절대 최대 7,200, Production 기본 상한 1,800.

preferences(시청자 취향 신호)

호스팅 웹뷰가 자막·오디오 기본값, 자동 재생, 추천에 적용하고 분석용으로 세션에 저장하는 선택 객체입니다. 스키마는 엄격하여 알 수 없는 키는 422를 반환합니다. 값에 원시 PII가 없어야 하며 @ 또는 공백이 있으면 422 validation_failed를 반환합니다.

필드타입비고
preferred_languagesstring[] (≤20)선호 순서의 BCP-47 또는 ISO 언어 코드
preferred_genresstring[] (≤50)파트너 측 장르 태그
subtitle_languagestring기본 자막 트랙
audio_languagestring기본 오디오 또는 더빙 트랙
autoplay_nextboolean다음 에피소드 자동 재생
maturity_ratingstring시청자의 최대 관람 등급

이 엔드포인트는 선택적 X-NU-Request-Id로 멱등하게 동작합니다. 같은 ID 재시도는 원본 응답을 반환하고 처리 중인 동시 중복은 conflict(409)를 반환합니다.

응답

{
  "data": {
    "playback_session_id": "pbs_123",
    "expires_at": "2026-06-24T00:30:00Z",
    "webview_url": "https://signal-partners.newunivers.ai/w/pbs_123?t=...",
    "manifest": {
      "hls": "https://signal-partners.newunivers.ai/media/hls/pbs_123/signal-city/ep001/master.m3u8?token=...",
      "dash": "https://signal-partners.newunivers.ai/media/dash/pbs_123/signal-city/ep001/manifest.mpd?token=..."
    },
    "tracking": {
      "event_endpoint": "https://signal-partners.newunivers.ai/v1/events",
      "required_events": [
        "EPISODE_STARTED",
        "PLAYBACK_PROGRESS",
        "EPISODE_COMPLETED"
      ]
    }
  }
}

동일한 인가 세션을 재생하는 두 가지 동등한 방법이 제공됩니다. 하나를 선택하세요.

  • webview_url(권장): NU가 호스팅하는 재생 전용 페이지입니다. WebView(WKWebView/android.webkit.WebView) 또는 <iframe>에서 여세요. 내부적으로 매니페스트를 해석하고 저장된 preferences를 적용하므로 플레이어 연동이 필요 없습니다. 링크에는 세션 ID와 서명된 ?t=이 있으므로 시크릿으로 취급하고 expires_at 이후 캐시하지 마세요.
  • manifest(자체 플레이어): 자체 플레이어 운영 파트너를 위한 서명 HLS/DASH URL입니다. 각 매니페스트·세그먼트 요청에서 서명, TTL, 세션 ID 및 승인 미디어 경로를 검증합니다. 원본 마스터 파일은 반환하지 않습니다. 검증은 앱의 /media 또는 동등한 Cloudflare 엣지 워커에서 실행되며 URL 규약은 같습니다.

두 방식 모두 같은 playback_session_id에 바인딩되며 어느 쪽이든 동일하게 이벤트를 보고합니다.

테스트 웹뷰

실제 세션 전 테스트 플레이어를 열어 WebView 또는 iframe 연동을 검증하세요. 토큰, 세션 또는 미디어 설정 없이 Episode 009 Confession 9:16 프리뷰를 즉시 재생합니다.

https://signal-partners.newunivers.ai/w/test?subtitle=ko&audio=ko&lang=ko&autoplay=1

테스트는 webview_url과 동일한 플레이어를 사용합니다. 세로형 샘플이 WebView에서 재생되면 실제 링크도 같은 9:16 화면 정책을 사용합니다.

검증 순서

검사는 순서대로 실행됩니다. 타이틀 또는 에피소드가 없으면 resource_not_found(404)를 반환합니다. 리소스 확인 후 인가 실패는 403을 반환하고 BLOCKED 세션에 block_reason을 기록합니다.

  1. API 키가 유효하고 playback:token를 보유합니다. 키 환경이 카탈로그 및 세션 접근 범위를 결정합니다.
  2. 타이틀이 해당 환경에 노출되고 에피소드가 타이틀에 속해야 하며 그렇지 않으면 resource_not_found입니다.
  3. 권리 패키지가 만료되지 않았고 status ∈ {CLEAR, RESTRICTED}apiStreamingAllowed = true을 충족해야 합니다.
  4. 에피소드가 READY이고 승인·미삭제·HLS 준비 완료 영상 에셋이 있으며 에셋 권리는 CLEAR 또는 RESTRICTED여야 합니다.
  5. Production: country가 필수이고 ACTIVE 계약이 타이틀·지역을 포괄하며 production_api_enabled = true이고 준비된 영상 에셋을 accessLevel = stream으로 포함해야 합니다. Sandbox: 계약은 필요 없으며 country가 있으면 노출 권리 지역과 대조합니다.
  6. 키에 allowed_origins가 있으면 origin이 필수이고 일치해야 합니다. allowed_ips가 설정되면 토큰 발급 요청 IP가 일치해야 합니다. 발급 시점에만 적용되며 토큰은 시청자 IP에 바인딩되지 않습니다.
  7. 동시 세션 상한: Production 계약 또는 Sandbox 타이틀별 viewer_id_hash당 최대 PLAYBACK_MAX_CONCURRENT_SESSIONS개(기본 3) 활성 세션입니다. 초과 발급은 BLOCKED 세션을 만들고 playback_concurrency_limit(429)를 반환합니다.

오류 사유

error.codeHTTP원인
resource_not_found404타이틀이 환경에 비공개이거나 에피소드가 없거나 다른 타이틀에 속함
missing_scope403키에 playback:token이 없음
license_not_active403ACTIVE 계약이 없거나 production_api_enabled가 false이거나 노출된 스트리밍 가능 권리 패키지가 없음
territory_not_allowed403Production country 누락, country가 계약·권리 지역 밖, 필수 origin 누락 또는 origin/IP 차단
episode_not_licensed403에피소드가 READY가 아니거나 준비된 영상 에셋이 없거나 에셋이 라이선스 집합 밖
validation_failed422viewer_id_hash가 원시 PII로 보이거나 preferences에 알 수 없는 키 또는 원시 PII('@'나 공백)가 있음
playback_concurrency_limit429이 시청자와 계약 또는 타이틀의 활성 세션이 너무 많음
conflict409처리 중 X-NU-Request-Id를 사용한 동시 중복 요청

세션

curl "https://signal-partners.newunivers.ai/v1/playback/sessions/pbs_123" \
  -H "Authorization: Bearer nsp_live_xxx" -H "X-NU-Partner-Id: org_acme"
{
  "data": {
    "playback_session_id": "pbs_123",
    "title_id": "ttl_abc",
    "episode_id": "ep_001",
    "status": "issued",
    "block_reason": null,
    "preferences": { "subtitle_language": "ko", "autoplay_next": true },
    "expires_at": "2026-06-24T00:30:00Z",
    "started_at": null,
    "completed_at": null
  }
}

API는 저장된 세션 상태를 소문자로 반환합니다. 흐름: issued → started → completed | expired | revoked | blocked. 토큰 발급은 issued를 만들고 EPISODE_STARTEDstarted로 전진시키며 started_at을 채웁니다. EPISODE_COMPLETEDcompleted로 전진시키고 completed_at을 채웁니다. TTL 이후 조회는 expired를 저장하고 인가 실패는 block_reason이 있는 blocked를 만듭니다. 알 수 없는 ID는 invalid_playback_session(400)를 반환합니다.

세션 폐기

curl -X POST "https://signal-partners.newunivers.ai/v1/playback/sessions/pbs_123/revoke" \
  -H "Authorization: Bearer nsp_live_xxx" -H "X-NU-Partner-Id: org_acme"

활성 issued/started 세션을 revoked로 표시하여 동시 세션 수에서 제외합니다. 응답은 실제 최종 상태를 반환하며 종료된 세션은 completed, expired 또는 기존 상태를 유지합니다. 앱 /media 경로는 다음 매니페스트 요청에서 폐기를 확인하지만 기존 엣지 워커 토큰은 TTL 동안 유효할 수 있으므로 TTL을 짧게 유지하세요.

viewer_id_hash 및 만료

  • viewer_id_hash는 안정적인 시청자 ID와 서버 보관 솔트의 SHA-256이어야 합니다. Production은 정확히 64자 소문자 16진수를 허용하고 Sandbox는 기존 opaque ID를 유지합니다. NU는 preferences를 포함해 원시 PII를 수락하거나 저장하지 않으며 @ 또는 공백 값은 거부합니다.
  • 토큰은 수명이 짧습니다: 기본 1,800초, 절대 최대 7,200초, Production 기본 상한 1,800초. 만료 시 재발급하고 expires_at 이후 webview_url 또는 매니페스트 URL을 캐시하지 마세요. webview_url에는 서명 토큰이 있으므로 로그나 공유 링크에 넣지 마세요.
  • 키를 폐기하거나 계약을 비활성화해도 이미 발급된 재생 토큰은 취소되지 않습니다. TTL을 짧게 유지하고 만료 시 재발급하세요.

반환된 playback_session_id를 사용하여 이벤트 API로 재생 활동을 보고하세요.