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. 업로드 시작
사전 서명된 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. 파일을 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. 준비되면 재생 정보 조회
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에 대해 궁금한 점이 있나요? 문의하기