본문으로 건너뛰기
개발자

NULX API로 만드세요.

내 스토리지에 영상을 올리고, 재생 준비까지 상태를 추적하고, 서명된 재생 URL을 발급받는 테넌트 범위 REST API입니다.

인증

헤더 하나, 범위가 정해진 키.

모든 요청에 키를 함께 보냅니다. 키는 대시보드에서 만들며 필요한 범위만 담을 수 있습니다.

요청 예시

curl https://api.nulx.dev/api/v1/assets \
  -H "X-API-Key: $NULX_API_KEY"

사용 가능한 범위

assets:read 영상 자산·컬렉션·분석을 조회합니다.
assets:write 업로드 세션을 만들고 자산을 등록·수정합니다.
playback:read 재생 URL과 서명된 재생 토큰을 발급받습니다.
billing:write 테넌트의 청구 예상액을 조회합니다.
api_keys:read 기존 API 키 목록을 조회합니다.
api_keys:write API 키를 만들고 폐기합니다.
webhooks:read 웹훅 엔드포인트 목록을 조회합니다.
webhooks:write 웹훅 엔드포인트를 만들고 일시중지·삭제합니다.

API 키는 유료 플랜에서 제공됩니다. 무료 플랜은 키 화면을 볼 수 있지만 발급은 불가합니다.

키는 서버에만 두세요. 브라우저 JavaScript나 앱 번들에 API 키를 넣지 마세요 — 브라우저는 백엔드가 반환한 단기 재생 URL을 쓸 수 있지만, 직접 발급하면 안 됩니다.

빠른 시작

업로드에서 재생까지, 호출 세 번.

  1. 1. 업로드 시작

    사전 서명된 PUT URL을 요청합니다. 응답에는 upload_url, upload_headers, 업로드 id가 들어 있습니다.

    curl -X POST https://api.nulx.dev/api/v1/uploads/initiate \
      -H "X-API-Key: $NULX_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{"filename":"launch.mp4","bytes_expected":73400320}'
  2. 2. 파일을 PUT 한 뒤 완료 처리

    받은 헤더 그대로 upload_url에 원본 바이트를 보낸 뒤, complete를 호출해 트랜스코딩을 큐에 넣습니다.

    curl -X PUT "<upload_url>" \
      -H "Content-Type: video/mp4" \
      --upload-file launch.mp4
    
    curl -X POST https://api.nulx.dev/api/v1/uploads/<id>/complete \
      -H "X-API-Key: $NULX_API_KEY"
  3. 3. 준비되면 재생 정보 조회

    playback_status가 ready가 될 때까지 자산을 폴링하거나 video.asset.ready 웹훅을 등록한 뒤, 재생 토큰을 요청합니다.

    curl https://api.nulx.dev/api/v1/playback/<asset_id> \
      -H "X-API-Key: $NULX_API_KEY"

레퍼런스

공개 엔드포인트 전체.

아래 OpenAPI 문서와 같은 원본에서 생성한 표라 어긋날 수 없습니다.

Tenants

GET /api/v1/tenants List tenants visible to the caller

Video Assets

GET /api/v1/assets List video assets for the caller's tenant
POST /api/v1/assets Create a video asset directly (out-of-band ingestion)
GET /api/v1/assets/export Export asset metadata (CSV or JSON)
GET /api/v1/assets/graph_export No-lock-in asset graph export (JSON)
GET /api/v1/assets/duplicates Duplicate detection lookup (desktop uploader 중복 알림)
POST /api/v1/assets/import Bulk import asset metadata from CSV
GET /api/v1/assets/{id} Fetch a single video asset
PATCH /api/v1/assets/{id} Update a video asset's title, description, or collection
PUT /api/v1/assets/{id} Update a video asset's title, description, or collection (PUT alias)
PATCH /api/v1/assets/{id}/tags Add or update schemaless tags on an asset
DELETE /api/v1/assets/{id}/tags/{key} Remove a tag from an asset
GET /api/v1/assets/{id}/download Get a short-lived signed download URL for the original source
GET /api/v1/assets/{id}/deovr_manifest.json Get a DeoVR/HereSphere deep-link manifest for a publicly playable asset
GET /api/v1/analytics Tenant-wide viewer analytics summary
GET /api/v1/assets/{id}/analytics Per-asset viewer analytics summary

Collections

GET /api/v1/collections List collections (folders) for the caller's tenant
POST /api/v1/collections Create a collection (folder) for organizing assets
GET /api/v1/collections/tree Nested collection tree for the tenant
PATCH /api/v1/collections/{id} Update a collection
PUT /api/v1/collections/{id} Update a collection (PUT alias)
DELETE /api/v1/collections/{id} Delete a collection

Subtitles

GET /api/v1/assets/{video_asset_id}/subtitles List subtitle/caption tracks for a video asset
POST /api/v1/assets/{video_asset_id}/subtitles Upload a subtitle/caption track for a video asset
PATCH /api/v1/assets/{video_asset_id}/subtitles/{id} Update a subtitle/caption track
PUT /api/v1/assets/{video_asset_id}/subtitles/{id} Update a subtitle/caption track (PUT alias)
DELETE /api/v1/assets/{video_asset_id}/subtitles/{id} Remove a subtitle/caption track
POST /api/v1/assets/{video_asset_id}/subtitles/{id}/sync Re-time a subtitle/caption track against a reference track
POST /api/v1/assets/{video_asset_id}/subtitles/{id}/translate Create a new language track by machine-translating an existing one

Tracks

