변경이력 (Changelog)

Book Print API의 버전별 변경 내역입니다. 이전 버전의 변경 내역을 통해 API의 변화를 추적할 수 있습니다.

v1.2.3 2026-05-13

BookSpec 사이즈 수치 정정. 응답 필드 자체는 변경 없이 수치값만 변경되었습니다 (Issue #3).

호환성: 응답 shape 변경 없음. 다만 이전 수치 기준으로 캐싱·하드코딩한 클라이언트는 갱신 필요. PDF 생성 측에서도 동시에 새 수치로 전환되었으므로, 신규 PDF는 새 응답값 기준으로 만들면 됩니다.

변경 요약

분류항목이전변경 후
하드커버 (SQUAREBOOK_HC, SQUAREBOOK_LAYFLAT_HC)hingeGapMm (미소)9.510
하드커버spineWidthRules[].spineWidthMm (책등 너비)11 / 1710 / 16
소프트커버 (PHOTOBOOK_A4_SC, PHOTOBOOK_A5_SC)coverThicknessMm (표지 두께)0.41.0
소프트커버pageThicknessMm (페이지 1장당 두께)0.05740.054

※ 도련(bleedMm) / 싸바리 영역(caseWrapMarginMm) / 내지 트림 사이즈(innerTrimWidthMm·innerTrimHeightMm) 등 다른 필드는 변경 없습니다.

영향 받는 API

  • GET /book-specs/{bookSpecUid} / GET /book-specs — 신규 사이즈 필드 값이 위 표대로 변경
  • GET /book-specs/{bookSpecUid}/calculated-size?pages=N — 사이즈 계산 결과가 새 수치 기준으로 산출
  • PDF 업로드 검증 (POST /books/{bookUid}/pdf-cover · POST /books/{bookUid}/pdf-contents) — expected 사이즈가 새 수치 기준으로 자동 계산 (pdfToleranceMm ±1mm 동일)

사이즈 계산 공식 (변경 없음)

공식 자체는 기존과 동일하며 새 수치를 대입하여 계산됩니다. 자세한 계산식과 도식은 PDF 표지/내지 사이즈를, 페이지별 검산 표는 사이즈 계산 API의 검산 예시를 참고하세요.

호환성 / 마이그레이션

  • 응답 shape·필드 추가/제거 없음 — 응답 파싱 코드 변경 불필요
  • 이전 수치 기준의 캐싱·하드코딩이 있는 경우 갱신 필요
  • 이전 수치 기준으로 만든 PDF는 검증 실패할 수 있음 — 새 응답값 기준으로 PDF 재생성 권장

v1.2.2 2026-05-12

AI 에이전트 지원 (3가지 마크다운 산출물 + 9개 페이지 AI 가드 메모) + 신규 판형 SQUAREBOOK_LAYFLAT_HC(레이플랫 제본) + PDF 페이지수 검증 에러 메시지 포맷 명확화. 기존 판형·API 동작은 변경 없습니다.

호환성: 기존 HTML 페이지·SDK 변경 없음. 기존 판형(SQUAREBOOK_HC, PHOTOBOOK_A4_SC, PHOTOBOOK_A5_SC)의 PDF 업로드·응답 동작도 그대로 유지. 신규 판형(SQUAREBOOK_LAYFLAT_HC)을 사용하는 클라이언트만 LAYFLAT 펼침면 PDF 규칙(book.pageCount / 2) 학습 필요.

3가지 마크다운 산출물

산출물URL용도
llms.txt (인덱스)/docs/llms.txt전체 문서의 페이지 목록. ~3 KB / 39개 .md 링크
llms-full.txt (합본)/docs/llms-full.txt모든 페이지 본문을 합친 단일 마크다운. ~470 KB
.md URL (페이지별)/docs/{slug}.md특정 페이지만 마크다운으로. URL 끝에 .md만 붙이면 됨

AI 가드 메모 (9개 페이지)

.md 응답에만 HTML 주석(<!-- AGENT INSTRUCTIONS: ... -->)으로 노출되는 가드 메모. HTML 페이지에는 표시되지 않으며 AI가 자주 추정·실수하는 포인트(예: enum 값, 상태 비교, 메시지 파싱)를 명시적 가이드로 보강합니다.

SSR 전환 (Issue #39)

36개 docs 페이지에서 "use client" 지시문 제거 + usePageTitle 훅을 <PageTitleClient> 컴포넌트로 교체. 본문이 서버 HTML에 직접 포함되어 검색엔진 크롤러·웹 fetch 도구가 본문을 즉시 읽을 수 있습니다. (예외: docs/changelog/page.tsx는 useState 사용으로 client 컴포넌트 유지)

안내 페이지 신규 (3건)

SDKs · Demo Apps 페이지 통합

기존 /docs/sdk + /docs/demo-apps 두 페이지를 /docs/sdks-and-demos 단일 페이지로 통합. 두 옛 URL은 신 URL로 permanent redirect.

신규 판형 — SQUAREBOOK_LAYFLAT_HC (레이플랫 제본)

스퀘어북 레이플랫 하드커버 판형이 추가되었습니다. 본 판형은 플랫폼 최초의 LAYFLAT 제본 상품이며, 기존 PUR 제본과 PDF 업로드 규칙이 다릅니다.

  • 내지 트림 크기 243 × 248 mm, 페이지 범위 16 ~ 46p (2p 단위)
  • 책등 너비: 16~18p = 11mm, 19~46p = 17mm
  • 내지 PDF는 펼침면(spread): 업로드할 PDF 페이지수 = book.pageCount / 2 (표지는 PUR과 동일하게 펼침면 1페이지)

관련 페이지: BookSpecs API — 카탈로그 · PDF 표지/내지 사이즈 — 레이플랫 섹션 · 사이즈 계산 API — 검산 예시 · PDF 업로드 시나리오 — 제본 타입별 PDF 형식.

PDF 페이지수 검증 에러 메시지 포맷 변경

내지 PDF 페이지수 불일치 메시지 라벨이 더 명확하게 변경되었습니다. 메시지 문자열 파싱이 아닌 errorCode(ERR_VALIDATION_FAILED)로 분기하는 클라이언트에는 영향 없습니다.

Before (v1.2.1 이전)
내지 PDF 페이지수 불일치: 실제 10p, 예상 8p
After (v1.2.2, PUR)
내지 PDF 페이지수 불일치: 올바른 페이지수 24p, 업로드된 페이지수 30p
After (v1.2.2, LAYFLAT — 책 페이지 환산값 부가)
내지 PDF 페이지수 불일치: 올바른 페이지수 8p, 업로드된 페이지수 10p (책 페이지 환산: 올바른 페이지수 16p, 업로드된 페이지수 20p)

※ "예상" → "올바른 페이지수" / "실제" → "업로드된 페이지수"로 명확화. LAYFLAT 등 펼침면 PDF는 PDF 페이지 단위와 책 페이지 단위가 다르므로 책 페이지 환산값을 괄호로 부가.

정합성 수정 — SQUAREBOOK_HC 검산 표

사이즈 계산 API 페이지의 SQUAREBOOK_HC 검산 표에서 spineWidthMm 컬럼이 소스와 1mm 어긋나 있던 부분을 정정했습니다 (10 → 11, 16 → 17). 표지 너비 컬럼(coverWidthMm)은 이미 정확했으며, 실제 API 응답값에는 영향이 없는 표 정합성 수정입니다.

호환성 / 마이그레이션

  • 기존 판형(SQUAREBOOK_HC, PHOTOBOOK_A4_SC, PHOTOBOOK_A5_SC)·API 동작 변경 없음 — 클라이언트 코드 수정 불필요
  • 기존 HTML 페이지 URL·라우팅 변경 없음 (SDKs/Demo Apps 옛 URL 제외, 자동 redirect)
  • AI 도구 활용은 선택 — 별도 설정·플러그인 없이 URL fetch만으로 동작
  • 신규 판형 SQUAREBOOK_LAYFLAT_HC: 사용 시 PDF 업로드 흐름 LAYFLAT 차이(펼침면 PDF, 페이지수 환산) 학습 필요
  • PDF 페이지수 불일치 에러 메시지 포맷 변경: errorCode 기반 분기는 영향 없음. 메시지 문자열 파싱 클라이언트는 신규 라벨로 갱신 필요

v1.2.1 2026-05-11

list 응답 envelope을 평탄 구조로 통일. 단건 GET·단건 액션·통계 리포트는 변경 없습니다.

Breaking Change — list 응답 envelope 통일
영향 받는 파트너 공개 엔드포인트의 응답 구조가 평탄화됩니다. 클라이언트 코드에서 data.{리소스명} 접근을 data 직접 접근으로 변경해야 합니다.

envelope 변경

Before (v1.2.0 이전)
{
  "success": true,
  "data": {
    "books": [ /* ... */ ],
    "pagination": { "total": 120, "limit": 20, "offset": 0, "hasNext": true }
  }
}
After (v1.2.1)
{
  "success": true,
  "data": [ /* ... */ ],
  "pagination": { "total": 120, "limit": 20, "offset": 0, "hasNext": true }
}

페이지네이션이 없는 list는 pagination 필드가 응답에 생략됩니다.

영향 받는 파트너 공개 엔드포인트

엔드포인트Before dataAfter
GET /booksbooksdata: []
GET /books/{bookUid}/photosphotos + totalCountdata: [] + pagination.total
GET /templatestemplatesdata: []
GET /credits/transactionstransactionsdata: [] + pagination 신규 추가
GET /webhooks/deliveriesdeliveriesdata: []

변경 안 되는 엔드포인트

  • 단건 GET 전부 (GET /books/{bookUid}, GET /orders/{orderUid} 등)
  • 단건 액션 응답 전부 (POST / PATCH / DELETE)
  • GET /orders — v1.1.0 (C19)에서 이미 평탄화 완료
  • 모든 실패 응답 — v1.2.0 6필드 shape 유지

마이그레이션 가이드

클라이언트 코드의 list 응답 접근을 평탄화 패턴으로 변경합니다.

Before / After (JavaScript)
// Before
const res = await fetch('/v1/books?limit=20');
const { data } = await res.json();
data.books.forEach(book => { /* ... */ });
console.log(data.pagination.total);

// After
const res = await fetch('/v1/books?limit=20');
const json = await res.json();
json.data.forEach(book => { /* ... */ });
console.log(json.pagination.total);

자동 감지 어댑터 (배포 윈도우 대응): 배포 직후 일시적으로 두 패턴이 섞일 수 있다면 Array.isArray(json.data) ? json.data : json.data.books 형태로 양쪽을 모두 처리하는 어댑터를 일시적으로 두고 운영 안정화 후 제거하세요. 모든 list 엔드포인트가 동시에 평탄화되므로 어댑터는 짧은 기간만 필요합니다.

관련 페이지 갱신

v1.2.0 2026-05-07

정보 구조(IA) 재정비와 신규 페이지 추가. API 동작/엔드포인트 변경은 없으며 Breaking Change 없음.

신규 페이지

  • 창작 방식 선택 (/docs/concepts/creation-types) — PDF 업로드 / 템플릿 / 혼합 방식 비교 + 의사결정 가이드
  • 충전금 모델 (/docs/concepts/credit-model) — 환경 분리·차감/환불 규칙·402 잔액 부족 동작 원리
  • 에러 핸들링 권장사항 (/docs/operations/error-handling) — 재시도 가능/불가 분류·Backoff·Idempotency 결합·종합 코드 패턴

페이지 위치 변경

멱등성 페이지가 /docs/concepts/idempotency/docs/operations/idempotency로 이동했습니다. 기존 URL을 북마크/직링크로 사용 중이라면 새 경로로 갱신하세요.

콘텐츠 정정

  • Credits API — 응답 예시·필드를 실제 API 응답과 1:1 재정합 (사실 위반 정정)
  • 충전금 운영 절차 — 운영 절차 중심으로 재정리 + estimate 기반 잔액 검증 코드 패턴

v1.1.0 2026-04-28

Partner API v1.2 릴리스 반영. 에러 응답 6필드 shape 통일, 주문 응답 구조 개편, 책 페이지 메타 객체 도입, Photos API 다운로드, 환경 격리, Sandbox 미지원 정식 등재, 신규 errorCode 14종, 신규 엔드포인트 3개를 포함합니다.

Breaking Change 4건 포함: 기존 클라이언트 코드에 영향이 있는 변경입니다. 항목별 마이그레이션 가이드를 반드시 확인하세요.
  • 주문 응답 구조 변경GET /orders 평탄화 + orderStatus 문자열 enum (이하 C19)
  • 책 페이지 메타 객체 도입pageCount 필드 → pageMeta 객체 이동 (이하 C04)
  • 빈 TEMPLATE 책 finalize 응답 정정500400 ERR_FINALIZE_PREREQ_UNMET (이하 C-7 핫픽스)
  • PDF 다운로드 응답 코드 세분화 — TEMPLATE/MIX 표지 PDF GET이 일괄 404409/422/500 분리 (이하 C02)

C03 — 에러 응답 6필드 shape

모든 실패 응답이 success / errorCode / message / data / errors / fieldErrors 6필드 고정 shape으로 통일됩니다.errorCode·errors·fieldErrors는 항상 존재(빈 배열 보정)하므로 null·undefined 체크가 필요하지 않습니다.

변경내용
errorCode 신규 필드HTTP 상태 기반 기본값 자동 주입(ERR_VALIDATION_FAILED 등) + 도메인 specific 코드 발급(예: ERR_INSUFFICIENT_PAGES)
fieldErrors 5필드 구조field · message · currentValue · requiredValue · constraint. 마지막 셋은 값이 있을 때만 응답에 포함
constraint enum 6종min / max / increment / enum / pattern / required
ProblemDetails 폐지400 ModelBinding도 6필드 shape으로 변환되어 일관 응답

상세는 API 공통 사항 · 에러 코드 & 트러블슈팅 페이지를 참조하세요.

실패 응답 6필드 shape
{
  "success": false,
  "errorCode": "ERR_VALIDATION_FAILED",
  "message": "Bad Request",
  "data": null,
  "errors": ["pageCount: 페이지 수가 부족합니다"],
  "fieldErrors": [
    {
      "field": "pageCount",
      "message": "페이지 수가 부족합니다",
      "currentValue": 22,
      "requiredValue": 24,
      "constraint": "min"
    }
  ]
}

C19 — 주문 응답 구조 (Breaking)

Breaking Change: 기존 data.orders[] 래핑이 data[] 배열로 평탄화되고, orderStatus가 숫자 코드에서 문자열 enum으로 변경됩니다.

1. GET /orders 응답 평탄화

기존 data.orders[] + data.pagination 중첩 구조가 data[] + 최상위 pagination으로 평탄화되었습니다.

2. orderStatus 문자열 enum 12종

기존 숫자 코드(20 / 25 등)에서 문자열 enum("PAID" / "PDF_READY" 등)으로 변경되었습니다.orderStatusDisplay 한글 라벨 필드도 함께 제공됩니다.

3. order.restored 웹훅 신규 추가

취소된 주문이 복원될 때 발송되는 order.restored 이벤트가 추가되어 웹훅 이벤트 카탈로그가 9개로 확장되었습니다.

상세 마이그레이션은 Orders API 페이지의 Breaking Change 안내 박스를 참조하세요.

Before — GET /orders (v1.0)
{
  "success": true,
  "data": {
    "orders": [
      { "orderUid": "or_xxxx", "orderStatus": 20 }
    ],
    "pagination": { "total": 1, "limit": 20, "offset": 0, "hasNext": false }
  }
}
After — GET /orders (v1.1)
{
  "success": true,
  "data": [
    {
      "orderUid": "or_xxxx",
      "orderStatus": "PAID",
      "orderStatusDisplay": "결제완료"
    }
  ],
  "pagination": { "total": 1, "limit": 20, "offset": 0, "hasNext": false }
}

C04 — 책 페이지 메타 객체 (Breaking)

Breaking Change: 책 응답의 단일 pageCount 필드가 pageMeta 객체로 이동했습니다.

POST /books · POST /cover · POST /contents · POST /pdf-cover · POST /pdf-contents · POST /finalization 응답에 공통으로 적용되는 pageMeta 객체가 도입되었습니다.currentPageCount(현재 내지 페이지 수)·pageMin·pageMax·pageIncrement·isValid(페이지 제약 충족 여부) 5필드를 포함합니다.

신규 엔드포인트 — GET /books/{bookUid}

기존 GET /books?bookUid=... 목록 필터 방식 외에, RESTful 단건 조회 엔드포인트가 신설되었습니다. 존재하지 않는 책은 404 ERR_NOT_FOUND로 응답하므로 클라이언트가 명확하게 분기할 수 있습니다.

상세는 Books — PDF 기반 · Books — 템플릿 기반 페이지를 참조하세요.

Before — POST /books 응답 (v1.0)
{
  "success": true,
  "data": {
    "bookUid": "bk_xxxx",
    "pageCount": 0
  }
}
After — POST /books 응답 (v1.1)
{
  "success": true,
  "data": {
    "bookUid": "bk_xxxx",
    "pageMeta": {
      "currentPageCount": 0,
      "pageMin": 24,
      "pageMax": 130,
      "pageIncrement": 2,
      "isValid": false
    }
  }
}

C-7 — finalize 응답 정정 (Breaking) + 전제조건 매핑

Breaking Change (핫픽스): 빈 TEMPLATE 책 finalize 호출 시 응답이 500 ERR_INTERNAL_ERROR에서 400 ERR_FINALIZE_PREREQ_UNMET로 변경되었습니다. 정상 finalize 케이스 영향은 없습니다.

creationType=TEMPLATE 책에 콘텐츠를 추가하지 않은 상태에서 POST /books/{bookUid}/finalization을 호출하면fieldErrors[0].field == "contents" + constraint == "required"로 정확하게 응답합니다. PDF_UPLOAD/MIX와 동일한 패턴으로 정합화되었습니다.

전제조건별 에러코드 매핑 (C20)

finalize 실패 케이스가 errorCode + fieldErrors 매핑으로 명확하게 분기됩니다 — DRAFT 상태 검증, PDF 업로드 검증, 페이지 제약(min/max/increment) 검증.pageMeta.isValid는 페이지 제약만 판정하므로 finalize 가능 여부의 최종 확인은 POST /finalization 호출 결과로만 이루어집니다.

상세는 Books — PDF 기반 · Books — 템플릿 기반의 책 최종화 섹션을 참조하세요.

After — 빈 TEMPLATE finalize (v1.1)
HTTP/1.1 400 Bad Request
{
  "success": false,
  "errorCode": "ERR_FINALIZE_PREREQ_UNMET",
  "message": "Bad Request",
  "data": null,
  "errors": ["contents: 내지 콘텐츠가 최소 1개 이상 필요합니다"],
  "fieldErrors": [
    {
      "field": "contents",
      "message": "내지 콘텐츠가 최소 1개 이상 필요합니다",
      "currentValue": 0,
      "requiredValue": "at_least_one",
      "constraint": "required"
    }
  ]
}

C02 — PDF 다운로드 응답 분기 (Breaking)

Breaking Change (그룹 B만): TEMPLATE 책 표지·내지와 MIX_COVER_TEMPLATE 표지의 PDF GET이 일괄 404에서 pdfStatus에 따라 409·422·500으로 분리됩니다. 그룹 A(PDF_UPLOAD·MIX 내지)는 종전 동작 유지 + errorCode 추가만.

GET /books/{bookUid}/pdf-cover · GET /books/{bookUid}/pdf-contents 응답이 책의 creationType에 따라 두 그룹으로 분기됩니다.

그룹적용 케이스분기 기준
A — 사용자 업로드PDF_UPLOAD 표지·내지 + MIX 내지파일 존재 여부만 검사 → 200 또는 404 ERR_PDF_NOT_UPLOADED
B — 백그라운드 생성TEMPLATE 표지·내지 + MIX 표지책 상태 분기 → 200/409/422/500

신규 errorCode 5종

errorCodeHTTP발생 조건
ERR_PDF_NOT_UPLOADED404그룹 A — 업로드형 PDF 파일 없음
ERR_PDF_NOT_GENERATED409그룹 B — 책 최종화 호출 전
ERR_PDF_PENDING409그룹 B — 백그라운드 생성 진행 중
ERR_PDF_GENERATION_FAILED422그룹 B — 생성 실패(클라이언트 자체 해결 불가)
ERR_PDF_FILE_MISSING500그룹 B — 생성 완료 + 파일 부재(서버 결함)

기존 404 한 가지만 처리하던 클라이언트는 새 코드가 미처리 예외로 빠질 수 있으므로 5종 errorCode 분기 추가를 권장합니다. 상세는 Books — PDF 기반 · Books — 템플릿 기반의 PDF 다운로드 섹션을 참조하세요.

C14 — Photos API 다운로드 + 환경 격리

신규 엔드포인트 — GET /books/{bookUid}/photos/{fileName}

업로드된 사진의 800px 썸네일 바이트를 다운로드하는 엔드포인트가 신설되었습니다. 응답은 저장된 MIME 타입의 바이너리 스트림이며, 인증 헤더가 필요하므로 브라우저 <img src>에 직접 사용할 수 없습니다(백엔드 프록시 권장).

환경 격리 가드 — 403 ERR_ENV_MISMATCH

Photos API 4개 엔드포인트(업로드/목록/다운로드/삭제)에 환경 격리 가드가 일괄 적용됩니다. 호출 도메인(Sandbox/Live)과 책의 환경이 일치하지 않으면 403 ERR_ENV_MISMATCH로 응답합니다.

creationType 차단 — 400 ERR_CREATION_TYPE_UNSUPPORTED

PDF_UPLOAD 타입 책에 Photos API를 호출하면 400 ERR_CREATION_TYPE_UNSUPPORTED로 응답합니다. Photos API는 TEMPLATE·MIX_COVER_TEMPLATE 책에서만 지원됩니다.

상세는 Books — 템플릿 기반의 사진 관련 섹션을 참조하세요.

C01 — 템플릿 파라미터 스키마 조회

신규 엔드포인트 — GET /templates/{templateUid}/schema

템플릿 파라미터 명세를 JSON Schema (draft-07) 형식으로 반환하는 엔드포인트가 신설되었습니다. 기존 상세 조회(GET /templates/{templateUid})의 raw parameters 응답과 별도로, 표준 JSON Schema 검증기·자동화 도구·코드 생성기와 바로 연동할 수 있습니다.

  • 응답 필드: $schema / $id / title / type / properties / required / x-templateKind
  • 5종 binding(text / file / gallery / collageGallery / rowGallery) → JSON Schema 표준 형식으로 변환되며 원본 bindingx-binding 확장 필드로 보존
  • required 판정 정규화: 원본에 명시되지 않은 키는 자동으로 필수에 포함

기존 호출자는 변경 불필요. JSON Schema 형식이 필요한 클라이언트만 새 엔드포인트를 추가로 호출하면 됩니다. 상세는 Templates API의 파라미터 스키마 조회 섹션을 참조하세요.

C09 — 템플릿 외형 썸네일 명문화

GET /templates · GET /templates/{templateUid} 응답의 thumbnails 객체가 정식 미리보기 수단으로 명문화되었습니다. 정적 호스팅·인증 불요·영구 URL·확장자 가변 정책을 따르며, 등록되지 않은 항목은 응답에서 omit됩니다.

  • 썸네일은 사전 등록된 외형 견본이며, 파트너가 입력한 사진의 합성 결과가 아닙니다 — 합성 결과는 책 최종화 후 PDF 다운로드로만 확인 가능합니다.
  • 응답에 키가 존재하면 해당 URL은 항상 유효하며, <img src>에 직접 사용 가능합니다.
  • 코드 변경 없음(이미 운영 중인 필드의 정책 확정).

상세는 Templates API의 상세 조회 섹션을 참조하세요.

C10 — Sandbox 미지원 정식 등재

Sandbox 환경에서 의도적으로 차단된 엔드포인트(외부 결제망 호출 등)에 대해 신규 errorCode ERR_SANDBOX_UNSUPPORTED(HTTP 501)가 도입되었습니다. Live 전용 액션이며 자동 재시도 화이트리스트에서 제외해야 합니다(재시도해도 동일 결과).

엔드포인트별 환경(Sandbox/Live) 호출 가능 여부를 한눈에 확인할 수 있는 환경 매트릭스 페이지가 새로 추가되었습니다. 도메인 판별 규칙, 분류 체계 A/B/C/D, 인증 미들웨어 차이, FAQ 등을 포함합니다.

기타 변경 요약

항목내용
신규 errorCode 14종ERR_INSUFFICIENT_PAGES / ERR_PAGECOUNT_INVALID / ERR_FINALIZE_PREREQ_UNMET / ERR_CREATION_TYPE_UNSUPPORTED / ERR_ENV_MISMATCH / ERR_INSUFFICIENT_CREDIT(402, data에 진단 객체) / ERR_IDEMPOTENCY_KEY_MISMATCH(422) / ERR_TOO_MANY_REQUESTS(429, Retry-After 60초) / ERR_SANDBOX_UNSUPPORTED(501) / ERR_PDF_NOT_UPLOADED / ERR_PDF_NOT_GENERATED / ERR_PDF_PENDING / ERR_PDF_GENERATION_FAILED / ERR_PDF_FILE_MISSING
신규 엔드포인트 3개GET /books/{bookUid} 단건 조회 / GET /templates/{templateUid}/schema / GET /books/{bookUid}/photos/{fileName}
신규 페이지 1개환경 매트릭스 (운영 참고 그룹 최상단)
웹훅 이벤트 9개order.restored 신규 추가 (취소된 주문 복원 시 발송)
Idempotency-Key같은 키 + 다른 본문 시 422 ERR_IDEMPOTENCY_KEY_MISMATCH 반환 (재시도 시 반드시 동일 키 + 동일 본문 사용)

v1.1 → v1.2 클라이언트 마이그레이션 가이드

v1.1 시절에는 에러 분기를 HTTP 상태 코드 또는 errors[0] 문자열로 하는 경우가 있었습니다. v1.2부터는 errorCode 기반 분기로 일관되게 통합하시길 권장합니다.

권장 분기 패턴

TypeScript 기준 예시입니다. errorCode를 기본 축으로 하되, 같은 코드 안에서 세부 제약을 나눠야 할 때는 fieldErrors[].constraint를 조합합니다.

권장 분기 패턴
const res = await api.finalizeBook(bookUid);

if (!res.success) {
  switch (res.errorCode) {
    case "ERR_INSUFFICIENT_PAGES": {
      const f = res.fieldErrors.find(e => e.field === "pageCount");
      showError(`최소 ${f?.requiredValue}페이지 필요 (현재 ${f?.currentValue}p)`);
      break;
    }
    case "ERR_PAGECOUNT_INVALID": {
      const f = res.fieldErrors.find(e => e.field === "pageCount");
      if (f?.constraint === "max") {
        showError(`최대 ${f.requiredValue}페이지까지 가능`);
      } else if (f?.constraint === "increment") {
        // requiredValue는 객체 형태일 수 있음: { min, increment }
        showError("페이지 증분 규칙을 확인하세요");
      }
      break;
    }
    case "ERR_FINALIZE_PREREQ_UNMET": {
      const missing = res.fieldErrors.map(f => f.field);
      if (missing.includes("coverPdf")) askUploadCover();
      if (missing.includes("contentsPdf")) askUploadContents();
      break;
    }
    case "ERR_INSUFFICIENT_CREDIT": {
      // data에 진단 객체 포함
      const { required, balance } = res.data;
      openChargeDialog({ required, balance });
      break;
    }
    case "ERR_IDEMPOTENCY_KEY_MISMATCH":
      showError("요청 본문이 이전과 달라졌습니다. 새 Idempotency-Key로 재시도하세요.");
      break;
    case "ERR_TOO_MANY_REQUESTS":
      // Retry-After 헤더의 초 단위 값 대기
      scheduleRetry(retryAfterSeconds);
      break;
    case "ERR_ENV_MISMATCH":
      showError("호출 도메인을 리소스 환경에 맞춰 재시도 (sandbox ↔ live)");
      break;
    case "ERR_SANDBOX_UNSUPPORTED":
      // Sandbox에서 의도적으로 차단된 액션 — 자동 재시도 금지, Live 환경에서만 가능
      showError("이 기능은 Live(운영) 환경에서만 사용할 수 있습니다.");
      break;
    case "ERR_PDF_NOT_UPLOADED":
      // 그룹 A: 사용자 업로드 PDF가 없음 → 업로드 안내
      askUploadPdf();
      break;
    case "ERR_PDF_NOT_GENERATED":
      // 그룹 B: 책 최종화 호출 전 → finalize 후 재시도
      await finalizeBook();
      break;
    case "ERR_PDF_PENDING":
      // 그룹 B: 백그라운드 생성 진행 중 → 일정 간격 후 재시도(무한 폴링 금지)
      scheduleRetry(10_000); // 예: 10초 후 재시도
      break;
    case "ERR_PDF_GENERATION_FAILED":
      // 그룹 B: pdfStatus=9 (FAILED) — 클라이언트 자체 해결 불가
      showError("PDF 생성에 실패했습니다. 고객지원팀에 문의해 주세요.");
      break;
    case "ERR_PDF_FILE_MISSING":
      // 그룹 B: 서버 결함 — 일반 500과 별개로 PDF 파일 부재 식별
      showError("PDF 파일을 찾을 수 없습니다. 고객지원팀에 문의해 주세요.");
      break;
    case "ERR_UNAUTHORIZED":
      redirectToKeyIssue();
      break;
    case "ERR_NOT_FOUND":
      showError(res.errors[0] ?? "리소스를 찾을 수 없습니다");
      break;
    default:
      // 폴백: 한글 상세 메시지 표시
      showError(res.errors[0] ?? res.message);
  }
}

금지 사항

  • 메시지 문자열 파싱으로 분기하지 말 것. 예: res.errors[0].includes("페이지") 같은 패턴은 금지입니다. 문구는 다국어화·표현 정비로 언제든 변경될 수 있습니다.
  • HTTP 상태만으로 세분 분기하지 말 것. 같은 400도 ERR_INSUFFICIENT_PAGES·ERR_PAGECOUNT_INVALID·ERR_FINALIZE_PREREQ_UNMET·ERR_VALIDATION_FAILED 등으로 세분화됩니다.
  • 응답 shape을 가정하지 말 것. errorCode·errors·fieldErrors는 항상 존재하므로 optional chaining은 불필요하며, 누락 시에는 서버 버그이므로 그대로 노출하지 말고 로깅하세요.

마이그레이션 체크리스트

  • 기존 res.errors[0] 읽기 → 그대로 사용 가능 (shape 유지)
  • res.errorCode 기반 분기 추가 (권장)
  • res.fieldErrors로 폼 UI 하이라이트 구성 (권장)
  • HTTP 상태 코드로만 분기하던 로직은 errorCode로 대체 고려
  • Idempotency 재시도는 동일 키 + 동일 본문으로만 — 본문이 달라지면 새 키 발급
  • 자동 재시도 화이트리스트에서 ERR_SANDBOX_UNSUPPORTED(501) 제외 — 의도적 차단이라 재시도해도 동일 결과

하위 호환성 요약

  • 성공 응답 shape은 변경되지 않았습니다.
  • 기존 필드(success / message / data / errors)는 그대로 유지됩니다.
  • 신규 추가(errorCode, fieldErrors, fieldErrors[].currentValue/requiredValue/constraint)는 필드 추가만 된 것으로 기존 클라이언트가 깨지지 않습니다.
  • errorCode를 아직 쓰지 않는 클라이언트는 계속 errors[0]을 사용자에게 표시하면 동작에 문제없습니다.

v1.0.3 2026-04-08

통합 가이드 전면 재작성, 문서 간 불일치 해소, API 소스코드 최신 변경사항 반영

통합 가이드 재작성

변경내용
사이드바 구조7개 → 11개 메뉴 (표지 추가, 내지 추가, 최종화 분리)
신규 페이지표지 추가, 내지 추가, 최종화 가이드 3개 신설
기존 페이지API 소스코드 검증된 워크플로우 md 기반으로 8개 페이지 전면 재작성
엔드포인트 뱃지모든 엔드포인트에 GET/POST/PUT/PATCH/DELETE 뱃지 추가
다음 단계 안내각 페이지 하단에 워크플로우 연결 링크

문서 정확성 개선

항목내용
내부 정보 제거내부 상태 코드, 클래스명, 소스 파일 참조, 관리자 전용 파라미터 전체 제거
내부 필드 노출 차단BookSpec 9개, Book 5개, Order 18개 내부 필드 — 일반 사용자 응답에서 제거된 API 변경 반영
JWT / print_shop 제거파트너 문서에서 불필요한 JWT 인증, print_shop 계정 타입 참조 제거
API Key 스코프 제거인증 페이지 및 가이드 전체에서 스코프/권한 표기 제거
표현 톤 조정personal 계정 "차단" → "사용 불가"로 변경

문서 간 불일치 해소

항목변경 전변경 후
주문 상태 코드페이지마다 9~11개 불일치전체 11개 코드(20~90) 통일
웹훅 이벤트명order.paid, order.shippedorder.created, shipping.departed 등 8개 통일
웹훅 페이로드camelCase / 구조 불일치snake_case + envelope 구조 통일
X-Webhook-TimestampISO 8601Unix timestamp (초)
배송비3,500원 (일부 페이지)3,000원 통일
포장비500원 (일부 페이지)0원 통일
충전금 잔액 APIGET /credits/balanceGET /credits
402 에러 응답data: null{required, balance, currency}
금액 표기정수 (3000)decimal (3000.00)
파일 형식TIFF 포함 / HEIF 누락TIFF 제거, HEIC/HEIF 포함
자동 변환"모두 JPEG"GIF/WebP→PNG, BMP/HEIC/HEIF→JPG
templateKind2개 (일부 페이지)4개 (cover, content, divider, publish)
용어크레딧충전금

콘텐츠 보강

  • Sandbox/Live 환경 차이 — 판형 조회(가격 차이), 웹훅(환경별 설정 분리) 안내 추가
  • 책 조회 API — 책 생성 가이드에 목록/단건 조회 추가
  • Sandbox 가격 안내 — 주문 생성 가이드에 테스트 가격 안내 추가
  • 페이지 수 규칙 — 계산식에 한글 설명 추가

v1.0.2 2026-04-03

API 문서 정확성 개선 및 Sandbox/Live 환경 전환 UI가 추가되었습니다.

정정 사항

항목변경 전변경 후
배송비3,500원3,000원
포장비500원 × 수량0원 (현재 비활성)
웹훅 이벤트5종 (order.paid 등)8종 (order.created, production.confirmed, shipping.departed 등)
웹훅 서명HMAC 값만sha256= 접두사 추가
API Key 스코프명books:read (복수형)book:read (단수형)
API Key 생성 필드namenote
책 삭제 제약DRAFT 상태만본인 소유 책 상태 무관 삭제 가능
주문 취소cancelReason 선택필수 (최대 500자)
충전금 거래 필드transactionUid, type, descriptiontransactionId, reasonCode+reasonDisplay, memo
Sandbox 충전금 필드descriptionmemo

추가 사항

항목내용
충전금 reason code전체 11종 (1~11) 표기. 7 ORDER_CANCEL_REFUND, 8 ADMIN_CANCEL_REFUND 추가
충전금 잔액 응답accountUid, createdAt, updatedAt 필드 추가
Sandbox 충전금 규칙API Key 환경과 무관하게 항상 test 충전금에 적용
템플릿 파라미터 구조definitions 래퍼, binding 키, $$var$$ 플레이스홀더 구문 설명

UI 개선

  • Sandbox/Live 환경 탭 — 모든 API 요청 코드 예시에 Sandbox/Live URL 전환 탭 추가

v1.0.1 2026-04-02

API 기능 개선 릴리즈입니다. 책 삭제, 크레딧 거래 내역, Sandbox 크레딧 관리 엔드포인트가 신규 추가되었으며, API Key 스코프 시스템, 멱등성 지원, 템플릿 검색 등 여러 기능이 개선되었습니다.

Breaking Change 포함: 책 생성 요청 본문 (POST /books)에서 creationType 필드가 제거되었습니다. 자세한 내용은 아래를 참고하세요.

Breaking Change

1. 책 생성 요청 본문 (POST /books)에서 creationType 제거

책 생성 요청 본문에서 creationType 필드가 제거되었습니다. 해당 필드를 전송하더라도 무시되며,bookSpecUid만으로 책을 생성할 수 있습니다.

Before — POST /books
{
  "bookSpecUid": "spec_abc123",
  "creationType": "TEMPLATE"
}
After — POST /books
{
  "bookSpecUid": "spec_abc123"
}

신규 API

2. 책 삭제 — DELETE /books/{bookUid}

DRAFT 상태인 본인 소유의 책을 삭제할 수 있습니다. 삭제는 소프트 딜리트(soft delete)로 처리됩니다. 이미 주문이 연결된 책이나 타인 소유의 책은 삭제할 수 없습니다.

Request
curl -X DELETE 'https://api-sandbox.sweetbook.com/v1/books/book_abc123' \
  -H 'Authorization: Bearer {YOUR_API_KEY}'
Response (200 OK)
{
  "success": true,
  "message": "책이 삭제되었습니다.",
  "data": null
}

3. 크레딧 거래 내역 조회 — GET /credits/transactions

본인 계정의 크레딧 충전·차감 거래 내역을 조회합니다. 페이지네이션(limit/offset)을 지원합니다.

Request
curl 'https://api-sandbox.sweetbook.com/v1/credits/transactions?limit=20&offset=0' \
  -H 'Authorization: Bearer {YOUR_API_KEY}'
Response (200 OK)
{
  "success": true,
  "message": "Success",
  "data": {
    "total": 3,
    "transactions": [
      {
        "transactionUid": "txn_xyz789",
        "type": "CHARGE",
        "amount": 50000,
        "balanceAfter": 150000,
        "createdAt": "2026-04-01T09:00:00Z"
      }
    ]
  }
}

4. Sandbox 크레딧 충전/차감 — POST /credits/sandbox/charge, POST /credits/sandbox/deduct

Sandbox 환경에서 테스트용 크레딧을 충전하거나 차감할 수 있습니다. Live 환경에서는 동작하지 않습니다.

Sandbox API Key로만 호출 가능합니다. Live API Key로 호출 시 403 Forbidden이 반환됩니다.
충전 — POST /credits/sandbox/charge
curl -X POST 'https://api-sandbox.sweetbook.com/v1/credits/sandbox/charge' \
  -H 'Authorization: Bearer {YOUR_API_KEY}' \
  -H 'Content-Type: application/json' \
  -d '{
  "amount": 10000
}'
차감 — POST /credits/sandbox/deduct
curl -X POST 'https://api-sandbox.sweetbook.com/v1/credits/sandbox/deduct' \
  -H 'Authorization: Bearer {YOUR_API_KEY}' \
  -H 'Content-Type: application/json' \
  -d '{
  "amount": 5000
}'

