Skip to content

API 문서 (한국어)

개요

기본 URL: https://face-api.xylolabs.com

주요 콘텐츠 타입: - 이미지 업로드 엔드포인트: multipart/form-data - 관리자/인증 엔드포인트: application/json - 공개 /api/v1/mask 엔드포인트: 바이너리 이미지 응답

인증

공개 엔드포인트

  • POST /api/v1/detect
  • POST /api/v1/mask

이 엔드포인트들은 FACE_API_API_KEY_ENABLED=true일 때 X-API-Key 헤더가 필요합니다. 기본값은 true입니다.

X-API-Key: xyl_your_api_key_here

관리자 콘솔 / 관리자 API

관리자 인증 방식: - 브라우저 관리자 콘솔: 쿠키 기반 관리자 세션 - 직접 관리자 API를 호출하는 클라이언트: HTTP Basic 인증

브라우저 관리자 세션 엔드포인트: - POST /api/v1/admin/auth/login - GET /api/v1/admin/auth/session - POST /api/v1/admin/auth/logout

Authorization: Basic base64(username:password)

요청 제한

  • POST /api/v1/detect: 기본 300/minute
  • POST /api/v1/mask: 기본 150/minute
  • 관리자 로그인: 기본 10/minute

세션 기본값

  • 관리자 세션 TTL 기본값: 43200초 (12시간)
  • 관리자 로그인 요청 제한 기본값: 10/minute

오류 형식

{ "detail": "message" }

엔드포인트

GET /health

인증: 없음

서비스 상태와 모델 정보를 반환합니다. 모델과 필요한 DB/스토리지 의존성이 준비된 경우에만 200을 반환하고, 그렇지 않으면 503을 반환합니다.

  • 요청 형식: 없음
  • 응답 형식: JSON (HealthResponse)
curl https://face-api.xylolabs.com/health
import requests

response = requests.get("https://face-api.xylolabs.com/health")
print(response.json())
const response = await fetch("https://face-api.xylolabs.com/health");
console.log(await response.json());
using var client = new HttpClient();
var response = await client.GetAsync("https://face-api.xylolabs.com/health");
Console.WriteLine(await response.Content.ReadAsStringAsync());

POST /api/v1/detect

인증: API 키

얼굴을 감지하고 JSON을 반환합니다.

  • 요청 형식: multipart/form-data
  • 응답 형식: JSON (DetectResponse)

쿼리 파라미터

이름 타입 기본값 설명
confidence float 0.5 최소 신뢰도
nms_threshold float 0.4 NMS IoU 임계값
max_faces int 0 0이면 제한 없음

예시

curl -X POST "https://face-api.xylolabs.com/api/v1/detect?confidence=0.6&max_faces=5" \
  -H "X-API-Key: xyl_your_api_key_here" \
  -F "image=@photo.jpg"
import requests

response = requests.post(
    "https://face-api.xylolabs.com/api/v1/detect?confidence=0.6&max_faces=5",
    headers={"X-API-Key": "xyl_your_api_key_here"},
    files={"image": open("photo.jpg", "rb")},
)
print(response.json())
const formData = new FormData();
formData.append("image", fileInput.files[0]);

const response = await fetch("https://face-api.xylolabs.com/api/v1/detect?confidence=0.6&max_faces=5", {
  method: "POST",
  headers: { "X-API-Key": "xyl_your_api_key_here" },
  body: formData,
});
console.log(await response.json());
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "xyl_your_api_key_here");

using var content = new MultipartFormDataContent();
content.Add(new ByteArrayContent(File.ReadAllBytes("photo.jpg")), "image", "photo.jpg");

var response = await client.PostAsync(
    "https://face-api.xylolabs.com/api/v1/detect?confidence=0.6&max_faces=5",
    content
);
Console.WriteLine(await response.Content.ReadAsStringAsync());

