API 공통 사항

Book Print API의 인증, 요청/응답 형식, 페이지네이션, Rate Limiting 등 공통 규칙을 안내합니다.

인증

모든 API 요청에는 Bearer Token 인증이 필요합니다. 파트너 포털에서 발급받은 API Key를 Authorization 헤더에 포함하세요.

API Key는 SB로 시작하는 12자 prefix(SB + 10자 식별자)와 secret.으로 연결된 형식입니다. Sandbox 키와 Live 키가 분리되어 있으므로 환경에 맞는 키를 사용하세요.

보안 주의: API Key는 서버 측에서만 사용하세요. 클라이언트(브라우저, 앱)에 노출하지 마세요.
Authorization header
Authorization: Bearer SB{10자 식별자}.{secret}

예시 (더미):
Authorization: Bearer SBXXXXXXXXXX.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Base URL

환경Base URL용도
Sandboxhttps://api-sandbox.sweetbook.com/v1개발 및 테스트
Livehttps://api.sweetbook.com/v1실제 운영
Sandbox 환경에서는 실제 인쇄/배송이 이루어지지 않으며, Sandbox 충전금이 사용됩니다.

요청 / 응답 형식

대부분의 API 요청은 JSON 형식을 사용합니다. 파일 업로드가 필요한 엔드포인트는 multipart/form-data를 사용합니다.

Content-Type대상 엔드포인트
application/json일반 API (Orders, Webhooks 등)
multipart/form-data파일 업로드 (Cover, Contents, Photos)

응답 필드

성공/실패 모두 공통 shape을 사용합니다. 실패 응답은 6필드 고정(success·errorCode·message·data·errors·fieldErrors)이며 errorCode·errors·fieldErrors항상 존재합니다. errorCode는 HTTP 상태 기반 기본값이 자동 주입되어 빈 문자열이 되지 않으며, errors·fieldErrors는 해당 항목이 없으면 빈 배열([])로 반환됩니다.

필드타입성공실패설명
successbooleanOO요청 성공 여부(성공 true / 실패 false)
errorCodestring-O실패 분기용 기계 판독 식별자. ERR_* 형식. 실패 시 항상 존재
messagestringOOHTTP 상태의 영어 라벨(예: "Success", "Bad Request")
dataobject | nullOO응답 데이터. 실패 시 null이 기본이나 일부 에러는 진단 객체 포함(예: 402 {required, balance, currency})
errorsstring[]-O사용자 표시용 한글 메시지 배열. 실패 시 항상 존재(비어 있으면 [])
fieldErrorsobject[]-O필드 단위 구조화 에러 배열. 실패 시 항상 존재(해당 없으면 [])
클라이언트 분기 권장: 실패 분기는 errorCode(+ 필요 시 fieldErrors[].constraint)로 하세요. 사용자 표시용 한글은 errors[0]을 사용하고, message는 영어 라벨이라 표시 용도가 아닙니다. 메시지 문자열을 파싱해 분기하는 방식은 금지합니다(문구가 바뀔 수 있음). 전체 errorCode 카탈로그는 에러 코드 & 트러블슈팅을 참조하세요.

성공 응답

요청이 성공하면 success: true와 함께 data 필드에 결과가 포함됩니다.

Response
// 성공 응답
{
  "success": true,
  "message": "Success",
  "data": { ... }
}

에러 응답

요청이 실패하면 success: false와 함께 6필드 고정 shape으로 반환됩니다. errorCode항상 존재하며, 단순 에러는 errors 메시지만, 필드 단위 검증 실패는 fieldErrors에 구조화 정보가 포함됩니다.

참고: 도메인 검증(예: 페이지 제약, finalize 전제조건)의 errors·message는 한글로 반환되지만, 요청 본문의 필수 필드가 아예 누락되는 케이스(모델 바인딩 자동 검증)는 영어 라벨(예: "The PostalCode field is required.")로 반환될 수 있습니다. 클라이언트 분기는 errorCodefieldErrors[].constraint로 하세요.

Error response — 404 (단순 에러)
{
  "success": false,
  "errorCode": "ERR_NOT_FOUND",
  "message": "Not Found",
  "data": null,
  "errors": ["책을 찾을 수 없습니다: bk_xxx"],
  "fieldErrors": []
}
Error response — 400 (필드 검증)
{
  "success": false,
  "errorCode": "ERR_VALIDATION_FAILED",
  "message": "Bad Request",
  "data": null,
  "errors": [
    "shipping.address1: The Address1 field is required.",
    "shipping.postalCode: The PostalCode field is required.",
    "shipping.recipientName: The RecipientName field is required.",
    "shipping.recipientPhone: The RecipientPhone field is required."
  ],
  "fieldErrors": [
    { "field": "shipping.address1", "message": "The Address1 field is required.", "constraint": "required" },
    { "field": "shipping.postalCode", "message": "The PostalCode field is required.", "constraint": "required" },
    { "field": "shipping.recipientName", "message": "The RecipientName field is required.", "constraint": "required" },
    { "field": "shipping.recipientPhone", "message": "The RecipientPhone field is required.", "constraint": "required" }
  ]
}