기능 개선

5. API Key 스코프 시스템

API Key 생성 시 scopes 파라미터로 접근 가능한 엔드포인트 범위를 제한할 수 있습니다. 스코프가 설정된 키로 허용되지 않은 엔드포인트에 접근하면 403 Forbidden이 반환됩니다.

스코프허용 동작
books:read책 목록/상세 조회
books:write책 생성, 수정, 삭제
orders:read주문 목록/상세 조회
orders:write주문 생성, 취소
Before — POST /keys (스코프 없음)
{
  "env": "live"
}
After — POST /keys (스코프 지정)
{
  "env": "live",
  "scopes": ["books:read", "orders:read"]
}
Response — 스코프 부족 시 (403 Forbidden)
{
  "success": false,
  "message": "이 작업을 수행할 권한이 없습니다.",
  "data": null
}

6. 템플릿 목록 정렬/검색 파라미터 추가

GET /templates에 정렬 및 검색 파라미터가 추가되었습니다.

파라미터설명
sortname_asc, name_desc, created_asc, updated_desc, updated_asc
templateName이름 검색 (공백 구분 다중 키워드, AND 조건)
specProfileUid특정 판형 프로필 UID로 필터
theme테마로 필터 (예: minimal)
Before — GET /templates
curl 'https://api.sweetbook.com/v1/templates?limit=20&offset=0' \
  -H 'Authorization: Bearer {YOUR_API_KEY}'
