업체 시스템이 우리 영상·자막·문항·질의응답을 가져가는 규격입니다. v1 · 2026-09-15 갱신 — 바뀐 점
인증공통 규약질의응답 자료 조회문제은행분류 관리자료 등록게시물 등록영상 등록작업 시키기 완료 알림접근 제어영상 수신 재시도오류바뀐 점
| 기본 주소 | https://api.jaramai.co.kr/api/v1 |
|---|---|
| 경로 | 아래 표기는 모두 이 기본 주소 뒤에 붙습니다 — 예: /api/v1/videos |
| 형식 | 요청·응답 모두 JSON (UTF-8). 자막만 srt·vtt 로도 받습니다. |
| 인증 | X-API-Key 헤더 한 장 |
| 요금 | 조회는 과금하지 않습니다. 부를 때마다 AI 가 도는 /api/v1/ask 와 실제로 처리가 도는 작업(인코딩·자막·문제)만 토큰을 씁니다 — 작업은 끝난 뒤 실측으로 계산하고 실패하면 물리지 않습니다. |
발급받은 키를 헤더에 넣습니다. 키가 없거나 틀리면 401 입니다.
curl -H "X-API-Key: 발급받은키" https://api.jaramai.co.kr/api/v1/categories
이 키(업체)가 어떤 상품을 계약했는지 돌려줍니다. 연동 화면에서 계약 안 한 기능을 미리 가리거나 막을 때 쓰세요 —
실제 차단은 각 기능 호출에서 403 not_licensed 로도 막지만, 미리 알면 "안 되는 버튼"을 누르게 두지 않아도 됩니다.
curl -H "X-API-Key: 발급받은키" https://api.jaramai.co.kr/api/v1/me
{
"client": { "name": "○○학원" },
"features": {
"encode": true, // 동영상 인코딩
"transcribe": true, // 자막 + 요약
"quizgen": false, // 문제 생성 (AI 서비스에 포함)
"tutor": false // AI 서비스 (질의응답·게시물)
},
"quiz_per_video": 10
}
features 의 각 값이 true 면 그 기능을 쓸 수 있습니다. 문제 생성(quizgen)은 AI 서비스(tutor)에 포함되어 둘이 함께 켜지고 함께 꺼집니다.
목록형 조회는 모두 같은 규칙입니다. 처음에는 since 로 시작하고, 그 다음부터는
응답이 준 next_cursor 를 그대로 넣으면 됩니다.
| 파라미터 | 설명 |
|---|---|
| since | 이 시각 이후 것만 (예: 2026-08-01T00:00:00Z) |
| cursor | 지난 응답의 next_cursor. since 보다 우선합니다 |
| limit | 한 번에 받을 개수. 기본 100, 최대 500 |
(시각, 번호) 를 함께 담고 있어 그 구멍을 막습니다.
받은 것이 0건이어도 커서는 돌려드리니 그대로 저장해 두시면 됩니다.
{
"count": 100,
"has_more": true,
"next_cursor": "MjAyNi0wOC0xNiAxMDoxMjozM3wxNDIx",
"videos": [ ... ]
}
count(이번에 받은 개수) · has_more · next_cursor 세 칸은 어느 조회나 같고,
자료가 담기는 칸 이름만 엔드포인트마다 다릅니다.
| 엔드포인트 | 자료가 담기는 칸 |
|---|---|
| /api/v1/videos | videos |
| /api/v1/subtitles | subtitles |
| /api/v1/quiz | questions |
| /api/v1/chat-logs | logs |
| /api/v1/board | posts |
| /api/v1/categories | categories |
업체별로 셉니다 — 조회 분당 60회, 질의응답 분당 30회. 넘기면 429 입니다.
영상 하나를 지정하는 자리({video})에는 우리 번호와 업체 관리번호
어느 쪽을 넣어도 됩니다. 등록하실 때 관리번호를 함께 주시면 그 값으로 조회할 수 있습니다.
질문을 걸 수 있는 분류(과목·강좌) 목록입니다. /api/v1/ask 의 category_id 가 여기서 나옵니다.
분류에 매달린 자료·자막·게시물 세 갈래에서 근거를 찾아 답합니다.
| 본문 | 설명 |
|---|---|
| question | 필수 · 2~2,000자 |
| category_id | 필수 · /api/v1/categories 의 번호 |
| k | 근거 건수(생략 가능) |
curl -X POST https://api.jaramai.co.kr/api/v1/ask \
-H "X-API-Key: 발급받은키" -H "Content-Type: application/json" \
-d '{"question":"주주총회 소집 통지 기한은?","category_id":12}'
{
"found": true,
"answer": "...",
"category": { "id": 12, "name": "상법", "path": "..." },
"sources": [ { "cite": "[자료 3]", "text": "..." } ],
"usage": { "tokens": 1840 }
}
found:false 로 답하고
토큰도 쓰지 않습니다(AI 를 부르지 않으므로). sources[].cite 는 답변 본문의
인용 표시와 문자까지 같으니 그대로 대조하시면 됩니다.
모두 무과금이고, 위의 증분 규칙(since·cursor·limit)을 공통으로 받습니다.
| 엔드포인트 | 주는 것 / 추가 파라미터 |
|---|---|
| GET/api/v1/videos | 영상 목록 · category, status(encoded·subtitled·summarized) |
| GET/api/v1/videos/{video} | 영상 한 건 |
| GET/api/v1/videos/{video}/subtitle | 자막 · format=json(기본)·srt·vtt |
| GET/api/v1/videos/{video}/summary | 강의 요약 |
| GET/api/v1/subtitles | 자막 목록(증분) · category |
| GET/api/v1/quiz | 문항 · video, category — AI 가 생성한 문항을 그대로 드립니다. 승인/반려는 가져가신 뒤 업체에서 하세요. 각 문항에 AI 자체검수 결과(check)를 참고용으로 함께 드립니다 |
| GET/api/v1/chat-logs | 질의 기록 · category, found, origin |
| GET/api/v1/board | 게시물 Q&A · category, answered, q |
| POST/api/v1/board | 게시물 등록 · category, title, question → 게시물 등록 |
403 입니다.
또한 업체 자료만 보입니다 — 남의 분류·영상 번호를 넣으면 404 입니다.
quizgen 이 만든 문항(객관식·OX)을 있는 그대로 드립니다. 승인·반려는 가져가신 뒤
업체에서 하세요 — 우리는 게이트를 두지 않습니다. 다른 조회처럼 무과금이고 증분 규칙
(since·cursor·limit)을 그대로 받습니다.
| 파라미터 | 설명 |
|---|---|
| video | 이 영상 문항만 — 우리 번호나 업체 관리번호(external_key) 어느 쪽이든 |
| category | 이 분류(소분류) 문항만 — /api/v1/categories 의 번호 |
| since·cursor·limit | 증분 조회(공통 규약과 동일) |
curl -H "X-API-Key: 발급받은키" \
"https://api.jaramai.co.kr/api/v1/quiz?video=LEC-1001"
{
"count": 20,
"has_more": false,
"next_cursor": "...",
"questions": [
{
"id": 5500,
"media_id": 3000000056,
"video": { "number": 1, "title": "1강 총칙", "external_key": "LEC-1001" },
"type": "mc",
"question": "다음 중 ... 옳은 것은?",
"options": ["토테미즘", "샤머니즘", "애니미즘", "조상숭배", "다신교"],
"answer": "3",
"explanations": { "basic": "..." },
"source_ms": 128000,
"check": "ok",
"updated_at": "2026-09-08T15:09:59+09:00"
}
]
}
| 문항 칸 | 설명 |
|---|---|
| id | 문항 번호(우리 기준, 고유). 같은 문항이 다시 와도 이 번호로 중복을 걸러 쓰세요 |
| video | 이 문항이 나온 영상 — external_key 로 회차에 매답니다 |
| type | mc(객관식) · ox |
| options | 객관식 보기 배열. OX 문항은 없습니다 |
| answer | 객관식은 보기 번호(1부터) 문자열, OX 는 "O"·"X" |
| explanations | 해설(키·값). 옛 문항은 {"standard":"..."} 하나만 있을 수 있음 |
| source_ms | 강의 안에서 이 문항이 나온 지점(밀리초) — 플레이어에서 그 자리로 보낼 때 |
| check | AI 자체검수 결과(참고용) — ok·flawed·mismatch·split 등. 게이트가 아니라 업체가 우선순위 정할 때 쓰라고 함께 드립니다 |
check 는 그 판단을 돕는 힌트일 뿐입니다.
업체가 자기 칸의 분류를 직접 만들고 고치고 지웁니다. 여기서 만든 분류는
조회용 GET /api/v1/categories 와 콘솔에 바로 나타납니다 —
영상은 이렇게 만든 가장 아래 분류(소)에 매답니다.
parent_id 로 정해집니다. 상위를 주지 않으면 대분류,
대분류를 상위로 주면 중분류, 중분류를 상위로 주면 소분류 — 대 > 중 > 소 3단까지입니다.
소분류 아래로 더 만들려 하면 422 category_too_deep 입니다.
응답의 depth 가 1=대 · 2=중 · 3=소 입니다.
분류 하나를 만듭니다. 계약과 무관하게 모든 업체가 쓸 수 있습니다 — 분류는 상품이 아니라
업체 계정에 딸린 것이라, 인코딩만 계약하셔도 영상을 담을 자리를 만드셔야 하기 때문입니다.
잠그고 싶으시면 접근 제어에서 categories.write 를 끄시면 됩니다.
| 본문 | 설명 |
|---|---|
| name | 필수 · 분류 이름(최대 60자) |
| parent_id | 상위 분류 번호. 생략하면 대분류, 주면 그 아래(중·소)로 만듭니다 — /api/v1/categories 의 번호 |
| field | 분야 표시(선택, 최대 60자). 비우면 상위 분류의 분야를 물려받습니다 |
| active | 사용 여부(true·false). 생략하면 true |
| sort | 정렬 순서(0 이상 정수). 생략하면 0 |
curl -X POST https://api.jaramai.co.kr/api/v1/categories \
-H "X-API-Key: 발급받은키" -H "Content-Type: application/json" \
-d '{"name":"상법", "parent_id":10}'
{
"category": {
"id": 42,
"parent_id": 10,
"depth": 2,
"name": "상법",
"path": "법학 > 상법",
"field": "법학",
"sort": 0,
"active": true
}
}
응답은 201 입니다. 없는 상위 번호이거나 남의 업체 분류를 상위로 주면
— 존재를 숨기기 위해 — 똑같이 404 category_not_found 로 답합니다.
이름·분야·사용여부·정렬을 고칩니다. 부모를 바꾸는 트리 재배치는 받지 않습니다 —
자리를 옮기면 그 아래 가지의 깊이가 어긋나므로, 옮기려면 새로 만드는 편이 안전합니다.
보낸 칸만 반영하고, 없는 번호이거나 업체 분류가 아니면 404 입니다.
| 본문 | 설명 |
|---|---|
| name | 바꿀 이름(선택, 최대 60자) |
| field | 분야(선택) |
| active | 사용 여부(선택) |
| sort | 정렬 순서(선택) |
curl -X PUT https://api.jaramai.co.kr/api/v1/categories/42 \
-H "X-API-Key: 발급받은키" -H "Content-Type: application/json" \
-d '{"name":"상법(개정)", "active":false}'
분류 하나를 지웁니다. 하위 분류·영상·과정이 매달려 있으면 409
category_in_use 로 막고, 무엇이 걸려 있는지 in_use 에
children·videos·courses 개수로 돌려줍니다 — 옮길지 지울지는 부르는 쪽이 정합니다.
curl -X DELETE https://api.jaramai.co.kr/api/v1/categories/42 \
-H "X-API-Key: 발급받은키"
{ "deleted": true, "id": 42 }
// 매달린 것이 있을 때
{ "error": "category_in_use", "message": "...",
"in_use": { "children": 2, "videos": 5, "courses": 0 } }
질의응답(/api/v1/ask)이 근거로 삼는 자료(문서)를 올립니다. 올린 문서는
텍스트를 뽑아 분류에 매달아 임베딩하고, 이후 그 분류(및 하위)로 물어보면 근거로 쓰입니다 —
콘솔 [자료관리]에 올리는 것과 같은 자리에 들어갑니다.
category_id 는 소분류(대 > 중 > 소의 말단)를 권합니다 —
상위(대·중)에 매달면 그 아래 전체에 걸립니다. 텍스트를 뽑을 수 있는 txt·pdf 만
받습니다(스캔 PDF·hwp·이미지·영상은 422).
문서 하나를 올립니다. 파일(file) 또는 본문 텍스트(text) 중 하나는 필수입니다.
파일이면 multipart/form-data 로 보냅니다.
| 본문 | 설명 |
|---|---|
| category_id | 필수. 문서를 매달 분류 번호(소분류 권장) — /api/v1/categories 의 번호 |
| title | 필수 · 자료 제목(최대 200자) |
| file | txt·pdf 파일(최대 200MB). text 없이 보낼 때 필수 |
| text | 직접 입력하는 본문 텍스트. file 없이 보낼 때 필수 |
curl -X POST https://api.jaramai.co.kr/api/v1/documents \
-H "X-API-Key: 발급받은키" \
-F "category_id=42" -F "title=상법 요약" -F "file=@summary.pdf"
{
"ok": true,
"document": {
"id": 21,
"title": "상법 요약",
"category_id": 42,
"filename": "summary.pdf",
"status": "embedding"
}
}
응답은 201 이고, 임베딩은 백그라운드로 진행됩니다(status 는 이후 완료됩니다).
없는 분류이거나 남의 업체 분류면 404 category_not_found,
추출 가능한 텍스트가 없으면 422(extract_failed · too_short · no_content) 입니다.
이 기능은 접근 제어의 documents.write 로 잠글 수 있습니다.
올린 문서 하나를 지웁니다(임베딩 조각도 함께 정리). 자기 업체 자료만 지울 수 있고,
없는 번호이거나 업체 자료가 아니면 404 document_not_found 입니다.
documents.manage 스코프로 잠급니다.
curl -X DELETE https://api.jaramai.co.kr/api/v1/documents/21 \
-H "X-API-Key: 발급받은키"
{ "ok": true, "id": 21 }
업체 게시판의 학습 Q&A(질문 글)을 올립니다. 올린 글은 분류(교수)에 매달아 임베딩되어
콘솔 [게시물관리]에 나타나고, 질의응답(/api/v1/ask)의 근거로도 쓰입니다.
조회는 GET /api/v1/board 입니다.
category 는 소분류(회차) 또는 중분류(교수) 번호를 줍니다 —
소분류를 주면 그 상위 중분류(교수)로 자동 연결됩니다. 그 분류에 교수 연동(external_teacher_id)이
없으면 422 입니다.
게시물(질문 글) 하나를 올립니다. application/json 으로 보냅니다.
| 본문 | 설명 |
|---|---|
| category | 필수. 글을 매달 분류 번호(소분류=회차 권장 · 중분류=교수) — /api/v1/categories 의 번호 |
| title | 필수 · 글 제목(최대 500자) |
| question | 필수 · 질문 내용 |
| answer | 답변(있으면). 없으면 미답변 글로 등록 |
| posted_at | 등록일(YYYY-MM-DD). 생략 시 오늘 |
curl -X POST https://api.jaramai.co.kr/api/v1/board \
-H "X-API-Key: 발급받은키" -H "Content-Type: application/json" \
-d '{"category":42,"title":"상법 질문","question":"주주총회 결의요건이 궁금합니다."}'
{
"ok": true,
"id": 128,
"board_id": 128,
"category": 42,
"external_teacher_id": 7
}
응답은 201 이고, 질문 텍스트는 임베딩되어 콘솔 게시물관리·질의응답 근거로 반영됩니다.
없는 분류이거나 남의 업체 분류면 404 not_found, 그 분류에
교수 연동(external_teacher_id)이 없으면 422 not_linked 입니다.
이 기능은 접근 제어의 board.write 로 잠급니다.
업체 영상을 우리 쪽에 등록합니다. 같은 목록을 다시 보내도 두 벌이 되지 않습니다 —
external_key(업체 관리번호)가 같으면 갱신합니다. 그래서 실패 시 그대로 다시 보내면 됩니다.
curl -X POST https://api.jaramai.co.kr/api/v1/videos \
-H "X-API-Key: 발급받은키" -H "Content-Type: application/json" \
-d '{
"category_id": 12,
"pipeline": ["encode", "transcribe"],
"items": [
{ "external_key": "LEC-1001", "number": 1, "title": "1강 총칙", "url": "https://cdn.example.com/1.mp4" }
]
}'
| 칸 | 설명 |
|---|---|
| category_id | 필수. 영상을 매달 소분류 번호 — /api/v1/categories 의 가장 아래 분류 |
| items[] | 필수. 한 번에 최대 500건. 각 항목은 title(필수) · external_key · number · url 또는 path · duration · thumb_url · published_at |
| pipeline | 등록 직후 자동 진행할 단계 — encode · transcribe · quizgen. 계약한 단계만 반영됩니다. 생략하면 등록만 하고 멈춥니다 |
| presets | 뽑을 화질(최대 3). 생략하면 기본 화질로 뽑습니다 |
| storage_profile_id | 비공개 저장소(FTP·SFTP)에서 path 로 주실 때. 미리 등록해 둔 접근 설정 번호 — 저장소가 한 곳뿐이면 생략하셔도 됩니다 |
응답은 201 이고 added·updated·skipped 와 함께
이번에 보내신 영상만 우리 번호(media_id)와 함께 돌아옵니다 — 이어서 작업을 시킬 때 그 번호를 쓰시면 됩니다.
422 source_unavailable 로 답하고 한 건도 등록하지 않습니다 —
어느 항목이 왜 안 되는지 items[] 에 index·external_key·message 로 담깁니다.
고쳐서 그대로 다시 보내시면 됩니다.path 로 보내시는데 저장소가 여러 곳이면 422 storage_required 에
고를 수 있는 저장소 목록(storages[])이 함께 옵니다.pipeline 을 주셨는데 url·path 가 둘 다 없으면 시작할 것이 없으므로 막습니다.
이미 원본이 붙어 있는 회차의 제목만 고치는 갱신은 그대로 받습니다.pipeline 을 주시면 원본 확보부터 우리가 바로 시작합니다 — 따로 부르실 것이 없습니다.
이미 등록된 영상에 대해 인코딩 · 자막 · 문제 생성을 요청합니다.
등록할 때 pipeline 을 주셨다면 따로 부르지 않아도 자동으로 진행됩니다.
curl -X POST https://api.jaramai.co.kr/api/v1/jobs \
-H "X-API-Key: 발급받은키" -H "Content-Type: application/json" \
-d '{ "type": "encode", "video": "LEC-1001" }'
| 칸 | 설명 |
|---|---|
| type | 필수. encode · transcribe · quizgen (계약한 것만) |
| video | 필수. 우리 번호(media_id) 또는 업체 관리번호(external_key) |
| presets | encode 일 때 뽑을 화질(최대 3). 생략하면 등록할 때 정해진 화질, 그것도 없으면 기본 화질 |
| aspect | encode 일 때 결과물 비율 — 16:9 · 9:16(쇼츠) · 1:1 · 4:3 · 3:4 · 21:9 · 9:21. 생략하면 원본 비율 그대로. «원본 그대로» 화질과는 함께 못 씁니다 |
| fit | aspect 를 줬을 때 앉히기 — letterbox(여백 두기, 기본) · cover(꽉 채우기, 가장자리 잘림) |
| format | encode 일 때 출력 형식 — ["mp4"] · ["hls","dash"] · ["mp4","hls","dash"]. 생략하면 업체 인코더 설정의 기본값(대개 MP4). HLS/DASH 는 outputs[] 에 kind: "package" 로 옵니다 |
202 에 "job": null 로 답합니다 —
거절이 아니라 예약이고, 그 자리에서 원본 확보를 시작해 확보되는 대로 이어서 돕니다.
url·path)가 아예 없으면 기다려도 시작할 것이 없으므로
422 source_missing 로 답합니다 — /api/v1/videos 로 위치를 등록한 뒤 다시 시켜 주세요.
진행 상태를 봅니다. 목록은 증분 규칙을 그대로 따르고 type·status·video 로 좁힐 수 있습니다.
{ "job": { "id": "9f3c…", "type": "encode", "status": "processing", "progress": 40,
"video": { "media_id": 3000000009, "external_key": "LEC-1001", "title": "1강 총칙" },
"created_at": "2026-08-27T10:00:00+09:00", "started_at": "2026-08-27T10:00:12+09:00" } }
status 는 queued · processing · done · failed 넷입니다.
failed 면 error 칸에 이유가 담깁니다. 자막·요약·문항은 자료 조회로 가져가시고,
인코딩 결과물은 아래 outputs 링크로 받습니다.
인코딩 작업이 done 이 되면 작업 조회·영상 조회(/api/v1/videos/{video})·완료 알림에
outputs[] 가 붙습니다. 화질마다 한 줄이고 링크가 둘입니다.
"outputs": [
{ "name": "1080p", "filename": "pj-a52ab741d375.1080p.mp4", "size": 113843400,
"download": "https://api.jaramai.co.kr/api/v1/jobs/9f3c…/output/pj-a52ab741d375.1080p.mp4",
"play_url": "https://api.jaramai.co.kr/api/v1/jobs/9f3c…/output/pj-a52ab741d375.1080p.mp4?expires=1791966518&sig=1f3e…",
"expires_at": "2026-10-14T17:28:38+09:00" },
{ "name": "HLS/DASH", "kind": "package", "filename": "pj-a52ab741d375", "size": 11771811, "formats": ["hls", "dash"], "files": 8,
"hls_url": "https://api.jaramai.co.kr/api/v1/jobs/9f3c…/stream/1791966518/47484abe…/playlist.m3u8",
"dash_url": "https://api.jaramai.co.kr/api/v1/jobs/9f3c…/stream/1791966518/47484abe…/playlist.mpd",
"expires_at": "2026-10-14T17:28:38+09:00" }
]
| 링크 | 쓰임 |
|---|---|
| download | 서버끼리. X-API-Key 를 붙여 받습니다 |
| play_url | 브라우저 플레이어용. 서명이 붙어 있어 키 없이 열립니다 — <video src> 에 그대로 꽂으세요.
Range 를 받으므로 구간 탐색(seek)이 됩니다. 30일 뒤 만료되며, 작업이나 영상을 다시 조회하면 새 주소를 드립니다 |
| kind: "package" | HLS/DASH 스트리밍 묶음 — 출력 형식에 HLS·DASH 를 켠 업체에만 한 줄 붙습니다(파일이 아니라 폴더라 download 가 없습니다).
hls_url(.m3u8)·dash_url(.mpd)을 플레이어에 꽂으면 조각(segment)은 같은 주소 아래에서 알아서 가져갑니다 — 서명이 경로에 들어 있어 조각마다 열쇠가 필요 없습니다.
HLS 는 Safari 가 바로 열고 다른 브라우저는 hls.js, DASH 는 dash.js 를 쓰세요. 결과물 전송(FTP·SFTP·S3)을 쓰시면 관리번호/stream/ 폴더로 같은 구조가 갑니다 |
폴링하지 않으셔도 됩니다. 받을 주소를 알려 주시면 작업이 끝나는 대로 POST 로 알려 드립니다
— 인코딩 · 자막 · 문제 생성 각각 다른 주소로 받을 수 있습니다.
POST (업체가 지정한 주소)
X-Jaram-Event: job.completed ← 또는 job.failed
X-Jaram-Delivery: 1043 ← 전송 번호(재시도해도 같습니다)
X-Jaram-Timestamp: 1756270000
X-Jaram-Signature: sha256=<hex>
{ "event": "job.completed",
"job": { "id": "9f3c…", "type": "transcribe", "status": "done", "progress": 100,
"units": 72.4, "charged": 145, "finished_at": "2026-08-27T10:41:00+09:00",
"result": { … } } }
result 는 작업 종류별 결과입니다 — 인코딩이면 result.outputs[] 에 위의 결과물 링크(download·play_url)가
그대로 들어 있어, 알림을 받는 즉시 화면에서 틀 수 있습니다.
| 항목 | 내용 |
|---|---|
| 서명 검증 | HMAC-SHA256(시크릿, "<X-Jaram-Timestamp>.<본문 그대로>") 가 X-Jaram-Signature 의 sha256= 뒤와 같아야 합니다. 본문을 파싱하기 전 원문 그대로 계산하세요 |
| 중복 처리 | 재시도로 같은 알림이 두 번 갈 수 있습니다. X-Jaram-Delivery 가 같으면 같은 알림이니 한 번만 처리하세요 |
| 우리 재시도 | 2xx 로 답해 주시면 성공입니다. 그 밖이면 1 · 5 · 30 · 120 · 360분 뒤 최대 5회 다시 보냅니다 |
| 다시 보내지 않는 경우 | 주소·본문 문제로 보이는 4xx(400·401·403·404·422 등)에는 재시도하지 않습니다. 고치신 뒤 알려 주시면 저희가 수동으로 다시 보내 드립니다 |
Retry-After | 보내 주시면 그 시각까지 기다립니다(하루를 넘는 값은 무시). 429·503 에 유용합니다 |
키 하나로 다 열려 있는 게 부담스러우시면, 기능별로 잠그고 호출 주소를 좁힐 수 있습니다. 기본값은 미적용이라 아무것도 안 하시면 지금과 똑같이 동작합니다.
curl -X PUT https://api.jaramai.co.kr/api/v1/acl \
-H "X-API-Key: 발급받은키" -H "Content-Type: application/json" \
-d '{
"mode": "on",
"rules": [
{ "scope": "jobs.write", "allow": true, "allowed_ips": ["203.0.113.10", "10.1.0.0/16"] },
{ "scope": "board.read", "allow": false }
]
}'
| mode | 동작 |
|---|---|
| off | 미적용(기본). 검사하지 않습니다 |
| audit | 기록만. 막지 않고 판정만 남깁니다 — 조이기 전에 무엇이 막힐지 먼저 확인하는 자리 |
| on | 규칙을 넣은 기능만 검사합니다. 나머지는 열려 있습니다 |
| strict | 허용한 기능만 부를 수 있습니다(화이트리스트) |
GET /api/v1/acl 은 쓸 수 있는 scopes 전체 목록과 지금 호출하신 주소(your_ip)를 함께 돌려줍니다 —
허용 주소를 채울 때 그 값을 그대로 쓰시면 됩니다.
422 would_lock_out 으로 거절합니다. 그래도 잠기셨다면 담당자에게 알려 주세요 — 저희가 풀어 드립니다.
/api/v1/acl 자체는 이 규칙의 적용을 받지 않습니다 — 잠긴 뒤에도 설정을 되돌릴 수 있어야 하니까요.
업체 시스템에 새 영상이 생겼을 때 알려 주는 자리입니다. 토큰은 수신 경로마다 따로
발급하며, 이 엔드포인트는 X-API-Key 대신 그 토큰으로 신원을 확인합니다.
받은 영상은 계약한 단계(인코딩 → 자막 → 문제)까지 자동으로 진행됩니다.
이 경로는 X-API-Key 를 쓰지 않으므로 오류도 다릅니다.
| HTTP | error | 뜻 / 대처 |
|---|---|---|
404 | unknown_token | 토큰이 없거나 틀림 — 발급받은 수신 주소를 확인하세요 |
403 | source_inactive | 그 수신 경로가 꺼져 있음 — 담당자에게 문의 |
422 | too_many_items | 한 번에 보낼 수 있는 건수(2,000)를 넘음 — 나눠 보내세요 |
연동에서 제일 자주 어긋나는 부분이라 규칙을 못박아 둡니다. 분기는 HTTP 상태와 error 코드로 하세요.
| 받은 응답 | 어떻게 |
|---|---|
429 | 재시도하세요. Retry-After 헤더가 있으면 그 초만큼 기다린 뒤에. 없으면 1분 뒤부터 점점 늘려서 |
500·502·503·504 | 재시도하세요. 우리 쪽 일시 장애입니다 — 1 · 5 · 30분 식으로 간격을 늘리는 것을 권합니다 |
| 연결 실패 · 타임아웃 | 재시도하세요. 쓰기 요청도 안전합니다(아래 참고) |
400·401·403·404·422 | 재시도하지 마세요. 같은 답이 옵니다 — message 를 읽고 고쳐서 보내야 합니다 |
402 insufficient_tokens·429 monthly_cap | 재시도해도 풀리지 않습니다. 충전·한도 조정이 필요합니다 |
POST /api/v1/videos 는 external_key 가 같으면 갱신이고,
POST /api/v1/jobs 는 같은 영상·같은 단계면 이미 만든 작업을 그대로 돌려줍니다 —
중복 등록도, 이중 과금도 생기지 않습니다. 다만 external_key 없이 등록하시면
회차로 판정하므로, 재시도가 걱정되시면 external_key 를 꼭 넣어 주세요.
오류는 두 칸으로 옵니다 — error(분기용 코드)와 message(사람이 읽을 설명).
분기는 HTTP 상태가 아니라 error 로 하세요 — 같은 404 라도 뜻이 다릅니다.
단 하나의 예외가 분당 호출 제한(429)으로, 이때는 error 없이 message 만 옵니다.
{ "error": "subtitle_not_ready", "message": "자막이 아직 준비되지 않았습니다." }
| HTTP | error | 뜻 / 대처 |
|---|---|---|
401 | unauthorized | 키가 없거나 틀림 — X-API-Key 확인 |
403 | inactive | 계약이 활성 상태가 아님 |
403 | not_licensed | 그 자료에 해당하는 상품 미계약 — 계약 범위 확인 |
404 | video_not_found | 없는 영상이거나 업체 영상이 아님 |
404 | category_not_found | 없는 분류이거나 업체 분류가 아님 |
404 | subtitle_not_ready | 실패가 아니라 아직 — 그대로 두고 나중에 다시 부르세요 |
404 | summary_not_ready | 실패가 아니라 아직 — 기다리시면 됩니다 |
404 | summary_failed | 요약을 만들지 못함 — 알려 주시면 다시 만들어 드립니다 |
402 | insufficient_tokens | 토큰 잔액 부족 — 재시도해도 풀리지 않습니다, 충전이 필요합니다 |
422 | bad_cursor | 커서가 깨짐 — 앞선 응답의 next_cursor 를 그대로 보내세요 |
422 | invalid_payload | 파라미터가 틀림 — message 를 그대로 읽으면 됩니다 |
429 | — (없음) | 분당 호출 제한 — 이때만 error 칸이 없고 message 만 옵니다. Retry-After 헤더의 초만큼 기다린 뒤 재시도 |
429 | rate_limit | 토큰 한도 초과 — 한도가 걸린 기간이 지나야 풀립니다 |
429 | monthly_cap | 월 한도 초과 — 재시도해도 풀리지 않습니다, 담당자에게 문의 |
502 | upstream_failed | AI 호출 실패 — 우리 쪽 일시 장애입니다, 잠시 뒤 재시도 |
403 | acl_denied | 접근 설정에서 막힘 — scope 칸에 어떤 기능인지 담깁니다. /api/v1/acl 로 설정 확인 |
404 | job_not_found | 없는 작업이거나 업체 작업이 아님 |
404 | storage_not_found | 없는 저장소 설정 번호(storage_profile_id) |
409 | subtitle_not_ready | 문제 생성을 시켰는데 자막이 아직 없음 — 자막부터 끝난 뒤 다시 요청 |
409 | not_startable | 지금은 시작할 수 없음 — 잔액·계약·동시 처리 한도를 확인하세요 |
422 | category_not_leaf | 영상은 소분류에 매답니다 — 가장 아래 분류를 고르세요 |
422 | category_too_deep | 분류를 소(3단) 아래로 만들려 함 — 대 > 중 > 소 까지만 됩니다 |
409 | category_in_use | 하위 분류·영상·과정이 매달려 삭제 불가 — in_use 의 개수를 비운 뒤 지우세요 |
422 | source_unavailable | 원본이 그 자리에 없음 — items[] 에 항목별 사유가 담깁니다. 한 건도 등록되지 않았습니다 |
422 | storage_required | path 로 보내셨는데 저장소를 고를 수 없음 — storages[] 에서 골라 storage_profile_id 로 지정 |
422 | source_missing | 작업을 시킨 영상에 원본 위치가 없음 — 먼저 url·path 를 등록 |
422 | would_lock_out | 그 접근 설정을 적용하면 스스로 잠깁니다 — 저장하지 않았습니다 |
422 | bad_ip | 허용 주소 형식 오류 — 1.2.3.4 또는 10.0.0.0/8 |
422 | duplicate_scope | 접근 설정에 같은 scope 를 두 번 보냄 |
subtitle_not_ready·summary_not_ready 를 실패로 처리하지 마세요.
아직 만드는 중이라는 뜻입니다. 진행 상태는 /api/v1/subtitles 로 확인하시고,
correction 이 done 이 된 뒤에 본문을 받아 가시면 헛걸음이 없습니다.
문의는 담당자에게 주세요. 이 문서는 실제 서비스 중인 규격과 함께 갱신됩니다.
| 날짜 | 내용 |
|---|---|
| 2026-09-15 |
· 인코딩 결과물 HLS/DASH 스트리밍 묶음 — outputs[] 에 kind: "package"(hls_url·dash_url), 결과물 전송은 관리번호/stream/ 폴더· POST /api/v1/jobs 에 format(mp4·hls·dash) · aspect(결과물 비율) · fit(여백 두기/꽉 채우기) — 생략하면 업체 설정·원본 비율· 결과물 주소( play_url·hls_url)의 호스트는 업체 도메인으로 바꿔 불러도 됩니다(서명은 경로·만료·작업번호에만)
|
| 2026-09-14 | · GET /api/v1/jobs/{id}/output/{filename} — 인코딩 결과물 받기(download·play_url), 작업·영상 조회와 완료 알림에 outputs[] |
| 2026-09-11 | · GET /api/v1/me(내 계약) · POST /api/v1/board(게시물 등록) |
이 문서와 같은 내용의 사본이 한 벌 더 있습니다(아티팩트). 둘 중 어느 쪽을 보셔도 같습니다.