응답 구성

  • request_id: 요청 UUID
  • image: 입력 이미지 정보
  • detections[]: bbox, 랜드마크, 크기, 면적, 중심, 상대 위치
  • summary: 얼굴 수와 신뢰도 요약
  • processing: 모델/임계값/핵심 처리 시간
  • profiling: 상세 타이밍 정보

POST /api/v1/mask

인증: API 키

얼굴을 감지하고 마스킹한 뒤, 처리된 이미지를 바이너리로 반환합니다.

  • 요청 형식: multipart/form-data
  • 응답 형식: 바이너리 이미지 (image/jpeg, image/png, image/webp)

쿼리 파라미터

이름 타입 기본값 설명
confidence float 0.5 최소 신뢰도
nms_threshold float 0.4 NMS IoU 임계값
max_faces int 0 0이면 제한 없음
method enum gaussian gaussian, pixelate, solid, elliptical
strength int 199 블러/픽셀화 강도
padding float 0.15 마스킹 전 bbox 확장 비율
format enum jpeg jpeg, png, webp
quality int 95 출력 품질

예시

curl -X POST "https://face-api.xylolabs.com/api/v1/mask?method=pixelate&strength=32&format=webp" \
  -H "X-API-Key: xyl_your_api_key_here" \
  -F "image=@photo.jpg" \
  -o masked.webp
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "xyl_your_api_key_here");

using var content = new MultipartFormDataContent();
content.Add(new ByteArrayContent(File.ReadAllBytes("photo.jpg")), "image", "photo.jpg");

var response = await client.PostAsync(
    "https://face-api.xylolabs.com/api/v1/mask?method=pixelate&strength=32&format=webp",
    content
);
await using var output = File.Create("masked.webp");
await response.Content.CopyToAsync(output);
import requests

response = requests.post(
    "https://face-api.xylolabs.com/api/v1/mask?method=pixelate&strength=32&format=webp",
    headers={"X-API-Key": "xyl_your_api_key_here"},
    files={"image": open("photo.jpg", "rb")},
)
with open("masked.webp", "wb") as f:
    f.write(response.content)
const formData = new FormData();
formData.append("image", fileInput.files[0]);

const response = await fetch("https://face-api.xylolabs.com/api/v1/mask?method=pixelate&strength=32&format=webp", {
  method: "POST",
  headers: { "X-API-Key": "xyl_your_api_key_here" },
  body: formData,
});
const blob = await response.blob();

응답

바이너리 이미지와 함께 아래 메타데이터 헤더를 반환합니다. - X-Request-Id - X-Face-Count - X-Inference-Ms - X-Mask-Ms - X-Encode-Ms - X-Total-Ms - X-Model - 저장 기능이 켜져 있으면 X-Image-Id, X-Job-Id


관리자 인증/세션 엔드포인트

POST /api/v1/admin/auth/login

인증: 없음

쿠키 기반 관리자 세션을 발급합니다.

  • 요청 형식: JSON
  • 응답 형식: 빈 바디 (204 No Content) + Set-Cookie
{ "username": "admin", "password": "secret" }
curl -X POST https://face-api.xylolabs.com/api/v1/admin/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"secret"}' \
  -c cookies.txt -i
import requests

session = requests.Session()
response = session.post(
    "https://face-api.xylolabs.com/api/v1/admin/auth/login",
    json={"username": "admin", "password": "secret"},
)
print(response.status_code)
const response = await fetch("https://face-api.xylolabs.com/api/v1/admin/auth/login", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  credentials: "include",
  body: JSON.stringify({ username: "admin", password: "secret" }),
});
console.log(response.status);
using System.Text;

using var client = new HttpClient();
using var content = new StringContent("{\"username\":\"admin\",\"password\":\"secret\"}", Encoding.UTF8, "application/json");
var response = await client.PostAsync("https://face-api.xylolabs.com/api/v1/admin/auth/login", content);
Console.WriteLine(response.StatusCode);