After — 정렬 및 검색 적용
curl 'https://api.sweetbook.com/v1/templates?sort=updated_desc&templateName=일기장&theme=minimal' \
  -H 'Authorization: Bearer {YOUR_API_KEY}'

7. BookSpecs accountUid 자동 적용

GET /book-specs 조회 시 accountUid를 전달하지 않으면 API Key 소유자의 UID가 자동으로 적용됩니다. 커스텀 가격이 설정된 경우 자동으로 반영됩니다. 타인의 accountUid를 전달하면 403 Forbidden이 반환됩니다.

Before — accountUid 직접 전달 필요
curl 'https://api.sweetbook.com/v1/book-specs?accountUid=acc_myuid123' \
  -H 'Authorization: Bearer {YOUR_API_KEY}'
After — accountUid 생략 가능 (자동 적용)
curl 'https://api.sweetbook.com/v1/book-specs' \
  -H 'Authorization: Bearer {YOUR_API_KEY}'

8. 멱등성(Idempotency-Key) 지원 확대

네트워크 재시도 시 중복 처리를 방지하기 위한 Idempotency-Key 헤더 지원이 확대되었습니다. 동일한 키로 재요청하면 최초 응답이 그대로 반환됩니다.

지원 엔드포인트:

  • POST /books
  • POST /orders
  • POST /credits/sandbox/charge
