AI 이미지 감지 API
애플리케이션에 TruthScan의 AI 이미지 감지 API를 통합하기 위한 전체 문서입니다.
코드 없이 시도하려면 FastAPI 엔드포인트를 방문하세요: https://detect-image.truthscan.com/docs
인증
TruthScan은 API 접근을 위해 API key를 사용합니다. API key는 개발자 포털 페이지 상단에서 확인할 수 있습니다.
TruthScan은 API key를 다음과 같은 JSON 본문에 포함해 서버로 보내기를 기대합니다(엔드포인트가 헤더 전용 인증만 문서화한 경우, 예: check-user-credits는 예외):
{
"key": "YOUR API KEY GOES HERE"
}YOUR API KEY GOES HERE를 개인 API key로 반드시 바꾸세요.
Rate Limits
API는 각 API key에 대해 분당 요청 예산을 적용합니다. 쓰기(write) 엔드포인트는 읽기(read) 엔드포인트보다 비용이 큽니다. 기본 한도는 분당 60회이며, 더 높은 한도가 필요하면 문의해 주세요.
엔드포인트 가중치
각 호출은 분당 예산에서 가중치만큼 차감됩니다:
| 엔드포인트 | 유형 | 가중치 |
|---|---|---|
| POST /detect | 쓰기 | 1 |
| POST /bulk-upload | 쓰기 | 1 |
| GET /get-presigned-url | 읽기 | 0.2 |
| GET /check-user-credits | 읽기 | 0.2 |
| POST /heatmap/{id} | 읽기 | 0.2 |
| POST /preview/{id} | 읽기 | 0.2 |
| POST /query | 읽기 | 제한 없음 |
| GET /health | 읽기 | 제한 없음 |
예: 분당 60 예산이면 쓰기 60회, 읽기 약 300회, 또는 가중치 합계가 분당 ≤ 60이 되는 어떤 조합이든 보낼 수 있습니다.
제한 응답 (HTTP 429)
분당 예산을 초과하면 API는 다음을 반환합니다:
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 3
X-RateLimit-Retry-After: 3
Content-Type: application/json
{
"error": "Too many requests"
}Rate limit 응답 헤더
- X-RateLimit-Limit — 분당 용량.
- X-RateLimit-Remaining — 이 요청 이후 현재 분의 남은 호출 수.
- X-RateLimit-Reset — (429일 때만) 다음 쓰기 요청을 보낼 수 있을 때까지의 초.
- X-RateLimit-Retry-After — (429일 때만) X-RateLimit-Reset과 동일 값을 Retry-After 형식으로 제공.
권장 클라이언트 동작
- 성공 응답의 X-RateLimit-Remaining을 보며 요청 속도를 조절하세요.
- 429를 받으면 최소 X-RateLimit-Retry-After 초 동안 대기 후 재시도하세요. 지수 백오프 + jitter 사용을 권장합니다.
- 배치 작업에는 여러 /detect 병렬 호출 대신 POST /bulk-upload(한 번에 최대 50장 처리)를 사용하세요.
AI 이미지 감지기
Detect (3단계 프로세스)
AI 이미지 감지 워크플로는 다음 단계로 구성됩니다:
- Pre-signed 업로드 URL 받기
- 이미지 업로드
- 이미지 감지 요청 제출
1. Pre-signed 업로드 URL 받기
먼저 API에 pre-signed URL을 요청합니다. 이 URL로 이미지 파일을 스토리지 서버에 안전하게 업로드할 수 있습니다.
지원 파일 형식
JPG, JPEG, PNG, WebP, JFIF, HEIC, HEIF, AVIF, BMP, TIFF, TIF, GIF, SVG, PDF
파일명
pre-signed URL을 요청할 때 이미지 파일명에서 공백을 제거하세요.
PDF 파일의 경우 첫 번째 이미지만 감지됩니다(단일 파일 플로우).
일괄 업로드로 ZIP을 제출할 경우 이 엔드포인트에서 .zip 파일명을 사용하세요.
Query parameters
- file_name (필수) — 원본 파일명; 서버가 정규화할 수 있습니다(공백 및 안전하지 않은 문자 조정). 일괄 업로드에는 .zip 확장자를 사용하세요.
- expiration (선택) — pre-signed URL 유효 시간(초, 기본값: 3600).
GET https://detect-image.truthscan.com/get-presigned-url?file_name=example.jpg요청 예시
curl -X GET 'https://detect-image.truthscan.com/get-presigned-url?file_name=example.jpg' \
--header 'apikey: YOUR API KEY GOES HERE'응답 예시
{
"status": "success",
"presigned_url": "https://nyc3.digitaloceanspaces.com/ai-image-detector-dev/uploads/581d47c7-3ef4-42af-88d9-6dab6bf69389_20250611-121955_example.jpg...",
"file_path": "uploads/example.jpg",
"document_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}document_id는 이 업로드 요청에 대해 새로 생성된 UUID입니다(상관/로깅용). /detect 또는 /bulk-upload에 사용하는 id는 해당 엔드포인트를 제출할 때 부여되며, /detect에 선택적 id를 전달하지 않는 한 presign 단계의 id와 다를 수 있습니다.
2. 이미지 업로드
제공된 presigned_url로 PUT 요청하여 이미지를 업로드합니다. 이미지 형식에 맞게 Content-Type을 설정하세요.
파일명
업로드 시 이미지 파일명에서 공백을 제거하세요.
파일 확장자와 정확히 일치하도록 Content-Type 설정
- image/jpeg: jpg, jpeg, jfif
- image/png: png
- image/webp: webp
- image/heic: heic
- image/heif: heif
- image/avif: avif
- image/bmp: bmp
- image/tiff: tiff, tif
- image/gif: gif
- image/svg+xml: svg
- application/pdf: pdf
흔한 실수
- image/jpg는 잘못된 값입니다. image/jpeg를 사용하세요.
- 파일과 헤더가 맞지 않게 하지 마세요(예: .png 파일에 image/jpeg).
- 헤더를 바꾸면 확장자도 맞추고, 반대도 마찬가지입니다.
- 요청/업로드 시 파일명에 공백을 넣지 마세요.
요청 예시
curl -X PUT 'https://nyc3.digitaloceanspaces.com/ai-image-detector-dev/uploads/581d47c7-3ef4-42af-88d9-6dab6bf69389_20250611-121955_example.jpg...' \
--header 'Content-Type: image/jpeg' \
--header 'x-amz-acl: private' \
--data-binary '@example.jpg'추가 업로드 예시(PNG, PDF, SVG)
curl -X PUT '<PRESIGNED_URL_FOR_example.png>' \
--header 'Content-Type: image/png' \
--header 'x-amz-acl: private' \
--data-binary '@example.png'curl -X PUT '<PRESIGNED_URL_FOR_example.pdf>' \
--header 'Content-Type: application/pdf' \
--header 'x-amz-acl: private' \
--data-binary '@example.pdf'curl -X PUT '<PRESIGNED_URL_FOR_example.svg>' \
--header 'Content-Type: image/svg+xml' \
--header 'x-amz-acl: private' \
--data-binary '@example.svg'파일 크기 제한
- 최소 파일 크기: 1KB
- 최대 파일 크기: 10MB
업로드 과정에서 파일 형식이 일관되게 유지되는지 확인하세요. 성공 시 HTTP 200을 반환합니다.
3. AI 감지를 위해 이미지 제출
업로드 후 이전 단계의 file_path를 참조하여 AI 감지를 요청합니다. PDF 업로드 시 첫 번째 이미지만 분석·감지됩니다.
POST https://detect-image.truthscan.com/detect요청 예시
curl -X 'POST' \
'https://detect-image.truthscan.com/detect' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"key": "YOUR-API-KEY-GOES-HERE",
"url": "https://ai-image-detector-prod.nyc3.digitaloceanspaces.com/<FILE_PATH>",
"generate_preview": true
}'FILE_PATH는 pre-signed URL 단계에서 반환된 경로를 의미합니다(예: uploads/...). 예시처럼 스토리지 호스트로 전체 URL을 구성하세요.
선택 파라미터
id: 선택 UUID 문자열. 생략 시 서버가 새 document id를 생성합니다. 제공 시 이미 존재하면 안 되며, 그렇지 않으면 API가 오류를 반환합니다.generate_preview: true면 이미지 미리보기 URL 생성(기본: true). false면 미리보기 생략.document_type: 문서 유형(기본: Image).email: 처리용 이메일 주소.generate_analysis_details: false면 상세 분석 생성 생략(기본: true).generate_heatmap_overlayed: 히트맵 생성 시 히트맵 이미지 출력 방식(기본: true). true면 원본에 블렌딩한 표준 오버레이, false면 투명 RGBA 히트맵(JET 색상 맵 + 알파)으로 UI에서 합성 가능.generate_heatmap_normalized: false면 활성화 맵에 사용되는 정규화 단계를 생략(기본: true). generate_heatmap_overlayed와 함께 히트맵 외형을 조절합니다.model: 모델 또는 라우팅 힌트(기본: generic). generic, instance_id/model(예: my-instance-id/generic) 등. 잘못된 instance_id는 400으로 거부됩니다.user_agent: 문서에 저장되는 선택 문자열(분석/지원용).
응답 예시
{
"id": "77565038-9e3d-4e6a-8c80-e20785be5ee9",
"status": "pending"
}응답에는 감지 상태 추적용 고유 이미지 ID가 포함됩니다.
감지 상태 및 결과 조회
상태 확인과 결과를 가져오려면 이미지 ID로 /query 엔드포인트를 사용하세요.
인증: 요청 본문에는 id만 포함되며 이 호출에는 API key를 보내지 않습니다. UUID를 아는 누구나 결과를 폴링할 수 있으므로, 점수 공개를 제한하려면 document ID를 민감 정보로 취급하세요.
POST https://detect-image.truthscan.com/query요청 예시
curl -X 'POST' \
'https://detect-image.truthscan.com/query' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"id": "IMAGE-ID-GOES-HERE"
}'응답 예시
{
"id": "00fee5ff-a55b-42fb-b7c7-d14f05ae0769",
"status": "done",
"result": 90.2371538185235,
"result_details": {
"is_valid": true,
"detection_step": 3,
"final_result": "AI Generated",
"metadata": [
"No Information Detected for Real/AI",
"Could not find anything from ExifTool and Pillow metadata"
],
"metadata_basic_source": "null",
"ocr": [
"OCR did not detect AI",
0.0
],
"ml_model": [
"AI Generated",
90.2371538185235
],
"confidence": 90.2371538185235,
"heatmap_status": "ready",
"heatmap_url": "https://ai-image-detector-prod.nyc3.digitaloceanspaces.com/uploads/....",
"analysis_results_status": "pending",
"analysis_results": null,
"warnings": [
{ "type": "blur_dark", "label": "Blurred" },
{ "type": "watermark", "label": "Gemini", "confidence": 0.95 },
{ "type": "screen_recapture", "label": "screen", "metrics": { "is_screen": false }, "confidence": 99.99 }
]
},
"preview_url": "https://ai-image-detector-prod.nyc3.digitaloceanspaces.com/previews/..."
}응답 예시(/query, 조직에 secure URL이 켜진 경우)
{
"id": "00fee5ff-a55b-42fb-b7c7-d14f05ae0769",
"status": "done",
"result": 90.2371538185235,
"result_details": {
"is_valid": true,
"detection_step": 3,
"final_result": "AI Generated",
"confidence": 90.2371538185235,
"heatmap_status": "ready",
"heatmap_url": "https://ai-image-detect.undetectable.ai/heatmap/00fee5ff-a55b-42fb-b7c7-d14f05ae0769",
"analysis_results_status": "ready",
"analysis_results": null
},
"preview_url": "https://ai-image-detect.undetectable.ai/preview/00fee5ff-a55b-42fb-b7c7-d14f05ae0769"
}분석 결과가 준비된 경우의 응답 예시
{
"id": "00fee5ff-a55b-42fb-b7c7-d14f05ae0769",
"status": "done",
"result": 90.2371538185235,
"result_details": {
"heatmap_status": "ready",
"heatmap_url": "https://ai-image-detector-prod.nyc3.digitaloceanspaces.com/uploads/....",
"analysis_results_status": "ready",
"analysis_results": {
"imageTags": ["person", "portrait", "outdoor", "vineyard", "smiling"],
"agreement": "strong",
"confidence": 92,
"keyIndicators": [
"Unnaturally smooth skin texture",
"Consistent lighting anomalies"
],
"detailedReasoning": "The image shows clear signs of AI generation with unnaturally smooth textures and consistent lighting patterns not typical of real photography.",
"visualPatterns": ["Uniform noise pattern typical of diffusion models"],
"recommendations": [
"Cross-reference with original source if available",
"Check for metadata inconsistencies",
"Compare with known AI generation patterns"
]
}
},
"preview_url": "https://ai-image-detector-prod.nyc3.digitaloceanspaces.com/previews/..."
}결과 필드
is_valid: 이미지 파일 유효 여부(true/false).detection_step: 감지가 완료된 단계: 1 = 메타데이터만, 2 = 메타데이터+ocr, 3 = 메타데이터+ocr+ml_model.final_result: Overall determination (예: "AI Generated", "Real", "Digitally Edited", "AI Edited").confidence: 감지 신뢰도 점수.metadata: ExifTool과 Pillow로 추출한 이미지 메타데이터.metadata_basic_source: 특정 모바일 카메라, AI 도구 생성, 사진 편집 소프트웨어 수정 등 출처 힌트(가능한 경우).ocr: 역사적 필드명 ocr 아래 워터마크 감지 결과. 두 요소 배열 [label, score]: label은 감지된 워터마크 클래스(예: "Gemini") 또는 "OCR did not detect AI"; score는 0–100(불확실 시 0). label이 있으면 warnings에 요약됨.ml_model: 머신러닝 모델 결과.warnings: 선택 경고 객체 배열(blur_dark, watermark, screen_recapture 등). 비어 있거나 생략될 수 있음.preview_url: generate_preview가 true일 때 미리보기 URL. 직접 스토리지이거나 secure URL 시 https://<api-host>/preview/<document_id> 형태일 수 있음.heatmap_status: pending, ready, failed. 히트맵 생성은 비동기입니다.heatmap_url: heatmap_status가 ready일 때 히트맵. generate_heatmap_overlayed에 따라 외형이 달라짐. 직접 스토리지 또는 https://<api-host>/heatmap/<document_id>(secure 시 POST /heatmap/{id}와 key 사용).analysis_results_status: pending, ready, skipped, failed, analyzing. generate_analysis_details가 false면 생략 또는 null.analysis_results: 활성화 시 상세 서술 분석; 아래 Analysis Result Explanation 참고.
Analysis Result Explanation
analysis_results가 준비되면 일반적으로 agreement(strong | moderate | weak | disagreement), imageTags(최대 5개 짧은 태그), confidence(0–100), keyIndicators, detailedReasoning, visualPatterns, recommendations를 포함합니다.
참고
- 히트맵 생성은 비동기입니다. heatmap_status와 heatmap_url을 위해 /query를 폴링하세요.
- generate_analysis_details=false가 아니면 상세 분석도 비동기입니다. analysis_results_status와 analysis_results를 폴링하세요.
- Secure URL: 활성화 시 heatmap_url과 preview_url이 API 호스트를 사용할 수 있으며, key로 POST /heatmap/{id}, POST /preview/{id}로 가져오세요(Secure heatmap and preview assets 참고).
- 메인 점수가 준비된 뒤에도 완료 시점까지 /query를 다시 호출해 히트맵과 analysis_results를 받으세요.
히트맵 및 오버레이 동작
heatmap_url의 파일은 /detect(또는 /bulk-upload)의 generate_heatmap_overlayed, generate_heatmap_normalized를 반영합니다: 기본 오버레이(true)는 일반 이미지에 히트맵을 덮은 형태이고, false는 합성용 투명 PNG가 일반적입니다.
예: result ~90.24, final_result AI Generated, detection_step 3이면 메타데이터, OCR, ML 모델까지 전체 파이프라인이 완료된 것입니다.
Analysis Results (비동기 심층 분석)
/detect에서 generate_analysis_details가 true이면 상세 분석은 메인 점수 이후에 완료될 수 있습니다. analysis_results_status가 ready(또는 skipped/failed)가 될 때까지 /query를 폴링하세요.
1. 초기 결과가 분석보다 먼저 준비될 수 있음
핵심 감지(result, final_result, confidence)는 analysis_results_status가 아직 pending인 동안에도 완료될 수 있습니다.
{
"id": "00fee5ff-a55b-42fb-b7c7-d14f05ae0769",
"status": "done",
"result": 90.2371538185235,
"result_details": {
"is_valid": true,
"detection_step": 3,
"final_result": "AI Generated",
"confidence": 90.2371538185235,
"analysis_results_status": "pending",
"analysis_results": null
}
}권장 대응
핵심 필드는 즉시 사용하고, analysis_results가 필요하면 계속 폴링하세요.
2. 폴링 유지
같은 id로 /query를 호출하여 analysis_results_status가 pending에서 바뀔 때까지 기다리세요.
curl -X 'POST' \
'https://detect-image.truthscan.com/query' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"id": "00fee5ff-a55b-42fb-b7c7-d14f05ae0769"
}'3. 분석 완료
analysis_results_status가 ready이면 analysis_results에 agreement, imageTags, confidence, keyIndicators, detailedReasoning, visualPatterns, recommendations가 포함됩니다.
{
"id": "00fee5ff-a55b-42fb-b7c7-d14f05ae0769",
"status": "done",
"result": 90.2371538185235,
"result_details": {
"is_valid": true,
"detection_step": 3,
"final_result": "AI Generated",
"confidence": 90.2371538185235,
"heatmap_status": "ready",
"heatmap_url": "https://ai-image-detector-prod.nyc3.digitaloceanspaces.com/uploads/....",
"analysis_results_status": "done",
"analysis_results": {
"imageTags": [
"person",
"portrait",
"outdoor",
"vineyard",
"smiling"
],
"agreement": "strong",
"confidence": 92,
"keyIndicators": [
"Unnaturally smooth skin texture",
"Consistent lighting anomalies"
],
"detailedReasoning": "The image shows clear signs of AI generation with unnaturally smooth textures and consistent lighting patterns not typical of real photography.",
"visualPatterns": [
"Uniform noise pattern typical of diffusion models"
],
"recommendations": [
"Cross-reference with original source if available",
"Check for metadata inconsistencies",
"Compare with known AI generation patterns"
]
}
},
"preview_url": "https://ai-image-detector-prod.nyc3.digitaloceanspaces.com/previews/..."
}분석을 사용할 수 없을 때
analysis_results_status가 skipped, failed이거나 없거나 generate_analysis_details가 false이면 핵심 감지 결과를 최종으로 취급하세요.
{
"status": "done",
"result": 12.5,
"result_details": {
"analysis_results_status": "skipped",
"analysis_results": null
}
}Analysis Results Fields
- analysis_results_status: pending | ready | skipped | failed | analyzing
- analysis_results.agreement: strong | moderate | weak | disagreement
- analysis_results.imageTags: 짧은 설명 태그
- analysis_results.confidence: 0–100
- analysis_results.keyIndicators: 구체적 단서
- analysis_results.detailedReasoning: 짧은 설명
- analysis_results.visualPatterns: 넓은 패턴
- analysis_results.recommendations: 다음 단계
Bulk Upload (ZIP)
ZIP으로 여러 이미지를 한 번에 제출합니다. 단일 이미지와 동일한 흐름: presign(ZIP 이름) → PUT ZIP → POST /bulk-upload → /query 폴링.
1. Pre-signed 업로드 URL 받기 (ZIP)
get-presigned-url에 .zip 파일명(예: images.zip)으로 요청합니다.
GET https://detect-image.truthscan.com/get-presigned-url?file_name=images.zip요청 예시
curl -X GET 'https://detect-image.truthscan.com/get-presigned-url?file_name=images.zip' \
--header 'apikey: YOUR API KEY GOES HERE'2. ZIP 업로드
presigned URL로 PUT하며 Content-Type: application/zip.
curl -X PUT '<PRESIGNED_URL_FOR_images.zip>' \
--header 'Content-Type: application/zip' \
--header 'x-amz-acl: private' \
--data-binary '@images.zip'ZIP 제한
- ZIP 최대 크기: 100MB
- 일괄당 최대 이미지 수: 50
- 이미지당: 최소 1KB, 최대 10MB
ZIP 내부 지원 형식
JPG, JPEG, PNG, WebP, JFIF, HEIC, HEIF, AVIF, BMP, TIFF, TIF, GIF, SVG
ZIP 내부 PDF는 지원하지 않으며 건너뜁니다.
SVG는 감지 전 PNG로 변환됩니다.
3. ZIP 일괄 감지 제출
POST /bulk-upload에 key와 업로드된 ZIP 경로를 가리키는 url을 전달합니다.
선택 파라미터
generate_preview: true면 이미지별 미리보기 URL 생성(기본: false).generate_analysis_details: true면 상세 분석 생성(기본: false).generate_heatmap_overlayed: /detect와 동일(오버레이 vs 투명 RGBA 히트맵).generate_heatmap_normalized: /detect와 동일(기본: true).model: 모델 도메인: generic, instance_id/model 형식.
요청 예시
curl -X 'POST' \
'https://detect-image.truthscan.com/bulk-upload' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"key": "YOUR-API-KEY-GOES-HERE",
"url": "https://ai-image-detector-prod.nyc3.digitaloceanspaces.com/<FILE_PATH>",
"generate_preview": false,
"generate_analysis_details": false,
"model": "generic"
}'응답 예시
{
"id": "77565038-9e3d-4e6a-8c80-e20785be5ee9",
"status": "pending",
"expected_count": 12
}id, status pending, expected_count(ZIP에서 분석할 이미지 수)를 반환합니다.
ZIP 일괄 결과 갱신 방식
- 제출 직후 처리 시작 전까지 status는 pending, 이후 analyzing.
- results에 이미지별 항목; 완료 전까지 result와 result_details가 null일 수 있음.
- 히트맵·상세 분석은 result_details 안에서 아직 pending일 수 있음.
- results의 모든 이미지가 끝나면 전체 status는 done. 배치 실패 시 failed.
- ZIP 완료 전에도 /query로 부분 결과를 볼 수 있음.
4. Bulk Upload 결과 조회
POST /query에 /bulk-upload에서 받은 id. 단일 이미지와 동일 엔드포인트; id가 단일인지 ZIP 배치인지에 따라 응답 형태가 달라집니다.
curl -X 'POST' \
'https://detect-image.truthscan.com/query' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"id": "77565038-9e3d-4e6a-8c80-e20785be5ee9"
}'응답 예시(아직 처리 중)
{
"id": "3b81fb24-dd23-40e7-ae95-82f823f44098",
"status": "analyzing",
"results": [
{
"id": "4600c7e5-00ec-469d-9117-ff20e0f1c1fa",
"status": "done",
"result": 44.0006,
"result_details": {},
"filename": "photo1.jpg",
"preview_url": null
},
{
"id": "2f770c89-352a-4d53-b6a3-a2147ca2c0ae",
"status": "pending",
"result": null,
"result_details": null,
"filename": "photo2.jpg",
"preview_url": null
}
],
"skipped": []
}응답 필드 (bulk ZIP)
- id — 일괄 요청 id.
- status — pending, 이후 analyzing, done 또는 failed.
- results — 분석 중인 이미지별 항목(id, status, result, result_details, filename, preview_url 등).
- skipped — 분석하지 않은 파일(지원하지 않는 형식, 크기 등)로 status failed와 result_details에 사유.
과금: 성공적으로 분석된 이미지에만 크레딧이 사용됩니다. SVG 변환 실패·건너뛴 파일은 과금되지 않습니다.
Secure heatmap and preview assets
/query의 heatmap_url 또는 preview_url이 객체 스토리지가 아닌 API 호스트를 가리키면, POST와 key로 바이트를 가져옵니다.
POST /heatmap/{id}
POST /preview/{id}
Request body JSON: { "key": "YOUR-API-KEY-GOES-HERE" }
Heatmap 응답(HTTP 상태 및 Content-Type 확인)
- 200 + binary (image/png 등) — 히트맵 파일 사용 가능. X-Heatmap-Status 설정 가능.
- 202 + JSON — heatmap_status pending; /query 폴링 후 재시도.
- 200 + JSON — 제공할 히트맵 없음(선택 기능, 실패 등); 서버 오류 아님.
- 500 + JSON — 저장된 heatmap_url은 있으나 스토리지에서 다운로드 실패; 나중에 재시도.
- 404 + JSON — document id 없음.
- 403 + JSON — API key가 해당 문서 소유가 아님.
Preview: POST /preview/{id}는 원시 미리보기 바이트를 반환합니다. 미리보기가 없으면(generate_preview false) JSON과 함께 404.
예시
curl -X POST 'https://detect-image.truthscan.com/heatmap/00fee5ff-a55b-42fb-b7c7-d14f05ae0769' \
-H 'Content-Type: application/json' \
-d '{"key":"YOUR-API-KEY-GOES-HERE"}' \
--output heatmap.pngcurl -X POST 'https://detect-image.truthscan.com/preview/00fee5ff-a55b-42fb-b7c7-d14f05ae0769' \
-H 'Content-Type: application/json' \
-d '{"key":"YOUR-API-KEY-GOES-HERE"}' \
--output preview.png내부: 조직 사용량 Stripe 동기화 (job secret)
신뢰할 수 있는 백엔드 작업 전용이며 일반 API 고객용이 아닙니다. 헤더 x-job-secret이 서버 JOB_SECRET과 일치해야 합니다. 지정 기간 TruthScan 조직 사용량을 Stripe에 미터링 동기화합니다.
POST /organizations/{org_id}/usage/sync-to-stripe
Headers: x-job-secret: <JOB_SECRET>
Body JSON: start_date, end_date, Stripe 미터 idempotency용 선택 idempotency_id.
success, organization_id, total_documents, value_sent_to_stripe, report_date, message 반환. 조직이 미터링이 아니거나 stripe_customer_id 필요 시 없으면 400; 비밀 401; 조직 없음 404; Stripe/설정 오류 500.
사용자 크레딧 확인
이 엔드포인트는 헤더로 사용자 apikey를 받아 크레딧 정보를 반환합니다.
GET https://detect-image.truthscan.com/check-user-credits요청 예시
curl -X 'GET' \
'https://detect-image.truthscan.com/check-user-credits' \
-H 'apikey: YOUR API KEY GOES HERE' \
-H 'accept: application/json' \
-H 'Content-Type: application/json'응답 예시
{
"baseCredits": 10000,
"boostCredits": 1000,
"credits": 11000
}외부 연동에서는 credits 필드만 채워집니다.
헬스 체크
API 서버의 상태를 확인합니다.
GET https://detect-image.truthscan.com/health요청 예시
curl -X 'GET' \
'https://detect-image.truthscan.com/health' \
-H 'accept: application/json'응답 예시
{
"status": "healthy"
}"healthy" 응답은 서비스가 정상 동작 중임을 의미합니다.
오류
대부분의 오류는 API로 잘못된 파라미터를 보냈을 때 발생합니다. 각 호출을 다시 확인하고 제공된 예시를 참고하세요.
사용하는 일반 오류 코드는 REST 표준을 따릅니다:
| 오류 코드 | 의미 |
|---|---|
| 400 | Bad Request — 요청이 유효하지 않습니다. |
| 401 | Unauthorized — 잘못된 job secret(내부 사용 엔드포인트) 또는 유사 인증 실패. |
| 403 | Forbidden — API key가 유효하지 않거나 접근이 거부되었거나 작업에 필요한 크레딧이 부족합니다. |
| 404 | Not Found — 지정한 리소스가 없습니다. |
| 405 | Method Not Allowed — 허용되지 않은 메서드로 리소스에 접근했습니다. |
| 406 | Not Acceptable — JSON이 아닌 형식을 요청했습니다. |
| 410 | Gone — 이 엔드포인트의 리소스가 제거되었습니다. |
| 422 | Invalid Request Body — 요청 본문 형식이 잘못되었거나 유효하지 않거나 필수 파라미터가 누락되었습니다. |
| 429 | Too Many Requests — API key별 rate limit을 초과했습니다(Rate Limits 참조). 본문은 {"error":"Too many requests"}이며, X-RateLimit-Retry-After 헤더가 재시도까지 대기할 초를 알려줍니다. |
| 500 | Internal Server Error — 서버 문제가 발생했습니다. 나중에 다시 시도하세요. |
| 503 | Service Unavailable — 유지보수로 일시 중단되었습니다. 나중에 다시 시도하세요. |
일반적인 문제와 해결
인증 문제
"User verification failed" (403)
원인: 유효하지 않거나 만료된 API key
해결:
- API key가 정확한지 확인
- 계정에서 API key가 활성인지 확인
- API key 재발급 시도
"Not enough credits" (403)
원인: 이미지 처리에 필요한 크레딧 부족
해결:
- /check-user-credits로 남은 크레딧 확인
- 필요 시 추가 크레딧 구매
입력 검증 문제
"Input URL cannot be empty" (400)
원인: 빈 URL 또는 유효하지 않은 URL 제출
해결:
- url 입력이 비어 있지 않은지 확인
- 이미지 이름의 앞뒤 공백 제거
- URL 인코딩이 올바른지 확인
"Input email is empty" (400)
원인: URL 처리에 필요한 이메일 누락
해결:
- URL 제출 시 유효한 이메일 주소 제공
- 이메일 형식 확인
"Unsupported image type" (400)
원인: 지원하지 않는 파일 형식
해결:
- 지원 형식으로 변환(JPG, PNG, WebP, HEIC, HEIF, AVIF, BMP, TIFF, GIF, SVG, PDF)
- 파일 확장자가 올바른지 확인
"File size is too small" (400)
원인: 이미지가 최소 크기 미만
해결:
- 더 큰 이미지 사용(최소 1KB)
- 업로드 중 손상 여부 확인
"File size exceeds limit" (400)
원인: 이미지가 최대 크기 초과
해결:
- 압축 또는 리사이즈(API 오류 메시지에 MB 단위 제한이 표시됨)
- 다른 이미지 형식 사용
"Invalid file type" (400)
원인: 파일 유형 검증 실패
해결:
- 유효한 이미지 형식인지 확인
- 파일이 손상되지 않았는지 확인
- MIME 타입이 확장자와 일치하는지 확인
처리 문제
이미지 상태 "failed"
원인: 다양한 이유로 처리 실패
해결:
- URL이 지원 형식인지 확인
- 이미지 파일이 유효하고 손상되지 않았는지 확인
- 크기 요건 충족 여부 확인
- 문제가 지속되면 지원팀에 문의
"User not found"
원인: 유효하지 않은 사용자 ID
해결:
- 사용자 ID가 올바른지 확인
- 계정이 활성인지 확인
- 필요 시 재인증
"File metadata could not be fetched" (500)
원인: 업로드된 파일에 접근할 수 없음
해결:
- 파일이 성공적으로 업로드되었는지 확인
- 파일 URL에 접근 가능한지 확인
- 파일을 다시 업로드 시도
업로드 문제
"Image upload failed" (403/400)
원인: 유효하지 않거나 만료된 pre-signed URL, 또는 스토리지 서버 문제
해결:
- pre-signed URL을 받은 직후 사용
- Content-Type이 파일 형식과 일치하는지 확인
- 업로드 전 파일명에서 공백 제거
- 필요 시 새 pre-signed URL 발급
"Invalid pre-signed URL" (400)
원인: 공백이 있는 파일명 또는 만료/손상된 pre-signed URL
해결:
- pre-signed URL 요청 전 파일명에서 공백 제거
- 영문자, 숫자, 하이픈, 밑줄 사용
- 필요 시 새 pre-signed URL 발급
일괄 업로드 문제
"URL must point to a ZIP file" (400)
원인: /bulk-upload에 전달한 URL이 ZIP을 가리키지 않음
해결:
- get-presigned-url?file_name=images.zip(또는 다른 .zip 이름) 사용
- 유효한 ZIP을 presigned URL에 업로드
- bulk-upload 요청의 url이 해당 업로드 ZIP을 가리키는지 확인
"ZIP file too large" (400)
원인: ZIP이 최대 크기(100MB) 초과
해결:
- 이미지 수를 줄이거나 압축
- 여러 번 일괄 업로드로 분할
"Too many files" (400)
원인: ZIP에 유효한 이미지가 50개 초과
해결:
- ZIP당 50장 이하로
- 여러 번 일괄 업로드로 분할
"No valid images found in ZIP" (400)
원인: ZIP의 모든 파일이 건너뛰어짐(지원하지 않는 형식, 너무 작음, 잘못된 경로 등)
해결:
- 지원 형식 사용(JPG, PNG, WebP, HEIC, HEIF, AVIF, BMP, TIFF, TIF, GIF, SVG)
- 일괄 업로드에서는 PDF 미지원
- 각 이미지 최소 1KB, 최대 10MB
- 숨김 파일(이름이 .) 및 경로 조작(..) 피하기
"Document is not a bulk upload (image-zip) result" (400)
원인: id가 해당 업로드 유형과 맞지 않음(단일 이미지 vs ZIP 배치)
해결:
- 단일 이미지 제출에는 /detect의 id 사용
- ZIP 제출에는 /bulk-upload의 id 사용
API 자주 묻는 질문
TruthScan AI 이미지 감지 API에 대한 가장 흔한 질문과 답변입니다.