GET /api/v1/assets/{video_asset_id}/tracks List timecode-anchored tracks for a video asset
POST /api/v1/assets/{video_asset_id}/tracks Create or replace an asset track (idempotent upsert)
PUT /api/v1/assets/{video_asset_id}/tracks Create or replace an asset track (idempotent upsert, PUT alias)
GET /api/v1/assets/{video_asset_id}/tracks/{id} Show a single asset track
PATCH /api/v1/assets/{video_asset_id}/tracks/{id} Update an asset track by id
PUT /api/v1/assets/{video_asset_id}/tracks/{id} Update an asset track by id (PUT alias)
DELETE /api/v1/assets/{video_asset_id}/tracks/{id} Remove an asset track

Uploads

POST /api/v1/uploads/initiate Create a tenant-scoped direct upload session
POST /api/v1/uploads/initiate_multipart Initiate a resumable multipart source upload
POST /api/v1/uploads/{id}/sign_part Presign a single S3 multipart part PUT
POST /api/v1/uploads/{id}/complete_multipart Finalize a multipart/resumable upload
POST /api/v1/uploads/{id}/abort_multipart Abort a multipart/resumable upload
GET /api/v1/uploads/{id} Fetch an upload session's status
POST /api/v1/uploads/{id}/complete Mark an upload complete and enqueue transcoding

API Keys

GET /api/v1/api_keys List API keys for the caller's tenant
POST /api/v1/api_keys Issue a new API key for a tenant
DELETE /api/v1/api_keys/{id} Revoke an API key

Device Tokens

POST /api/v1/device_tokens Redeem a desktop pairing code for a device token
DELETE /api/v1/device_tokens/current Revoke the API key used for this request

Billing

GET /api/v1/billing/estimate Estimate the current billing period charges

Usage

GET /api/v1/usage/summary Current-month usage and billing estimate per tenant

Encoding

GET /api/v1/encoding_spec Canonical transcoding encoding specification

Playback

GET /api/v1/assets/{id}/deovr_manifest.json Get a DeoVR/HereSphere deep-link manifest for a publicly playable asset
GET /api/v1/playback/{id} Get playback URLs and a signed playback token for an asset
POST /api/v1/playback_events Ingest a viewer playback beacon (public, unauthenticated)

Ingest Batches

GET /api/v1/ingest_batches/desktop_storage Resolve the server-managed desktop upload storage
POST /api/v1/ingest_batches Create a storage ingest batch lease
GET /api/v1/ingest_batches/{id} Fetch ingest batch status
POST /api/v1/ingest_batches/{id}/manifest/preview Validate an ingest manifest without mutation
POST /api/v1/ingest_batches/{id}/manifest/commit Commit a client encoder manifest to assets
POST /api/v1/ingest_batches/{id}/cancel Cancel an uncommitted ingest batch
POST /api/v1/ingest_batches/{id}/uploads Create a server-managed desktop object upload
GET /api/v1/ingest_batches/{id}/uploads List upload intents recorded for a desktop batch (resume/이어올리기)
PUT /api/v1/ingest_batches/{id}/uploads/{upload_id}/proxy Stream a small object through the control plane to Bunny
PUT /api/v1/ingest_batches/{id}/uploads/{upload_id}/proxy_parts/{part_number} Stage one part of a chunked Bunny server-proxy upload
POST /api/v1/ingest_batches/{id}/uploads/{upload_id}/proxy_complete Assemble and commit a chunked Bunny server-proxy upload
POST /api/v1/ingest_batches/{id}/uploads/{upload_id}/parts Sign one exact R2 multipart part
POST /api/v1/ingest_batches/{id}/uploads/{upload_id}/parts/{part_number}/complete Durably record one confirmed multipart part etag (resume/이어올리기)
POST /api/v1/ingest_batches/{id}/uploads/{upload_id}/complete Complete an R2 multipart upload
DELETE /api/v1/ingest_batches/{id}/uploads/{upload_id} Abort an active R2 multipart upload

Webhooks

GET /api/v1/webhooks List webhook endpoints for the caller's tenant(s)
POST /api/v1/webhooks Register a new webhook endpoint for a tenant
DELETE /api/v1/webhooks/{id} Delete a webhook endpoint
PATCH /api/v1/webhooks/{id}/active Activate or deactivate a webhook endpoint

오류

오류는 항상 JSON입니다.

실패는 error와 code 쌍을 반환합니다. 메시지가 아니라 code로 판별하세요.

형태

{
  "error": "insufficient_scope",
  "code": "forbidden_scope",
  "required_scopes": ["assets:write"]
}

주요 코드

unauthorized API 키가 없거나, 잘못됐거나, 만료됐습니다.
forbidden_scope 키는 유효하지만 필요한 범위가 없습니다.
parameter_missing 필수 파라미터가 없거나 잘못됐습니다.
playback_token_required 서명 재생 자산입니다 — 먼저 토큰을 요청하세요.
rate_limited 요청이 너무 많습니다. 잠시 후 다시 시도하세요.
not_found 내 테넌트에 해당 리소스가 없습니다.
internal_server_error 서버 측 문제입니다 — 재시도하거나 문의하세요.

웹훅

폴링 대신 구독하세요.

HTTPS 엔드포인트를 등록하면 video.asset.ready, video.upload.failed 등 수명주기 이벤트를 서명된 JSON으로 보내드립니다. 모든 전달은 HMAC로 서명되며, 검증 방법은 스펙에 있습니다.

OpenAPI

계약 전체를 가져가세요.

공개 표면 전체의 OpenAPI 3.0 문서입니다 — Swagger UI, Postman, 클라이언트 생성기에 바로 넣을 수 있습니다.

API에 대해 궁금한 점이 있나요? 문의하기