Before — Idempotency-Key 미지원
curl -X POST 'https://api.sweetbook.com/v1/books' \
  -H 'Authorization: Bearer {YOUR_API_KEY}' \
  -H 'Content-Type: application/json' \
  -d '{ "bookSpecUid": "spec_abc123" }'
After — Idempotency-Key 헤더 추가
curl -X POST 'https://api.sweetbook.com/v1/books' \
  -H 'Authorization: Bearer {YOUR_API_KEY}' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000' \
  -d '{ "bookSpecUid": "spec_abc123" }'

9. 콘텐츠 추가 응답에 pageCount 추가

POST /books/{bookUid}/content 응답에 현재까지 추가된 총 페이지 수를 나타내는 pageCount 필드가 포함됩니다.

Before — 콘텐츠 추가 응답
{
  "success": true,
  "message": "Success",
  "data": {
    "bookUid": "book_xyz123",
    "status": "DRAFT"
  }
}
After — pageCount 포함
{
  "success": true,
  "message": "Success",
  "data": {
    "bookUid": "book_xyz123",
    "status": "DRAFT",
    "pageCount": 4
  }
}

10. 템플릿 응답에 theme 필드 추가

GET /templates 목록 및 GET /templates/{templateUid} 상세 응답 객체에 theme 필드가 추가됩니다.