fieldErrors 항목 구조

필드 단위 검증 실패는 fieldErrors 배열의 각 항목이 아래 필드를 가집니다. field·message는 항상 존재하며, 나머지 3개는 해당 맥락에서 값이 있을 때만 포함됩니다(없으면 키 자체가 생략).

필드타입항상 포함설명
fieldstringO에러가 발생한 필드명. 중첩 필드는 점 표기(shipping.recipientPhone)
messagestringO해당 필드의 한글 설명
currentValueany-현재 전달된 값(표시 가능할 때만)
requiredValueany-기대값 또는 허용 범위. 단일 값(예: 24)일 수도 있고 객체(예: {"min": 50, "increment": 2}) 형태일 수도 있음
constraintstring-제약 종류. 클라이언트 분기에 사용. 아래 enum 6종

constraint enum

의미
required필수 필드 누락
min최솟값 미만(숫자) 또는 최소 개수 미만(배열/페이지)
max최댓값 초과(숫자) 또는 최대 개수 초과(배열/페이지)
increment증분 규칙 위반(예: 페이지 수가 지정된 증분 단위의 배수가 아님)
enum허용 목록 밖의 값
pattern정규식 패턴 불일치(형식 오류)
fieldErrors 예시 (5필드)
{
  "field": "pageCount",
  "message": "최소 24 페이지가 필요합니다",
  "currentValue": 10,
  "requiredValue": 24,
  "constraint": "min"
}

페이지네이션

목록 조회 API는 limit/offset 기반 페이지네이션을 사용합니다. 응답 구조는 data.{리소스명} 배열과 data.pagination 객체가 분리된 형태입니다. 리소스명은 엔드포인트에 따라 다릅니다 (books, orders, templates 등).

Query 파라미터

파라미터기본값최대값설명
limit20100한 페이지에 반환할 항목 수
offset0-건너뛸 항목 수

공통 응답 필드

필드타입설명
data.{리소스}array항목 배열. 키 이름은 엔드포인트마다 다름 (books, orders, templates 등)
data.pagination.totalnumber전체 항목 수
data.pagination.limitnumber현재 요청의 limit
data.pagination.offsetnumber현재 요청의 offset
data.pagination.hasNextboolean다음 페이지 존재 여부
list envelope 통일 (2026-05): 모든 list 엔드포인트는 data 자체가 배열로 반환되고, 페이지네이션 메타는 pagination 최상위 형제 필드로 노출됩니다. 이전 패턴(data.books·data.transactions·data.templates·data.photos 등 리소스 키 중첩)은 더 이상 사용되지 않습니다. 단건 GET·단건 액션·통계 리포트는 변경 없습니다.
GET /books — Response (list envelope)
{
  "success": true,
  "message": "성공",
  "data": [ /* ... book 항목들 */ ],
  "pagination": {
    "total": 0,
    "limit": 10,
    "offset": 0,
    "hasNext": false
  }
}
GET /orders — Response (list envelope)
{
  "success": true,
  "message": "성공",
  "data": [ /* ... order 항목들 */ ],
  "pagination": {
    "total": 42,
    "limit": 20,
    "offset": 0,
    "hasNext": true
  }
}
GET /templates — Response (list envelope)
{
  "success": true,
  "message": "성공",
  "data": [ /* ... template 항목들 */ ],
  "pagination": {
    "total": 120,
    "limit": 100,
    "offset": 0,
    "hasNext": true
  }
}

Rate Limiting

정책대상제한기준
auth인증 엔드포인트10 req/minIP 기반
general일반 API300 req/minAPI Key 기반
upload파일 업로드 / Contents200 req/minAPI Key 기반

Rate Limit을 초과하면 429 Too Many Requests 응답이 반환됩니다. 응답의 Retry-After 헤더(초 단위)를 확인한 뒤 재시도하세요. errorCodeERR_TOO_MANY_REQUESTS로 반환됩니다.

Response headers
HTTP/1.1 429 Too Many Requests
Retry-After: 60
Content-Type: application/json
Error response (429)
{
  "success": false,
  "errorCode": "ERR_TOO_MANY_REQUESTS",
  "message": "Too Many Requests",
  "data": null,
  "errors": ["요청 한도를 초과했습니다. Retry-After 헤더 값만큼 대기 후 재시도하세요."],
  "fieldErrors": []
}

멱등성 (Idempotency)

네트워크 오류로 동일한 요청이 중복 실행되는 것을 방지하기 위해 Idempotency-Key 헤더를 지원합니다.Books/Credits/Orders 주요 POST 엔드포인트(POST /books, POST /orders, POST /credits/sandbox/charge 등)에서 사용을 강력히 권장합니다.

