Owl3D Cloud API
이 API는 2D 영상을 사이드 바이 사이드 3D로 변환합니다. 코드에서 가격을 받고, 파일을 업로드하고, 작업이 끝나기를 기다린 뒤 결과를 다운로드합니다. 변환 방식은 Owl3D Cloud와 같습니다.
AI 코딩 에이전트는 /llms.txt에서 이 페이지를 일반 텍스트로 읽을 수 있습니다. AI 에이전트는 Owl3D MCP 서버로 코드 없이 동영상을 변환할 수도 있습니다.
시작하기 전에
- app.owl3d.com에 로그인하고 이메일 주소를 인증합니다.
- 요금제에 가입하거나 크레딧을 구매합니다. 작업은 요금제의 월 크레딧을 먼저 쓰고, 그다음 체험 크레딧, 마지막으로 구매한 크레딧을 씁니다.
- API 키 페이지를 열고 키를 만듭니다. 키는 한 번만 표시됩니다.
키는 환경 변수 OWL3D_API_KEY에 넣어 두세요. 이 페이지의 모든 예제는 여기에서 키를 읽습니다.
API 사용에는 Owl3D Cloud API Terms(영어)가 적용됩니다.
export OWL3D_API_KEY="o3d_live_..."인증
| 항목 | 값 |
|---|---|
| Base URL | https://api.owl3d.com |
| 키 형식 | o3d_live_<keyId>_<secret> |
| 인증 헤더 | Authorization: Bearer <key> |
Bearer는 대문자 B로 쓰고 뒤에 공백 하나를 둡니다. 다른 형식은 401을 받습니다.
각 라우트에는 스코프가 필요합니다: jobs:read 또는 jobs:write. 라우트별 스코프는 라우트 표에 있습니다.
키는 비밀로 유지하세요. 키로 크레딧을 쓸 수 있습니다. 키가 유출되면 API 키 페이지에서 폐기하세요. 폐기한 키는 60초 안에 작동을 멈춥니다.
GET /v1/jobs/{id}
curl https://api.owl3d.com/v1/jobs/job_... \
-H "Authorization: Bearer $OWL3D_API_KEY"{"id": "job_...", "status": "converting"}영상 하나 변환하기
스크립트 하나를 내려받아 영상에 실행하세요. 모든 스크립트가 아래 단계를 전부 수행합니다.
| 스크립트 | 필요한 것 | 실행 |
|---|---|---|
| convert.sh | bash, curl, jq, ffprobe | bash convert.sh my-video.mp4 |
| convert.py | Python 3.9+, requests, ffprobe |
python3 convert.py my-video.mp4 |
| convert.mjs | Node.js 20+, ffprobe | node convert.mjs my-video.mp4 |
convert.sh · convert.py · convert.mjs
curl -O https://www.owl3d.com/docs/api/convert.sh
bash convert.sh my-video.mp4스크립트는 선택 사항입니다. 직접 작성하는 코드는 어떤 언어든 사용할 수 있습니다. HTTPS 호출, SHA-256, 파일 정보만 있으면 됩니다. 먼저 업로드 방식에서는 HTTPS 호출만 있으면 됩니다.
과정은 여섯 단계입니다.
- 파일 정보를 읽고 핑거프린트를 만듭니다.
POST /v1/estimates: 가격을 받습니다. 요금은 청구되지 않습니다.POST /v1/jobs: 가격을 승인합니다. 크레딧이 예약됩니다.- 각 파트를 업로드 URL에
PUT한 다음POST /v1/jobs/{id}/upload-complete를 호출합니다. - 15초마다
GET /v1/jobs/{id}를 폴링합니다. GET /v1/jobs/{id}/result: 다운로드 링크를 받습니다. 링크는 15분 동안,GET으로만 사용할 수 있습니다.
먼저 업로드 방식은 1단계와 2단계를 건너뜁니다. 코드는 파일 이름과 크기를 POST /v1/jobs로 보냅니다. 업로드 후 서버가 파일을 읽고 가격을 정합니다.
오류
대부분의 오류 응답은 JSON 본문이며, error에 짧은 코드가 들어 있습니다.
| 상태 | 의미 |
|---|---|
400 |
잘못된 요청. 예: bad_fingerprint |
401 |
토큰이 없거나, 토큰이 틀렸거나, 키가 폐기되었습니다 |
402 |
short_of_credits: 요금제, 체험, 구매 크레딧을 합쳐도 가격에 부족합니다 |
403 |
insufficient_scope이거나 공개되지 않은 경로입니다 |
404 |
no_job. Cloud 앱에서 만든 작업은 API에서 보이지 않습니다 |
409 |
상태 충돌. 예: not_uploading, endpoint_exists |
410 |
출력이 만료되었습니다. 또는 insufficient_credits_expired: 작업이 크레딧을 24시간 기다렸습니다 |
429 |
한도가 가득 찼습니다. 제한을 보세요 |
재시도 규칙:
429이면Retry-After초만큼 기다린 뒤 같은 요청을 보냅니다.5xx또는 네트워크 오류이면 1초에서 60초까지 백오프합니다.- 그 밖의
4xx이면 요청을 고칩니다.
curl -i https://api.owl3d.com/v1/jobs/job_unknown \
-H "Authorization: Bearer $OWL3D_API_KEY"{"error": "no_job"}제한
| 제한 | 값 | 응답 |
|---|---|---|
| 진행 중인 작업 | 계정의 모든 API 키를 합쳐 10개. 모든 채널을 합쳐 계정당 15개. 키당 한도는 선택 | 429 concurrency_limit, Retry-After: 15 |
| 요청 | 키당 분당 120회 | 429, Retry-After: 60 |
| 버스트 | 라우트마다 초당 10회, 버스트 20회, 모든 호출자 합산 | 429 throttled, Retry-After: 1 |
| 일일 크레딧 한도 | 키마다 선택 사항 | 429 daily_credit_cap, 00:00 UTC까지 |
| 활성 키 | 계정당 10개 | 생성이 거부됩니다 |
| 입력 | 100 GB, 3시간, 4096 x 2160, 60 fps | 가격 조회가 거부됩니다 |
| 컨테이너 | MP4, MOV, MKV, M4V | 가격 조회가 거부됩니다 |
429 concurrency_limit 본문은 가득 찬 한도를 알려 줍니다. scope는 api(계정의 모든 API 키), account(계정의 모든 작업), key(이 키) 중 하나입니다. 작업 하나가 끝나면 다음 작업을 시작하세요.
{
"error": "concurrency_limit",
"scope": "api",
"limit": 10,
"inProgress": 10
}라우트
| 메서드와 경로 | 스코프 | 설명 |
|---|---|---|
POST /v1/estimates |
jobs:write |
가격과 소요 시간. 요금은 청구되지 않습니다. 1시간 동안 유효하며 작업 하나에만 쓸 수 있습니다 |
POST /v1/jobs |
jobs:write |
크레딧을 예약하고 업로드 계획을 반환합니다. estimateId를 보내거나, filename과 sizeBytes를 보냅니다(먼저 업로드) |
GET /v1/jobs/{id}/upload |
jobs:read |
업로드 상태: done, missing, 새 parts URL |
POST /v1/jobs/{id}/upload-complete |
jobs:write |
ETag를 보내고 작업을 대기열에 넣습니다 |
GET /v1/jobs/{id} |
jobs:read |
상태, 진행률, 남은 시간 |
POST /v1/jobs/{id}/cancel |
jobs:write |
작업을 취소합니다 |
POST /v1/jobs/{id}/resume |
jobs:write |
크레딧을 추가한 후 insufficient_credits 작업을 계속합니다. 다시 업로드하지 않습니다 |
GET /v1/jobs/{id}/result |
jobs:read |
다운로드 링크, 15분 |
가격 조회
POST /v1/estimates는 파일 하나의 가격과 소요 시간을 알려 줍니다. 요금은 청구되지 않습니다. 가격 조회는 1시간 동안 유효하며 작업 하나에만 쓸 수 있습니다.
| 필드 | 값 |
|---|---|
name, size |
파일 이름과 바이트 단위 크기 |
durationSeconds, width, height, fps |
ffprobe, MediaInfo 등 어떤 도구로든 파일에서 읽습니다 |
codec |
H.264, HEVC, AV1, VP9 중 하나 |
bitDepth, chroma |
파일에서 읽습니다. chroma는 4:2:0입니다 |
fingerprint |
{size, headSha256, tailSha256, edgeBytes} |
edgeBytes는 4194304이며, 더 작은 파일이면 파일 크기입니다.headSha256과tailSha256은 파일의 처음edgeBytes바이트와 마지막edgeBytes바이트의 해시입니다.
응답에서 "ok": false는 가격 조회가 거부되었다는 뜻입니다. reason을 읽으세요. credits.shortBy가 0보다 크면 계정에 크레딧이 더 필요합니다. credits.fromPlan, credits.fromTrial, credits.fromPurchased는 어떤 크레딧으로 가격을 내는지 보여 줍니다.
POST /v1/estimates
curl https://api.owl3d.com/v1/estimates \
-H "Authorization: Bearer $OWL3D_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "my-video.mp4",
"size": 104857600,
"durationSeconds": 120,
"width": 1920, "height": 1080, "fps": 24,
"codec": "H.264", "bitDepth": 8, "chroma": "4:2:0",
"fingerprint": {
"size": 104857600,
"headSha256": "<SHA-256 of the first 4194304 bytes>",
"tailSha256": "<SHA-256 of the last 4194304 bytes>",
"edgeBytes": 4194304
}
}'{
"ok": true,
"id": "est_...",
"credits": {
"total": 60,
"fromPlan": 60,
"fromTrial": 0,
"fromPurchased": 0,
"shortBy": 0
},
"etaMinutes": 6,
"hdr": {"detected": false},
"output": {"format": "FULL_SBS", "width": 3840, "height": 1080}
}작업
{"estimateId": "est_..."}를 담아 POST /v1/jobs를 호출하면 가격을 승인합니다. 크레딧이 예약됩니다. 응답에는 작업 id와 업로드 계획(upload.partSize와 upload.parts URL)이 들어 있습니다.
출력 옵션
POST /v1/jobs는 output: {layout, max_height}도 받습니다.
layout:full_sbs(기본값).max_height:"source"(기본값),2160또는1080.
POST /v1/jobs
curl https://api.owl3d.com/v1/jobs \
-H "Authorization: Bearer $OWL3D_API_KEY" \
-H "Content-Type: application/json" \
-d '{"estimateId": "est_...", "output": {"layout": "full_sbs", "max_height": "source"}}'{
"id": "job_...",
"status": "uploading",
"upload": {
"partSize": 67108864,
"parts": ["https://...", "https://..."],
"completeUrl": "/v1/jobs/job_.../upload-complete"
}
}먼저 업로드
estimateId 없이 POST /v1/jobs를 보냅니다. 코드는 파일을 읽지 않고 핑거프린트도 만들지 않습니다.
| 필드 | 값 |
|---|---|
filename |
파일 이름, 최대 255자. .mp4, .mov, .mkv 또는 .m4v로 끝납니다 |
sizeBytes |
파일 크기(바이트) |
output |
선택 사항. 출력 옵션을 참고하세요 |
- 잔액이 최소 가격 이상이어야 합니다. 그렇지 않으면 응답은
402 short_of_credits이며 작업이 만들어지지 않습니다. 201응답에는reservedCredits와"priceAfterUpload": true도 있습니다.- 업로드 후 서버가 파일을 읽고 가격을 정합니다.
- 서버가 파일을 변환할 수 없으면 작업은
failed가 됩니다. 요금은 청구되지 않으며 파일은 삭제됩니다.
HDR10 영상은 가격 조회가 필요합니다. 가격 조회가 없으면 응답은 400 hdr_needs_estimate입니다.
POST /v1/jobs (upload first)
curl https://api.owl3d.com/v1/jobs \
-H "Authorization: Bearer $OWL3D_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"filename\": \"my-video.mp4\", \"sizeBytes\": $(wc -c < my-video.mp4)}"{
"id": "job_...",
"status": "uploading",
"upload": {
"partSize": 67108864,
"parts": ["https://...", "https://..."],
"completeUrl": "/v1/jobs/job_.../upload-complete"
},
"reservedCredits": 15,
"priceAfterUpload": true
}크레딧 부족
가격이 잔액보다 높으면 작업은 insufficient_credits가 됩니다. 요금은 청구되지 않습니다. 가격 조회가 있든 없든 같습니다.
GET /v1/jobs/{id}에shortBy(추가할 크레딧),neededCredits,deleteAt,resumeUrl이 표시됩니다.- 크레딧을 추가한 다음
POST /v1/jobs/{id}/resume을 보냅니다. 파일을 다시 업로드하지 마세요. - 잔액이 아직 부족하면 resume은
shortBy와 함께402 short_of_credits를 반환합니다. deleteAt(24시간)까지 resume하지 않으면 작업은insufficient_credits_expired로failed가 됩니다. 파일은 삭제됩니다.
POST /v1/jobs/{id}/resume
curl -X POST https://api.owl3d.com/v1/jobs/job_.../resume \
-H "Authorization: Bearer $OWL3D_API_KEY"{
"id": "job_...",
"status": "queued"
}{
"error": "short_of_credits",
"shortBy": 120,
"neededCredits": 450,
"deleteAt": "2026-11-04T09:00:00.000Z"
}업로드
- 파일을
upload.partSize바이트 크기의 파트로 자릅니다. 파트 1은 바이트 0에서 시작합니다. - 각 파트를
upload.parts의 해당 URL에PUT합니다. 각 응답의ETag헤더를 따옴표까지 그대로 보관합니다. - 파트 순서대로
{"etags": [...]}를 담아POST /v1/jobs/{id}/upload-complete를 호출합니다.
각 URL은 정확히 한 가지 길이로 서명되어 있습니다. 파트는 partSize 바이트여야 하고, 마지막 파트가 나머지를 담습니다. 다른 길이이거나 chunked 본문이면 스토리지가 403을 반환합니다. Content-Length를 보내세요.
업로드가 멈춰도 처음부터 다시 시작하지 마세요.
GET /v1/jobs/{id}/upload를 호출합니다.done을 읽습니다. 각 항목에partNumber,etag,size가 있습니다.missing을 읽습니다. 파트 번호 목록입니다.- 빠진 파트를 각각
parts[partNumber - 1]에 업로드합니다. 이 URL은 1시간 동안 새 것으로 유효합니다. - 모든 ETag를 파트 순서대로 담아 완료합니다. 같은 파일을 사용하세요.
업로드는 24시간 안에 완료하세요. 그 후에는 스토리지가 완료되지 않은 업로드의 파트를 삭제합니다.
PUT upload.parts[n] · POST /v1/jobs/{id}/upload-complete
split -b 67108864 my-video.mp4 part_
curl -sS -D - -o /dev/null -X PUT --upload-file part_aa "<upload.parts[0]>" | grep -i '^etag'
curl -sS -D - -o /dev/null -X PUT --upload-file part_ab "<upload.parts[1]>" | grep -i '^etag'
curl https://api.owl3d.com/v1/jobs/job_.../upload-complete \
-H "Authorization: Bearer $OWL3D_API_KEY" \
-H "Content-Type: application/json" \
-d '{"etags": ["\"<etag of part 1>\"", "\"<etag of part 2>\""]}'{"id": "job_...", "status": "queued"}GET /v1/jobs/{id}/upload
curl https://api.owl3d.com/v1/jobs/job_.../upload \
-H "Authorization: Bearer $OWL3D_API_KEY"{
"id": "job_...",
"partSize": 67108864,
"parts": ["https://...", "https://..."],
"completeUrl": "/v1/jobs/job_.../upload-complete",
"done": [{"partNumber": 1, "etag": "\"...\"", "size": 67108864}],
"missing": [2]
}작업 상태
GET /v1/jobs/{id}는 상태, 진행률, 남은 시간을 알려 줍니다. 15초마다 폴링하세요.
status |
의미 |
|---|---|
uploading |
작업이 파일을 기다립니다 |
queued |
작업이 GPU를 기다립니다. 작업이 converting에서 잠시 queued로 돌아갈 수 있습니다 |
converting |
progress가 0에서 1로 진행됩니다 |
delayed |
저희 쪽에서 보류 중입니다. 크레딧은 예약된 상태로 유지됩니다 |
insufficient_credits |
가격이 잔액보다 높습니다. shortBy 크레딧을 추가한 다음 resume합니다. 크레딧 부족을 참고하세요 |
done |
완료되었습니다. result에 이름, 크기, 링크 경로가 들어 있습니다 |
failed |
error에 code가 있습니다. 크레딧은 돌아왔습니다 |
cancelled |
호출한 쪽에서 취소했습니다 |
GET /v1/jobs/{id}
curl https://api.owl3d.com/v1/jobs/job_... \
-H "Authorization: Bearer $OWL3D_API_KEY"{
"id": "job_...",
"status": "converting",
"progress": 0.42,
"etaSeconds": 310
}결과
GET /v1/jobs/{id}/result는 done 상태인 작업의 다운로드 링크를 줍니다. 링크는 15분 동안, GET으로만 사용할 수 있습니다. 새 링크가 필요하면 이 라우트를 다시 호출하세요. 출력이 만료되었으면 응답은 410입니다.
GET /v1/jobs/{id}/result
curl https://api.owl3d.com/v1/jobs/job_.../result \
-H "Authorization: Bearer $OWL3D_API_KEY"
curl -o output.mp4 "<url>"{
"url": "https://...",
"filename": "...",
"sizeBytes": 209715200,
"expiresInS": 900
}취소
POST /v1/jobs/{id}/cancel은 작업을 취소합니다. 변환이 시작되기 전에 취소한 작업은 비용이 들지 않습니다. 시작된 뒤에는 가격 x progress를 올림한 금액이며, 최소 1크레딧입니다.
POST /v1/jobs/{id}/cancel
curl -X POST https://api.owl3d.com/v1/jobs/job_.../cancel \
-H "Authorization: Bearer $OWL3D_API_KEY"{"id": "job_...", "status": "cancelled"}