Before — 템플릿 응답 객체
{
  "templateUid": "tmpl_abc123",
  "name": "미니멀 일기장",
  "bookSpecUid": "spec_xyz"
}
After — theme 필드 포함
{
  "templateUid": "tmpl_abc123",
  "name": "미니멀 일기장",
  "bookSpecUid": "spec_xyz",
  "theme": "minimal"
}

v1.0 2026-03-24

Book Print API 최초 공개 릴리즈입니다. 책 생성부터 주문·배송까지의 전체 워크플로우를 지원하는 7개 리소스 그룹이 포함됩니다.

리소스포함 엔드포인트
AuthenticationAPI Key 발급 — Bearer token, IP 화이트리스트
Books생성, 표지/콘텐츠 추가, 사진 업로드, 최종화, 목록/상세/사진 조회
Orders견적 조회, 주문 생성, 취소, 배송지 변경, 목록/상세 조회
Templates목록/상세 조회
BookSpecs목록/상세 조회
Credits잔액 조회
Webhooks설정 등록/조회/삭제, 테스트 전송, 전송 이력 조회

1. Authentication (인증)

모든 API 요청은 Authorization: Bearer {API_KEY} 헤더를 통해 인증합니다.

Key 형식

API Key는 SB{10자리prefix}.{32자리secret} 형식입니다. prefix(SBXXXXXXXXXX)는 키를 식별하며, secret은 생성 시 1회만 반환됩니다. 서버에는 SHA-256 해시로만 저장되므로 분실 시 재발급이 필요합니다.