성공 시 204 No ContentSet-Cookie를 반환합니다.

GET /api/v1/admin/auth/session

인증: 쿠키 기반 관리자 세션 또는 HTTP Basic

  • 요청 형식: 없음
  • 응답 형식: JSON (AdminSessionResponse)
curl -u admin:password https://face-api.xylolabs.com/api/v1/admin/auth/session
import requests
from requests.auth import HTTPBasicAuth

response = requests.get(
    "https://face-api.xylolabs.com/api/v1/admin/auth/session",
    auth=HTTPBasicAuth("admin", "password"),
)
print(response.json())
const basic = btoa("admin:password");
const response = await fetch("https://face-api.xylolabs.com/api/v1/admin/auth/session", {
  headers: { Authorization: `Basic ${basic}` },
});
console.log(await response.json());
using System.Net.Http.Headers;
using System.Text;

using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
    "Basic",
    Convert.ToBase64String(Encoding.ASCII.GetBytes("admin:password"))
);
var response = await client.GetAsync("https://face-api.xylolabs.com/api/v1/admin/auth/session");
Console.WriteLine(await response.Content.ReadAsStringAsync());
{
  "authenticated": true,
  "username": "admin"
}

POST /api/v1/admin/auth/logout

인증: 없음

쿠키 기반 관리자 세션을 지웁니다. 204를 반환합니다.

  • 요청 형식: 없음
  • 응답 형식: 빈 바디 (204 No Content)
curl -X POST https://face-api.xylolabs.com/api/v1/admin/auth/logout -b cookies.txt -i
import requests

session = requests.Session()
response = session.post("https://face-api.xylolabs.com/api/v1/admin/auth/logout")
print(response.status_code)
const response = await fetch("https://face-api.xylolabs.com/api/v1/admin/auth/logout", {
  method: "POST",
  credentials: "include",
});
console.log(response.status);
using var client = new HttpClient();
var response = await client.PostAsync("https://face-api.xylolabs.com/api/v1/admin/auth/logout", content: null);
Console.WriteLine(response.StatusCode);

관리자 엔드포인트

모든 관리자 엔드포인트는 /api/v1/admin 아래에 있으며, 유효한 쿠키 기반 관리자 세션 또는 HTTP Basic 인증이 필요합니다.

GET /api/v1/admin/stats

이미지/작업 전체 통계를 반환합니다. 스토리지 기반 모드가 필요하며, FACE_API_STORAGE_ENABLED=false이면 501을 반환합니다.

  • 요청 형식: 없음
  • 응답 형식: JSON (StatsResponse)
  • 자세한 예제: 관리자 API

GET /api/v1/admin/images

페이지네이션된 이미지 목록을 반환합니다. 스토리지 기반 모드가 필요하며, FACE_API_STORAGE_ENABLED=false이면 501을 반환합니다.

  • 요청 형식: 없음(쿼리 문자열만 사용)

응답 항목에 들어가는 정보: - original_url (비공개 원본 다운로드 URL) - processed_url (있다면 가장 최근 처리 결과) - 크기, 용량, 작업 수, 생성 시각

아직 처리 결과가 없으면 processed_url 값은 null입니다. FACE_API_S3_PUBLIC_ENDPOINT가 설정되어 있으면 processed_url은 공개 처리 자산 호스트를 가리킬 수 있습니다.

  • 응답 형식: JSON (PaginatedResponse[StoredImageResponse])
  • 자세한 예제: 관리자 API

GET /api/v1/admin/images/{image_id}

이미지 상세 + 관련 작업 목록을 반환합니다.

  • 요청 형식: 없음
  • 응답 형식: JSON (StoredImageDetailResponse)
  • 자세한 예제: 관리자 API

DELETE /api/v1/admin/images/{image_id}