동일한 Idempotency-Key + 같은 요청 본문으로 재시도하면 최초 응답이 그대로 재사용됩니다(중복 처리 방지). 동일한 키 + 다른 요청 본문을 보내면 422 Unprocessable Entity + errorCode: "ERR_IDEMPOTENCY_KEY_MISMATCH"가 반환됩니다. 따라서 재시도 시에는 반드시 원본과 동일한 본문을 같은 키로 보내야 합니다.

엔드포인트설명
POST /books책 중복 생성 방지
POST /books/{bookUid}/cover표지 추가 중복 요청 방지
POST /books/{bookUid}/contents내지 추가 중복 요청 방지
POST /books/{bookUid}/finalization최종화 중복 요청 방지
POST /orders충전금 이중 차감 방지
POST /orders/{orderUid}/cancel전체 취소 중복 요청 방지 (환불 이중 처리 방지)
POST /orders/{orderUid}/items/{itemUid}/cancel부분 취소 중복 요청 방지 (환불 이중 처리 방지)
중요: 특히 주문 생성(POST /orders)에는 반드시 Idempotency-Key를 포함하세요. 충전금 이중 차감을 방지합니다.
Request
curl -X POST 'https://api-sandbox.sweetbook.com/v1/orders' \
  -H 'Authorization: Bearer {YOUR_API_KEY}' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: unique-request-id-12345' \
  -d '{ ... }'

주요 HTTP 에러 코드

자주 만나는 HTTP 상태 코드와 기본 errorCode 대응입니다. 상태 코드별 상세 케이스·응답 예시·마이그레이션 가이드는 에러 코드 & 트러블슈팅을 참조하세요.

상태 코드기본 errorCode원인해결 방법
400 Bad RequestERR_VALIDATION_FAILED요청 파라미터 또는 바디 유효성 검증 실패fieldErrors를 확인하여 오류 필드 수정
401 UnauthorizedERR_UNAUTHORIZEDAPI Key 누락 또는 유효하지 않음Authorization 헤더에 올바른 API Key 포함
402 Payment RequiredERR_INSUFFICIENT_CREDIT충전금 잔액 부족datarequired·balance 확인 후 충전금 충전
403 ForbiddenERR_FORBIDDEN접근 권한 없음파트너 포털에서 API Key 상태 및 IP 제한 설정 확인
404 Not FoundERR_NOT_FOUND요청한 리소스가 존재하지 않거나 접근 권한 없음UID 및 파트너 소유권 확인
409 ConflictERR_CONFLICT리소스 상태 충돌(예: 이미 등록된 표지 PDF에 POST 재호출)리소스 현재 상태 확인 후 적절한 메서드 사용
422 Unprocessable EntityERR_IDEMPOTENCY_KEY_MISMATCH동일 Idempotency-Key로 다른 요청 본문 전송동일 키는 원본과 같은 본문으로만 재시도. 본문이 다르면 새 키 사용
429 Too Many RequestsERR_TOO_MANY_REQUESTSRate Limit 초과Retry-After 헤더 값(초) 대기 후 재시도
500 Internal Server ErrorERR_INTERNAL_ERROR서버 내부 오류잠시 후 재시도, 지속 시 support@sweetbook.com 문의
501 Not ImplementedERR_SANDBOX_UNSUPPORTEDSandbox에서 의도적으로 차단된 엔드포인트 호출 (Live 전용)Live 환경에서만 호출. 자동 재시도 화이트리스트에서 제외. 엔드포인트별 환경 호출 가능 여부는 환경 매트릭스 참조

PDF 다운로드(GET /books/{bookUid}/pdf-cover·GET /books/{bookUid}/pdf-contents)는 책의 creationType에 따라 위 일반 에러 외에 5종 추가 errorCode(ERR_PDF_NOT_UPLOADED 404 / ERR_PDF_NOT_GENERATED 409 / ERR_PDF_PENDING 409 / ERR_PDF_GENERATION_FAILED 422 / ERR_PDF_FILE_MISSING 500)로 분기됩니다. 자세한 매트릭스는 Books — PDF 기반 / Books — 템플릿 기반 / 에러 코드 & 트러블슈팅의 PDF 다운로드 섹션을 참조하세요.

날짜 형식

모든 날짜/시간 필드는 ISO 8601 형식(UTC)을 사용합니다. 응답 필드에 따라 밀리초 단위까지 포함될 수 있습니다.

형식예시사용 맥락
초 단위2026-04-22T07:16:39.000Z대부분의 타임스탬프 (createdAt, orderedAt, paidAt 등)
밀리초 포함2026-04-22T01:04:38.104Z주문 생성 등 시각 정밀도가 필요한 필드 (createdAt 일부)