주요 특징

  • Sandbox / Live 환경별 별도 키 발급 — 환경 간 키 교차 사용 불가
  • IP 화이트리스트 최대 10개 등록 가능 (미설정 시 모든 IP 허용)
  • 잘못된 키: 401 Unauthorized / 화이트리스트 차단: 403 Forbidden
인증 헤더 예시
curl 'https://api.sweetbook.com/v1/books' \
  -H 'Authorization: Bearer SBXXXXXXXXXX.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
인증 실패 응답 (401 Unauthorized)
{
  "success": false,
  "message": "유효하지 않은 API Key입니다.",
  "data": null
}

2. Books API

책의 생성·편집·최종화까지 전체 생명주기를 관리합니다. 책은 DRAFT 상태에서 시작하며,POST /books/{bookUid}/finalization 호출 후 주문 가능한 상태가 됩니다.

엔드포인트 목록

메서드경로설명
POST/books새 책 생성 (bookSpecUid 필수)
GET/books책 목록 조회 — status, limit, offset, isTest 필터
GET/books/{bookUid}책 상세 조회
POST/books/{bookUid}/cover표지 추가 (템플릿 + 이미지 바인딩)
POST/books/{bookUid}/contents콘텐츠(내지) 추가 — Gallery 레이아웃 지원
POST/books/{bookUid}/photos사진 업로드 (최대 200장, 50MB/파일)
GET/books/{bookUid}/photos사진 목록 조회
DELETE/books/{bookUid}/photos/{photoId}사진 삭제
POST/books/{bookUid}/finalization최종화 — 편집 완료, 주문 가능 상태로 전환