DB 메타데이터를 지우고 S3 객체 정리를 시도합니다. 정리에 실패하면 cleanup task로 남겨 두고 이후 재시도합니다. 204를 반환합니다.

  • 요청 형식: 없음
  • 응답 형식: 빈 바디 (204 No Content)
  • 자세한 예제: 관리자 API

GET /api/v1/admin/images/{image_id}/download

원본 이미지 URL로 리다이렉트합니다.

  • 요청 형식: 없음
  • 응답 형식: 리다이렉트 (302 Found)
  • 자세한 예제: 관리자 API

GET /api/v1/admin/jobs

작업 목록을 반환합니다. job_type, method로 필터할 수 있습니다. 스토리지 기반 모드가 필요하며, FACE_API_STORAGE_ENABLED=false이면 501을 반환합니다.

  • 요청 형식: 없음(쿼리 문자열만 사용)
  • 응답 형식: JSON (PaginatedResponse[JobResponse])
  • 자세한 예제: 관리자 API

GET /api/v1/admin/jobs/{job_id}

감지 결과와 처리 이미지 URL을 포함한 작업 상세입니다.

  • 요청 형식: 없음
  • 응답 형식: JSON (JobDetailResponse)
  • 자세한 예제: 관리자 API

GET /api/v1/admin/jobs/{job_id}/download

처리 이미지 URL로 리다이렉트합니다.

  • 요청 형식: 없음
  • 응답 형식: 리다이렉트 (302 Found)
  • 자세한 예제: 관리자 API

POST /api/v1/admin/test/mask

관리자 콘솔 테스트 페이지에서 쓰는 관리자 전용 미리보기 엔드포인트입니다.

이 엔드포인트는 공개 /api/v1/mask와 달리 JSON을 반환합니다. 반환 내용: - DetectResponse 계열 필드 전체 - masking - output.image_base64

  • 요청 형식: multipart/form-data
  • 응답 형식: JSON (MaskResponse)
  • 자세한 예제: 관리자 콘솔

POST /api/v1/admin/api-keys

새 API 키를 만듭니다. 데이터베이스 기반 모드가 필요하며, DB 계층이 비활성화되어 있으면 501을 반환합니다.

{ "name": "Production App" }

생성 시점에만 전체 키를 반환합니다.

  • 요청 형식: JSON
  • 응답 형식: JSON (ApiKeyCreatedResponse)
  • 자세한 예제: API 키 관리

GET /api/v1/admin/api-keys

키 메타데이터만 반환합니다. 데이터베이스 기반 모드가 필요하며, DB 계층이 비활성화되어 있으면 501을 반환합니다.

  • 요청 형식: 없음(쿼리 문자열만 사용)

필드 예시: - id - name - key_prefix - key_suffix - key_preview - is_active - request_count - last_used_at - created_at

  • 응답 형식: JSON (PaginatedResponse[ApiKeyResponse])
  • 자세한 예제: API 키 관리

GET /api/v1/admin/api-keys/{key_id}

키 메타데이터만 반환합니다. 데이터베이스 기반 모드가 필요하며, DB 계층이 비활성화되어 있으면 501을 반환합니다.

  • 요청 형식: 없음
  • 응답 형식: JSON (ApiKeyResponse)
  • 자세한 예제: API 키 관리

PATCH /api/v1/admin/api-keys/{key_id}

키 이름을 바꾸거나 활성/비활성을 전환합니다. 데이터베이스 기반 모드가 필요하며, DB 계층이 비활성화되어 있으면 501을 반환합니다.

{ "name": "Renamed App", "is_active": false }
  • 요청 형식: JSON
  • 응답 형식: JSON (ApiKeyResponse)
  • 자세한 예제: API 키 관리

DELETE /api/v1/admin/api-keys/{key_id}

키를 삭제합니다. 데이터베이스 기반 모드가 필요하며, DB 계층이 비활성화되어 있으면 501을 반환합니다. 성공 시 204를 반환합니다.

  • 요청 형식: 없음
  • 응답 형식: 빈 바디 (204 No Content)
  • 자세한 예제: API 키 관리

