DEEP OCR SaaS API Guide
KDL Document AI — 단순 OCR을 넘어서는 문서 이해의 새로운 표준
시작하기 전에
DEEP OCR SaaS API는 문서 파일을 업로드하면 AI가 문서를 분류하고 키-값 데이터를 자동 추출해주는 API입니다.
모든 요청에는 발급된 API Key가 필요하며, x-api-key 헤더로 전달합니다.
1. OCR Direct API
POST /api/v2/ocr/direct
문서 파일을 업로드하여 OCR 처리를 요청하고 결과를 반환합니다.
템플릿 기반 추출, 페이지 범위 지정, 멀티 페이지 처리, 예약 실행, 수동 검수 생략, 법인인감 매칭 등 다양한 옵션을 지원합니다.
Content-Type: multipart/form-data
인증: x-api-key 헤더 필수
지원 버전: v2 전용
1.1 요청 예시
curl -X POST '<http://agent-api.koreadeep.com/api/v2/ocr/direct>' \
-H 'accept: application/json' \
-H 'x-api-key: kdl_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
-F 'file=@sample.pdf;type=application/pdf' \
-F 'params={
"template_ids": [456],
"advanced_options": {
"multi_pages": { "enabled": false },
"page_range": {
"enabled": true,
"start_page": 1,
"end_page": 14
},
"skip_manual_review": { "enabled": true }
}
}'curl -X POST '<http://agent-api.koreadeep.com/api/v2/ocr/direct>' \
-H 'accept: application/json' \
-H 'x-api-key: kdl_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
-F 'file=@sample.pdf;type=application/pdf' \
-F 'params={
"template_ids": [456],
"advanced_options": {
"multi_pages": { "enabled": false },
"page_range": {
"enabled": true,
"start_page": 1,
"end_page": 14
},
"skip_manual_review": { "enabled": true }
}
}'curl -X POST '<http://agent-api.koreadeep.com/api/v2/ocr/direct>' \
-H 'accept: application/json' \
-H 'x-api-key: kdl_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
-F 'file=@sample.pdf;type=application/pdf' \
-F 'params={
"template_ids": [456],
"advanced_options": {
"multi_pages": { "enabled": false },
"page_range": {
"enabled": true,
"start_page": 1,
"end_page": 14
},
"skip_manual_review": { "enabled": true }
}
}'
1.2 요청 파라미터
HTTP Header
헤더명 | 필수 | 설명 | 예시 |
|---|
x-api-key
| ✓ | SaaS API Key | kdl_xxxxxxxx...
|
accept
|
| 응답 형식 | application/json
|
Form Data
파라미터 | 타입 | 필수 | 설명 |
|---|
file
| UploadFile | ✓ | 분석할 문서 파일 |
params
| JSON string |
| OCR 처리 옵션 (1.3 상세 참조) |
1.3 params 구조
params는 multipart/form-data의 문자열 필드로 JSON 객체를 전달합니다.
{
"template_ids": [456],
"doc_code": null,
"rotate_yn": false,
"review_yn": true,
"advanced_options": {
"multi_pages": { "enabled": false },
"page_range": {
"enabled": true,
"start_page": 1,
"end_page": 14
},
"schedule": {
"enabled": false,
"start_at": null
},
"skip_manual_review": { "enabled": false },
"corporate_seal_match": {
"enabled": false,
"reference_file_id": null
}
}
}{
"template_ids": [456],
"doc_code": null,
"rotate_yn": false,
"review_yn": true,
"advanced_options": {
"multi_pages": { "enabled": false },
"page_range": {
"enabled": true,
"start_page": 1,
"end_page": 14
},
"schedule": {
"enabled": false,
"start_at": null
},
"skip_manual_review": { "enabled": false },
"corporate_seal_match": {
"enabled": false,
"reference_file_id": null
}
}
}{
"template_ids": [456],
"doc_code": null,
"rotate_yn": false,
"review_yn": true,
"advanced_options": {
"multi_pages": { "enabled": false },
"page_range": {
"enabled": true,
"start_page": 1,
"end_page": 14
},
"schedule": {
"enabled": false,
"start_at": null
},
"skip_manual_review": { "enabled": false },
"corporate_seal_match": {
"enabled": false,
"reference_file_id": null
}
}
}params 필드
필드명 | 타입 | 기본값 | 설명 |
|---|
template_ids
| `integer[] | null` | null
|
doc_code
| `string | null` | null
|
rotate_yn
| boolean
| false
| 문서 회전 보정 여부 |
review_yn
| boolean
| true
| 검수 단계 사용 여부 |
advanced_options
| `object | null` | null
|
1.4 advanced_options
1.4.1 multi_pages
여러 페이지를 하나의 문서 단위로 처리합니다.
필드명 | 타입 | 기본값 | 설명 |
|---|
enabled
| boolean
| false
| true이면 전체 페이지를 하나의 단위로 처리. 크레딧 차감 기준 변경: 활성 시 페이지당 1크레딧 / 비활성(기본) 시 5페이지당 1크레딧(올림)
|
multi_pages.enabled=true와 schedule.enabled=true는 동시에 사용할 수 없습니다.
1.4.2 page_range
처리할 페이지 범위를 지정합니다.
필드명 | 타입 | 기본값 | 설명 |
|---|
enabled
| boolean
| false
| 페이지 범위 적용 여부 |
start_page
| `integer | null` | null
|
end_page
| `integer | null` | null
|
제약 조건
start_page, end_page 모두 1 이상
start_page ≤ end_page
변환된 전체 페이지 수를 초과하는 범위 요청 시 400 반환
1.4.3 schedule
처리를 특정 시각에 예약합니다.
필드명 | 타입 | 기본값 | 설명 |
|---|
enabled
| boolean
| false
| 예약 처리 사용 여부 |
start_at
| `string | null` | null
|
제약 조건
ISO 8601 형식 필수 (예: "2026-06-18T10:30:00Z")
예약 시각은 분 단위로 정규화됨 (초·마이크로초 절단)
정규화 후 300초(5분) 초과 과거 시각은 거부 (400)
정규화 후 최대 30일 이내 (400)
multi_pages.enabled=true와 동시 사용 불가
1.4.4 skip_manual_review
필드명 | 타입 | 기본값 | 설명 |
|---|
enabled
| boolean
| false
| true이면 수동 검수 단계를 생략합니다
|
1.4.5 corporate_seal_match
법인인감 매칭 기능을 사용합니다.
필드명 | 타입 | 기본값 | 설명 |
|---|
enabled
| boolean
| false
| 법인인감 매칭 사용 여부 |
reference_file_id
| `integer | null` | null
|
1.5 지원 파일 형식
분류 | 확장자 |
|---|
이미지 | .jpg .jpeg .png .webp .bmp .gif .tif .tiff .heic .svg
|
PDF / 텍스트 | .pdf .txt .csv
|
MS Office | .doc .docx .xls .xlsx .ppt .pptx
|
한글 / ODF | .hwp .hwpx .hwtx .owpml .odt .odf
|
총 25개 확장자 지원. 목록 외 형식 업로드 시 변환 단계에서 502 반환.
1.6 처리 흐름
2. 응답 구조
2.1 성공 응답 (200 OK)
{
"status": "success",
"results": {
"elements": [
{
"page_number": 1,
"doc_code": "KDL-DOC-01",
"rotated": {
"angle": 5.0
},
"key_value_list": [
{
"key": "registration_no",
"value": ["261-53-00182"],
"type": "string",
"confidence_score": 0.98,
"bbox": {
"x1": 0.1,
"y1": 0.2,
"x2": 0.3,
"y2": 0.4
}
}
]
}
],
"metadata": null
},
"metadata": {
"file_info": {
"filename": "sample.pdf",
"content_type": "application/pdf",
"size": 3284879
},
"total_time": 12.345
}
}{
"status": "success",
"results": {
"elements": [
{
"page_number": 1,
"doc_code": "KDL-DOC-01",
"rotated": {
"angle": 5.0
},
"key_value_list": [
{
"key": "registration_no",
"value": ["261-53-00182"],
"type": "string",
"confidence_score": 0.98,
"bbox": {
"x1": 0.1,
"y1": 0.2,
"x2": 0.3,
"y2": 0.4
}
}
]
}
],
"metadata": null
},
"metadata": {
"file_info": {
"filename": "sample.pdf",
"content_type": "application/pdf",
"size": 3284879
},
"total_time": 12.345
}
}{
"status": "success",
"results": {
"elements": [
{
"page_number": 1,
"doc_code": "KDL-DOC-01",
"rotated": {
"angle": 5.0
},
"key_value_list": [
{
"key": "registration_no",
"value": ["261-53-00182"],
"type": "string",
"confidence_score": 0.98,
"bbox": {
"x1": 0.1,
"y1": 0.2,
"x2": 0.3,
"y2": 0.4
}
}
]
}
],
"metadata": null
},
"metadata": {
"file_info": {
"filename": "sample.pdf",
"content_type": "application/pdf",
"size": 3284879
},
"total_time": 12.345
}
}2.2 최상위 필드
필드명 | 타입 | 설명 |
|---|
status
| string
| 처리 상태. 성공 시 "success" |
results
| object
| OCR 결과 데이터 |
metadata
| object
| 파일 정보 및 처리 시간 |
2.3 metadata
필드명 | 타입 | 설명 | 예시 |
|---|
file_info.filename
| string
| 파일명 | "sample.pdf"
|
file_info.content_type
| string
| MIME 타입 | "application/pdf"
|
file_info.size
| integer
| 원본 파일 크기 (bytes) | 3284879
|
total_time
| `number | null` | 총 처리 시간 (초) |
2.4 results.elements
필드명 | 타입 | 필수 | 설명 |
|---|
page_number
| integer
| ✓ | 페이지 번호 (page_range 사용 시 원본 기준) |
doc_code
| `string | null` |
|
rotated
| `object | null` |
|
key_value_list
| `object[] | null` |
|
2.5 key_value_list
필드명 | 타입 | 설명 |
|---|
key
| string
| 추출 키. 중첩 객체는 .으로, 배열 요소는 [1], [2]로 표현 |
value
| array
| 추출 값 목록. 단일 값도 항상 배열 (["홍길동"]) |
type
| `string | null` |
confidence_score
| `number | null` |
bbox
| `object | null` |
2.6 bbox (경계 상자)
필드명 | 설명 |
|---|
x1, y1
| 좌상단 좌표 |
x2, y2
| 우하단 좌표 |
results.metadata는 현재 항상 null입니다. 향후 확장을 위해 예약된 필드이며, 최상위 metadata(파일 정보·처리 시간)와는 다른 필드입니다.
3. 오류 응답
3.1 오류 형식 안내
오류 응답의 detail 형식은 세 가지입니다.
유형 | 형식 | 예시 |
|---|
일반 오류 | 단일 문자열 | { "detail": "No file provided" }
|
options 검증 오류 | Pydantic ValidationError 문자열 | 핵심 메시지가 문자열 안에 embed |
크레딧 오류 | 객체 | { "detail": { "error_code": "...", ... } }
|
3.2 인증 오류
401 — 유효하지 않거나 폐기된 API Key
{ "detail": "Invalid or revoked API key" }{ "detail": "Invalid or revoked API key" }{ "detail": "Invalid or revoked API key" }422 — x-api-key 헤더 누락
{
"detail": [
{ "type": "missing", "loc": ["header", "x-api-key"], "msg": "Field required", "input": null }
]
}{
"detail": [
{ "type": "missing", "loc": ["header", "x-api-key"], "msg": "Field required", "input": null }
]
}{
"detail": [
{ "type": "missing", "loc": ["header", "x-api-key"], "msg": "Field required", "input": null }
]
}3.3 요청 검증 오류 (400)
상황 | detail 메시지 |
|---|
params JSON 파싱 실패 | "Invalid params JSON: ..."
|
params가 JSON 객체가 아님 | "params must be a JSON object"
|
파일 미제공 | "No file provided"
|
빈 파일 | "Empty file provided"
|
page_range가 페이지 수 초과 | "page_range exceeds converted page count"
|
advanced_options 제약 위반 (Pydantic 형식)
케이스 | 핵심 메시지 |
|---|
schedule.enabled=true, start_at 누락
| start_at is required when schedule is enabled
|
schedule.start_at이 5분 초과 과거
| scheduled_at must not be more than 300s in the past after minute-level normalization
|
schedule.start_at이 30일 초과
| scheduled_at must be within 30 days
|
multi_pages와 schedule 동시 사용
| schedule cannot be used with multi_pages
|
page_range.enabled=true, start/end 누락
| start_page and end_page are required when page_range is enabled
|
start_page > end_page
| start_page must be <= end_page
|
corporate_seal_match.enabled=true, reference_file_id 누락
| reference_file_id is required when corporate_seal_match is enabled
|
3.4 크레딧 오류 (400 / 404)
크레딧 차감 기준: 기본 5페이지당 1크레딧(올림) / multi_pages 활성 시 페이지당 1크레딧
크레딧 부족 (400)
{
"detail": {
"error_code": "INSUFFICIENT_CREDIT",
"error_message": "Insufficient credit. Available: 3, Requested: 5",
"available_credit": 3,
"requested_credit": 5
}
}{
"detail": {
"error_code": "INSUFFICIENT_CREDIT",
"error_message": "Insufficient credit. Available: 3, Requested: 5",
"available_credit": 3,
"requested_credit": 5
}
}{
"detail": {
"error_code": "INSUFFICIENT_CREDIT",
"error_message": "Insufficient credit. Available: 3, Requested: 5",
"available_credit": 3,
"requested_credit": 5
}
}종량제 한도 초과 (400)
{
"detail": {
"error_code": "METERED_LIMIT_EXCEEDED",
"error_message": "Metered usage limit exceeded. Available: 0, Requested: 5, Limit: 1000",
"available_credit": 0,
"requested_credit": 5,
"metered_credit_limit": 1000
}
}{
"detail": {
"error_code": "METERED_LIMIT_EXCEEDED",
"error_message": "Metered usage limit exceeded. Available: 0, Requested: 5, Limit: 1000",
"available_credit": 0,
"requested_credit": 5,
"metered_credit_limit": 1000
}
}{
"detail": {
"error_code": "METERED_LIMIT_EXCEEDED",
"error_message": "Metered usage limit exceeded. Available: 0, Requested: 5, Limit: 1000",
"available_credit": 0,
"requested_credit": 5,
"metered_credit_limit": 1000
}
}크레딧 정보 없음 (404)
{ "detail": "Credit not found for user" }{ "detail": "Credit not found for user" }{ "detail": "Credit not found for user" }
3.5 파일 변환 / 형식 오류 (502 / 504)
지원하지 않는 형식이거나 변환 실패 시 502, 변환 타임아웃 시 504로 반환됩니다.
{ "detail": "Unsupported format: zip" }{ "detail": "Unsupported format: zip" }{ "detail": "Unsupported format: zip" }{ "detail": "File conversion timed out" }{ "detail": "File conversion timed out" }{ "detail": "File conversion timed out" }
3.6 OCR 엔진 오류 (5xx)
상태 코드 | 상황 | detail |
|---|
500
| OCR 결과 없음, 변환 이미지 없음 | "No results returned from OCR API"
|
502
| OCR 엔진 호출 실패 | "OCR API error: <원인>"
|
504
| OCR 엔진 타임아웃, 큐 포화 (429/502/503/504) | "DeepFlow queue is full (HTTP 429)"
|
Rate limit: 이 엔드포인트에는 API Key 단위 rate limit이 없습니다. 호출 제어는 (1) 크레딧 쿼터 (400), (2) OCR 엔진 큐 용량 초과 (504)로만 이루어집니다.
3.7 오류 시나리오 요약
상황 | HTTP 코드 |
|---|
x-api-key 헤더 누락
| 422
|
유효하지 않거나 폐기된 API Key | 401
|
파일 미제공·빈 파일, JSON 파싱 실패 | 400
|
advanced_options 제약 위반 | 400
|
page_range 페이지 수 초과 | 400
|
크레딧 부족·종량제 한도 초과 | 400
|
크레딧 정보 없음 | 404
|
지원하지 않는 파일 형식·변환 실패 | 502
|
변환 타임아웃 | 504
|
OCR 엔진 오류 | 502
|
OCR 엔진 일시적 오류·큐 포화 | 504
|
OCR 결과 없음 | 500 / 502
|
KDL DEEP OCR SaaS API v1.0 — 2026-06-18
문의: cs@koreadeep.com