이미지 업로드 방식

사진 업로드(POST /photos)는 세 가지 방식을 혼합하여 한 번에 전송할 수 있습니다.

  • 파일 업로드: multipart/form-data로 직접 전송 ($upload 키 사용)
  • URL: 공개 접근 가능한 이미지 URL 지정
  • 서버 파일명: 이전에 업로드된 파일의 서버 측 파일명 참조

HEIC / WebP / BMP 포맷은 JPEG으로 자동 변환됩니다. EXIF 방향 정보도 자동으로 보정됩니다. MD5 해시 기반 중복 검사가 적용되어 동일 파일은 재업로드되지 않습니다.

Gallery 레이아웃

  • Collage: 한 페이지에 최대 9장 배치
  • Row: 행 단위 배치, 장 수 제한 없음

외부 시스템 연동

externalRef 파라미터를 통해 파트너 시스템의 고유 ID를 책에 연결할 수 있습니다. 목록 조회 시 해당 값으로 필터링하거나 추적이 가능합니다.

POST /books — 책 생성
curl -X POST 'https://api.sweetbook.com/v1/books' \
  -H 'Authorization: Bearer {YOUR_API_KEY}' \
  -H 'Content-Type: application/json' \
  -d '{
  "bookSpecUid": "spec_abc123",
  "externalRef": "my-order-9999"
}'
Response (201 Created)
{
  "success": true,
  "message": "Success",
  "data": {
    "bookUid": "book_xyz789",
    "status": "DRAFT",
    "bookSpecUid": "spec_abc123",
    "externalRef": "my-order-9999",
    "createdAt": "2026-03-24T10:00:00Z"
  }
}
POST /books/{bookUid}/photos — 사진 업로드 (혼합)
curl -X POST 'https://api.sweetbook.com/v1/books/book_xyz789/photos' \
  -H 'Authorization: Bearer {YOUR_API_KEY}' \
  -F '$upload=@/path/to/photo1.jpg' \
  -F 'url=https://example.com/photo2.jpg'
POST /books/{bookUid}/contents — Gallery 레이아웃
curl -X POST 'https://api.sweetbook.com/v1/books/book_xyz789/contents' \
  -H 'Authorization: Bearer {YOUR_API_KEY}' \
  -H 'Content-Type: application/json' \
  -d '{
  "layoutType": "COLLAGE",
  "photos": [
    { "photoId": "photo_001" },
    { "photoId": "photo_002" },
    { "photoId": "photo_003" }
  ]
}'

3. Orders API

견적 조회 후 주문을 생성하면 크레딧이 즉시 차감됩니다. 취소 시 차감된 크레딧은 자동으로 환불됩니다.

엔드포인트 목록

메서드경로설명
POST/orders/estimate견적 조회 — 주문 전 금액 미리 확인
POST/orders주문 생성 — 크레딧 즉시 차감
GET/orders주문 목록 조회
GET/orders/{orderUid}주문 상세 조회
POST/orders/{orderUid}/cancel주문 취소 — PAID / PDF_READY 상태만 가능, 크레딧 자동 환불
PATCH/orders/{orderUid}/shipping배송지 변경 — PAID / PDF_READY / CONFIRMED 상태 가능

금액 계산 공식

항목계산식
제품 금액단가 × 수량
배송비3,500원 / 주문 (수량 무관 고정)
포장비500원 × 수량
합계제품 금액 + 배송비 + 포장비
결제 크레딧 (VAT 포함)floor(합계 × 1.1 / 10) × 10

주문 상태 코드 (11종)

코드상태명설명
20PAID결제 완료 — 크레딧 차감됨
25PDF_READYPDF 생성 완료 — 제작 대기 중
30CONFIRMED제작 확정 — 취소 불가 시점
40IN_PRODUCTION제작 진행 중
45COMPLETED항목 제작 완료 (부분 완료)
50PRODUCTION_COMPLETE전체 제작 완료
60SHIPPED발송 완료 — 운송장 번호 제공
70DELIVERED배송 완료
80CANCELLED취소 처리됨
81CANCELLED_REFUND취소 후 크레딧 환불 완료
90ERROR오류 발생 — 고객센터 문의 필요
POST /orders/estimate — 견적 조회
curl -X POST 'https://api.sweetbook.com/v1/orders/estimate' \
  -H 'Authorization: Bearer {YOUR_API_KEY}' \
  -H 'Content-Type: application/json' \
  -d '{
  "bookUid": "book_xyz789",
  "quantity": 2
}'
견적 응답 (200 OK)
{
  "success": true,
  "message": "Success",
  "data": {
    "unitPrice": 15000,
    "quantity": 2,
    "productAmount": 30000,
    "shippingFee": 3500,
    "packagingFee": 1000,
    "totalAmount": 34500,
    "paidCreditAmount": 37950
  }
}
POST /orders — 주문 생성
curl -X POST 'https://api.sweetbook.com/v1/orders' \
  -H 'Authorization: Bearer {YOUR_API_KEY}' \
  -H 'Content-Type: application/json' \
  -d '{
  "bookUid": "book_xyz789",
  "quantity": 2,
  "shipping": {
    "recipient": "김영수",
    "phone": "010-0000-0000",
    "address": "서울시 강남구 테헤란로 123",
    "zipCode": "06234"
  }
}'
POST /orders/{orderUid}/cancel — 주문 취소
curl -X POST 'https://api.sweetbook.com/v1/orders/ord_abc123/cancel' \
  -H 'Authorization: Bearer {YOUR_API_KEY}'

4. Templates API

책 표지 및 내지에 적용할 수 있는 디자인 템플릿을 조회합니다. 템플릿에는 $key$ 형식의 파라미터가 포함될 수 있으며, 표지/콘텐츠 추가 시 실제 값으로 치환하여 바인딩합니다.

엔드포인트 목록

메서드경로설명
GET/templates템플릿 목록 조회
GET/templates/{templateUid}템플릿 상세 조회

목록 조회 필터 파라미터

파라미터설명
scope템플릿 접근 범위 (public / private)
templateKind종류: cover (표지) / content (내지)
category카테고리 — 일기장, 알림장, 사진앨범 등
bookSpecUid특정 판형에 호환되는 템플릿만 필터
limit / offset페이지네이션

파라미터 바인딩