스키마

DetectResponse

주요 구조:

{
  "request_id": "uuid",
  "image_id": null,
  "job_id": null,
  "image": {
    "width": 1920,
    "height": 1080,
    "channels": 3,
    "size_bytes": 245760
  },
  "detections": [],
  "summary": {
    "face_count": 1,
    "avg_confidence": 0.9876,
    "min_confidence": 0.9876,
    "max_confidence": 0.9876,
    "total_face_area": 39999.84,
    "face_area_ratio": 0.019
  },
  "processing": {
    "model": "scrfd_10g",
    "input_size": [640, 640],
    "confidence_threshold": 0.5,
    "nms_threshold": 0.4,
    "inference_ms": 12.34,
    "total_ms": 18.56
  },
  "profiling": {
    "decode_ms": 3.21,
    "preprocess_ms": 1.05,
    "blob_ms": 0.82,
    "inference_ms": 12.34,
    "postprocess_ms": 0.45,
    "nms_ms": 0.12,
    "mask_ms": null,
    "encode_ms": null,
    "storage_ms": null,
    "total_ms": 18.56,
    "candidates_before_nms": 15,
    "candidates_after_nms": 1,
    "det_scale": 0.333333,
    "input_resolution": "1920x1080",
    "det_resolution": "640x640",
    "input_bytes": 245760,
    "output_bytes": null,
    "input_pixels": 2073600,
    "model_name": "scrfd_10g"
  }
}

관리자 마스크 미리보기 응답

DetectResponse에 아래 필드를 더한 구조입니다.

{
  "masking": {
    "method": "gaussian",
    "strength": 199,
    "padding": 0.15,
    "regions_masked": 1
  },
  "output": {
    "format": "jpeg",
    "quality": 95,
    "size_bytes": 123456,
    "image_base64": "..."
  }
}

PaginatedResponse

{
  "items": [],
  "total": 0,
  "page": 1,
  "per_page": 20,
  "pages": 1
}

감지 모델

모델 설명
scrfd_10g 가장 정확하지만 CPU를 많이 씀
scrfd_2.5g 균형형
scrfd_500m 가장 작고 빠르지만 정확도가 낮음

코드 예제

Python (requests)

import requests

with open("photo.jpg", "rb") as f:
    response = requests.post(
        "https://face-api.xylolabs.com/api/v1/detect?confidence=0.6",
        headers={"X-API-Key": "xyl_your_api_key_here"},
        files={"image": f},
    )

print(response.json()["summary"]["face_count"])

JavaScript (fetch)

const formData = new FormData();
formData.append("image", fileInput.files[0]);

const response = await fetch(
  "https://face-api.xylolabs.com/api/v1/mask?method=gaussian",
  {
    method: "POST",
    headers: { "X-API-Key": "xyl_your_api_key_here" },
    body: formData,
  }
);

const blob = await response.blob();

C# (HttpClient)

using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "xyl_your_api_key_here");

using var detectContent = new MultipartFormDataContent();
detectContent.Add(new ByteArrayContent(File.ReadAllBytes("photo.jpg")), "image", "photo.jpg");
var detectResponse = await client.PostAsync(
    "https://face-api.xylolabs.com/api/v1/detect?confidence=0.6",
    detectContent
);
Console.WriteLine(await detectResponse.Content.ReadAsStringAsync());

using var maskContent = new MultipartFormDataContent();
maskContent.Add(new ByteArrayContent(File.ReadAllBytes("photo.jpg")), "image", "photo.jpg");
var maskResponse = await client.PostAsync(
    "https://face-api.xylolabs.com/api/v1/mask?method=gaussian",
    maskContent
);
await using var output = File.Create("masked.jpg");
await maskResponse.Content.CopyToAsync(output);