템플릿 내 $title$, $date$ 등의 플레이스홀더는 표지/콘텐츠 추가 요청 시parameters 객체에 키-값을 전달하여 치환됩니다.

GET /templates — 목록 조회
curl 'https://api.sweetbook.com/v1/templates?templateKind=cover&category=사진앨범&bookSpecUid=spec_abc123&limit=10' \
  -H 'Authorization: Bearer {YOUR_API_KEY}'
Response (200 OK)
{
  "success": true,
  "message": "Success",
  "data": {
    "total": 24,
    "templates": [
      {
        "templateUid": "tmpl_001",
        "name": "미니멀 사진앨범 표지",
        "templateKind": "cover",
        "category": "사진앨범",
        "bookSpecUid": "spec_abc123",
        "parameters": ["$title$", "$date$"]
      }
    ]
  }
}
POST /books/{bookUid}/cover — 표지 바인딩
curl -X POST 'https://api.sweetbook.com/v1/books/book_xyz789/cover' \
  -H 'Authorization: Bearer {YOUR_API_KEY}' \
  -H 'Content-Type: application/json' \
  -d '{
  "templateUid": "tmpl_001",
  "parameters": {
    "$title$": "우리 가족 앨범",
    "$date$": "2026.03"
  },
  "photoId": "photo_cover_001"
}'

5. BookSpecs API

책 생성에 사용할 수 있는 판형(크기·제본 방식) 목록과 가격 정보를 조회합니다.bookSpecUid는 책 생성 시 필수 파라미터입니다.

엔드포인트 목록

메서드경로설명
GET/book-specs판형 목록 조회
GET/book-specs/{bookSpecUid}판형 상세 조회

제공 판형 종류

판형명크기제본
A4 소프트커버210 × 297 mm소프트커버 무선제본
A5 소프트커버148 × 210 mm소프트커버 무선제본
스퀘어북 하드커버210 × 210 mm하드커버 양장
레이플랫 하드커버210 × 297 mm하드커버 레이플랫
슬림앨범 하드커버148 × 210 mm하드커버 양장

가격 계산 방식

기본 가격은 pageMin까지의 페이지를 포함합니다. 초과 페이지는 pageIncrement 단위로 추가되며, 초과분당 pricePerExtraPage가 부과됩니다. 전체 페이지 수는 pageMin 이상 pageMax 이하여야 합니다.

  • 단가 = 기본가 + (초과 페이지 수 ÷ pageIncrement) × 페이지당 추가금
  • 페이지는 반드시 pageIncrement 배수 단위로만 추가 가능
GET /book-specs — 판형 목록
curl 'https://api.sweetbook.com/v1/book-specs' \
  -H 'Authorization: Bearer {YOUR_API_KEY}'
Response (200 OK)
{
  "success": true,
  "message": "Success",
  "data": {
    "bookSpecs": [
      {
        "bookSpecUid": "spec_abc123",
        "name": "A4 소프트커버",
        "basePrice": 12000,
        "pricePerExtraPage": 200,
        "pageMin": 24,
        "pageMax": 200,
        "pageIncrement": 4
      }
    ]
  }
}

6. Credits API

주문 생성 시 사용되는 크레딧 잔액을 조회합니다. Sandbox와 Live 환경은 잔액이 완전히 분리되어 독립적으로 관리됩니다.

엔드포인트

메서드경로설명
GET/credits현재 크레딧 잔액 조회

크레딧 운영 규칙

  • 주문 생성(POST /orders) 시 paidCreditAmount만큼 즉시 차감
  • 주문 취소 시 차감된 크레딧 전액 자동 환불
  • 잔액 부족 시 402 Payment Required 반환
  • Sandbox 환경 잔액은 실제 결제와 무관한 테스트 전용 크레딧
GET /credits — 잔액 조회
curl 'https://api.sweetbook.com/v1/credits' \
  -H 'Authorization: Bearer {YOUR_API_KEY}'
Response (200 OK)
{
  "success": true,
  "message": "Success",
  "data": {
    "balance": 150000,
    "env": "live",
    "currency": "KRW"
  }
}
잔액 부족 응답 (402 Payment Required)
{
  "success": false,
  "message": "크레딧이 부족합니다.",
  "data": {
    "required": 37950,
    "balance": 10000
  }
}

7. Webhooks API

주문 상태 변경 등의 이벤트가 발생할 때 지정한 URL로 HTTP POST 요청을 전송합니다. 수신 서버는 HMAC-SHA256 서명을 검증하여 요청의 신뢰성을 확인해야 합니다.

엔드포인트 목록

메서드경로설명
PUT/webhooks/config웹훅 URL 및 secret 등록/수정
GET/webhooks/config현재 웹훅 설정 조회
DELETE/webhooks/config웹훅 설정 삭제
POST/webhooks/test테스트 이벤트 즉시 전송
GET/webhooks/deliveries전송 이력 조회 (성공/실패 포함)

지원 이벤트

이벤트발생 시점
order.paid주문 생성 및 크레딧 차감 완료
order.confirmed제작 확정 — 이후 취소 불가
order.status_changed주문 상태 변경 시 (모든 상태 전환)
order.shipped발송 완료 — 운송장 번호 포함
order.cancelled주문 취소 및 환불 처리 완료

전송 헤더

헤더설명
X-Webhook-Event이벤트 종류 (예: order.paid)
X-Webhook-SignatureHMAC-SHA256 서명 (sha256=...)
X-Webhook-Timestamp전송 시각 (Unix timestamp)
X-Webhook-Delivery-Id전송 이력 고유 ID

재시도 정책

수신 서버가 2xx 응답을 반환하지 않으면 최대 3회 재시도합니다. 재시도 간격: 1분 후 → 5분 후 → 30분 후. 3회 모두 실패하면 해당 전송은 실패 처리되며 GET /webhooks/deliveries에서 확인할 수 있습니다.

PUT /webhooks/config — 설정 등록
curl -X PUT 'https://api.sweetbook.com/v1/webhooks/config' \
  -H 'Authorization: Bearer {YOUR_API_KEY}' \
  -H 'Content-Type: application/json' \
  -d '{
  "url": "https://your-server.com/webhooks/sweetbook",
  "secret": "your-webhook-secret-key"
}'
웹훅 페이로드 예시 (order.shipped)
{
  "event": "order.shipped",
  "timestamp": "2026-03-25T14:30:00Z",
  "data": {
    "orderUid": "ord_abc123",
    "status": "SHIPPED",
    "trackingNumber": "1234567890",
    "carrier": "CJ대한통운"
  }
}
서명 검증 예시 (Node.js)
const crypto = require('crypto');

function verifySignature(payload, signature, secret) {
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signature)
  );
}

8. 플랫폼 공통 특징

v1.0 전체에 적용되는 공통 동작 및 제약 사항입니다.

항목내용
인증 방식API Key — Bearer token (Authorization 헤더)
환경 분리Sandbox / Live 환경 독립 운영 — 키·크레딧·데이터 모두 분리
응답 형식JSON { success, message, data } 구조 통일
페이지네이션limit / offset 기반 (전체 목록 조회 API 공통)
Rate Limiting일반 API 300 req/min, 업로드 API 200 req/min
날짜 형식ISO 8601 UTC (2026-03-24T00:00:00Z)
이미지 자동 변환HEIC / WebP / BMP → JPEG 자동 변환, EXIF 방향 자동 보정
중복 이미지 검사MD5 해시 기반 — 동일 파일 재업로드 방지
Webhook 보안HMAC-SHA256 서명 (X-Webhook-Signature)
Idempotency-Key미지원 (v1.0.1에서 추가됨)