변경이력 (Changelog)
Book Print API의 버전별 변경 내역입니다. 이전 버전의 변경 내역을 통해 API의 변화를 추적할 수 있습니다.
v1.2.3 2026-05-13
BookSpec 사이즈 수치 정정. 응답 필드 자체는 변경 없이 수치값만 변경되었습니다 (Issue #3).
변경 요약
| 분류 | 항목 | 이전 | 변경 후 |
|---|---|---|---|
하드커버 (SQUAREBOOK_HC, SQUAREBOOK_LAYFLAT_HC) | hingeGapMm (미소) | 9.5 | 10 |
| 하드커버 | spineWidthRules[].spineWidthMm (책등 너비) | 11 / 17 | 10 / 16 |
소프트커버 (PHOTOBOOK_A4_SC, PHOTOBOOK_A5_SC) | coverThicknessMm (표지 두께) | 0.4 | 1.0 |
| 소프트커버 | pageThicknessMm (페이지 1장당 두께) | 0.0574 | 0.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 동작은 변경 없습니다.
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 값, 상태 비교, 메시지 파싱)를 명시적 가이드로 보강합니다.
- Orders API · Webhooks API · Webhook Events · Credits API
- 인증 (API Key)
- 템플릿 기반 시나리오 · PDF 업로드 시나리오
- 에러 코드 & 트러블슈팅 · 환경 매트릭스
SSR 전환 (Issue #39)
36개 docs 페이지에서 "use client" 지시문 제거 + usePageTitle 훅을 <PageTitleClient> 컴포넌트로 교체. 본문이 서버 HTML에 직접 포함되어 검색엔진 크롤러·웹 fetch 도구가 본문을 즉시 읽을 수 있습니다. (예외: docs/changelog/page.tsx는 useState 사용으로 client 컴포넌트 유지)
안내 페이지 신규 (3건)
- AI 에이전트 지원 개요 — 3가지 산출물과 도구별 사용 흐름
- llms.txt · llms-full.txt 사용법 — 두 산출물의 차이, 도구별 등록 방법
- .md URL 사용법 — 페이지별 마크다운 fetch + AGENT INSTRUCTIONS 가드 메모 안내
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)로 분기하는 클라이언트에는 영향 없습니다.
내지 PDF 페이지수 불일치: 실제 10p, 예상 8p내지 PDF 페이지수 불일치: 올바른 페이지수 24p, 업로드된 페이지수 30p내지 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·단건 액션·통계 리포트는 변경 없습니다.
영향 받는 파트너 공개 엔드포인트의 응답 구조가 평탄화됩니다. 클라이언트 코드에서
data.{리소스명} 접근을 data 직접 접근으로 변경해야 합니다.envelope 변경
{
"success": true,
"data": {
"books": [ /* ... */ ],
"pagination": { "total": 120, "limit": 20, "offset": 0, "hasNext": true }
}
}{
"success": true,
"data": [ /* ... */ ],
"pagination": { "total": 120, "limit": 20, "offset": 0, "hasNext": true }
}페이지네이션이 없는 list는 pagination 필드가 응답에 생략됩니다.
영향 받는 파트너 공개 엔드포인트
| 엔드포인트 | Before data 키 | After |
|---|---|---|
GET /books | books | data: [] |
GET /books/{bookUid}/photos | photos + totalCount | data: [] + pagination.total |
GET /templates | templates | data: [] |
GET /credits/transactions | transactions | data: [] + pagination 신규 추가 |
GET /webhooks/deliveries | deliveries | data: [] |
변경 안 되는 엔드포인트
- 단건 GET 전부 (
GET /books/{bookUid},GET /orders/{orderUid}등) - 단건 액션 응답 전부 (POST / PATCH / DELETE)
GET /orders— v1.1.0 (C19)에서 이미 평탄화 완료- 모든 실패 응답 — v1.2.0 6필드 shape 유지
마이그레이션 가이드
클라이언트 코드의 list 응답 접근을 평탄화 패턴으로 변경합니다.
// 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 엔드포인트가 동시에 평탄화되므로 어댑터는 짧은 기간만 필요합니다.
관련 페이지 갱신
- 페이지네이션 — 응답 구조 섹션 전면 갱신,
data평탄화 패턴으로 통일 - API 공통 사항 — list envelope 통일 안내 박스 추가, 예시 3종 평탄화
- Books API — PDF 기반, Books API — 템플릿 기반 — 책 목록·사진 목록 Response 예시 갱신
- Templates API — 목록 조회 Response 갱신
- Credits API — 거래 내역 Response 갱신 +
pagination신규 노출
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개를 포함합니다.
- 주문 응답 구조 변경 —
GET /orders평탄화 +orderStatus문자열 enum (이하 C19) - 책 페이지 메타 객체 도입 —
pageCount필드 →pageMeta객체 이동 (이하 C04) - 빈 TEMPLATE 책 finalize 응답 정정 —
500→400 ERR_FINALIZE_PREREQ_UNMET(이하 C-7 핫픽스) - PDF 다운로드 응답 코드 세분화 — TEMPLATE/MIX 표지 PDF GET이 일괄
404→409/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 공통 사항 · 에러 코드 & 트러블슈팅 페이지를 참조하세요.
{
"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)
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 안내 박스를 참조하세요.
{
"success": true,
"data": {
"orders": [
{ "orderUid": "or_xxxx", "orderStatus": 20 }
],
"pagination": { "total": 1, "limit": 20, "offset": 0, "hasNext": false }
}
}{
"success": true,
"data": [
{
"orderUid": "or_xxxx",
"orderStatus": "PAID",
"orderStatusDisplay": "결제완료"
}
],
"pagination": { "total": 1, "limit": 20, "offset": 0, "hasNext": false }
}C04 — 책 페이지 메타 객체 (Breaking)
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 — 템플릿 기반 페이지를 참조하세요.
{
"success": true,
"data": {
"bookUid": "bk_xxxx",
"pageCount": 0
}
}{
"success": true,
"data": {
"bookUid": "bk_xxxx",
"pageMeta": {
"currentPageCount": 0,
"pageMin": 24,
"pageMax": 130,
"pageIncrement": 2,
"isValid": false
}
}
}C-7 — finalize 응답 정정 (Breaking) + 전제조건 매핑
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 — 템플릿 기반의 책 최종화 섹션을 참조하세요.
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)
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종
| errorCode | HTTP | 발생 조건 |
|---|---|---|
ERR_PDF_NOT_UPLOADED | 404 | 그룹 A — 업로드형 PDF 파일 없음 |
ERR_PDF_NOT_GENERATED | 409 | 그룹 B — 책 최종화 호출 전 |
ERR_PDF_PENDING | 409 | 그룹 B — 백그라운드 생성 진행 중 |
ERR_PDF_GENERATION_FAILED | 422 | 그룹 B — 생성 실패(클라이언트 자체 해결 불가) |
ERR_PDF_FILE_MISSING | 500 | 그룹 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 표준 형식으로 변환되며 원본binding은x-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.shipped 등 | order.created, shipping.departed 등 8개 통일 |
| 웹훅 페이로드 | camelCase / 구조 불일치 | snake_case + envelope 구조 통일 |
| X-Webhook-Timestamp | ISO 8601 | Unix timestamp (초) |
| 배송비 | 3,500원 (일부 페이지) | 3,000원 통일 |
| 포장비 | 500원 (일부 페이지) | 0원 통일 |
| 충전금 잔액 API | GET /credits/balance | GET /credits |
| 402 에러 응답 | data: null | {required, balance, currency} |
| 금액 표기 | 정수 (3000) | decimal (3000.00) |
| 파일 형식 | TIFF 포함 / HEIF 누락 | TIFF 제거, HEIC/HEIF 포함 |
| 자동 변환 | "모두 JPEG" | GIF/WebP→PNG, BMP/HEIC/HEIF→JPG |
| templateKind | 2개 (일부 페이지) | 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 생성 필드 | name | note |
| 책 삭제 제약 | DRAFT 상태만 | 본인 소유 책 상태 무관 삭제 가능 |
| 주문 취소 | cancelReason 선택 | 필수 (최대 500자) |
| 충전금 거래 필드 | transactionUid, type, description | transactionId, reasonCode+reasonDisplay, memo |
| Sandbox 충전금 필드 | description | memo |
추가 사항
| 항목 | 내용 |
|---|---|
| 충전금 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 스코프 시스템, 멱등성 지원, 템플릿 검색 등 여러 기능이 개선되었습니다.
책 생성 요청 본문 (POST /books)에서 creationType 필드가 제거되었습니다. 자세한 내용은 아래를 참고하세요.Breaking Change
1. 책 생성 요청 본문 (POST /books)에서 creationType 제거
책 생성 요청 본문에서 creationType 필드가 제거되었습니다. 해당 필드를 전송하더라도 무시되며,bookSpecUid만으로 책을 생성할 수 있습니다.
{
"bookSpecUid": "spec_abc123",
"creationType": "TEMPLATE"
}{
"bookSpecUid": "spec_abc123"
}신규 API
2. 책 삭제 — DELETE /books/{bookUid}
DRAFT 상태인 본인 소유의 책을 삭제할 수 있습니다. 삭제는 소프트 딜리트(soft delete)로 처리됩니다. 이미 주문이 연결된 책이나 타인 소유의 책은 삭제할 수 없습니다.
curl -X DELETE 'https://api-sandbox.sweetbook.com/v1/books/book_abc123' \
-H 'Authorization: Bearer {YOUR_API_KEY}'{
"success": true,
"message": "책이 삭제되었습니다.",
"data": null
}3. 크레딧 거래 내역 조회 — GET /credits/transactions
본인 계정의 크레딧 충전·차감 거래 내역을 조회합니다. 페이지네이션(limit/offset)을 지원합니다.
curl 'https://api-sandbox.sweetbook.com/v1/credits/transactions?limit=20&offset=0' \
-H 'Authorization: Bearer {YOUR_API_KEY}'{
"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 환경에서는 동작하지 않습니다.
403 Forbidden이 반환됩니다.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
}'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 | 주문 생성, 취소 |
{
"env": "live"
}{
"env": "live",
"scopes": ["books:read", "orders:read"]
}{
"success": false,
"message": "이 작업을 수행할 권한이 없습니다.",
"data": null
}6. 템플릿 목록 정렬/검색 파라미터 추가
GET /templates에 정렬 및 검색 파라미터가 추가되었습니다.
| 파라미터 | 설명 |
|---|---|
sort | name_asc, name_desc, created_asc, updated_desc, updated_asc |
templateName | 이름 검색 (공백 구분 다중 키워드, AND 조건) |
specProfileUid | 특정 판형 프로필 UID로 필터 |
theme | 테마로 필터 (예: minimal) |
curl 'https://api.sweetbook.com/v1/templates?limit=20&offset=0' \
-H 'Authorization: Bearer {YOUR_API_KEY}'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이 반환됩니다.
curl 'https://api.sweetbook.com/v1/book-specs?accountUid=acc_myuid123' \
-H 'Authorization: Bearer {YOUR_API_KEY}'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
curl -X POST 'https://api.sweetbook.com/v1/books' \
-H 'Authorization: Bearer {YOUR_API_KEY}' \
-H 'Content-Type: application/json' \
-d '{ "bookSpecUid": "spec_abc123" }'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 필드가 포함됩니다.
{
"success": true,
"message": "Success",
"data": {
"bookUid": "book_xyz123",
"status": "DRAFT"
}
}{
"success": true,
"message": "Success",
"data": {
"bookUid": "book_xyz123",
"status": "DRAFT",
"pageCount": 4
}
}10. 템플릿 응답에 theme 필드 추가
GET /templates 목록 및 GET /templates/{templateUid} 상세 응답 객체에 theme 필드가 추가됩니다.
{
"templateUid": "tmpl_abc123",
"name": "미니멀 일기장",
"bookSpecUid": "spec_xyz"
}{
"templateUid": "tmpl_abc123",
"name": "미니멀 일기장",
"bookSpecUid": "spec_xyz",
"theme": "minimal"
}v1.0 2026-03-24
Book Print API 최초 공개 릴리즈입니다. 책 생성부터 주문·배송까지의 전체 워크플로우를 지원하는 7개 리소스 그룹이 포함됩니다.
| 리소스 | 포함 엔드포인트 |
|---|---|
| Authentication | API 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'{
"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를 책에 연결할 수 있습니다. 목록 조회 시 해당 값으로 필터링하거나 추적이 가능합니다.
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"
}'{
"success": true,
"message": "Success",
"data": {
"bookUid": "book_xyz789",
"status": "DRAFT",
"bookSpecUid": "spec_abc123",
"externalRef": "my-order-9999",
"createdAt": "2026-03-24T10:00:00Z"
}
}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'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종)
| 코드 | 상태명 | 설명 |
|---|---|---|
20 | PAID | 결제 완료 — 크레딧 차감됨 |
25 | PDF_READY | PDF 생성 완료 — 제작 대기 중 |
30 | CONFIRMED | 제작 확정 — 취소 불가 시점 |
40 | IN_PRODUCTION | 제작 진행 중 |
45 | COMPLETED | 항목 제작 완료 (부분 완료) |
50 | PRODUCTION_COMPLETE | 전체 제작 완료 |
60 | SHIPPED | 발송 완료 — 운송장 번호 제공 |
70 | DELIVERED | 배송 완료 |
80 | CANCELLED | 취소 처리됨 |
81 | CANCELLED_REFUND | 취소 후 크레딧 환불 완료 |
90 | ERROR | 오류 발생 — 고객센터 문의 필요 |
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
}'{
"success": true,
"message": "Success",
"data": {
"unitPrice": 15000,
"quantity": 2,
"productAmount": 30000,
"shippingFee": 3500,
"packagingFee": 1000,
"totalAmount": 34500,
"paidCreditAmount": 37950
}
}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"
}
}'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 객체에 키-값을 전달하여 치환됩니다.
curl 'https://api.sweetbook.com/v1/templates?templateKind=cover&category=사진앨범&bookSpecUid=spec_abc123&limit=10' \
-H 'Authorization: Bearer {YOUR_API_KEY}'{
"success": true,
"message": "Success",
"data": {
"total": 24,
"templates": [
{
"templateUid": "tmpl_001",
"name": "미니멀 사진앨범 표지",
"templateKind": "cover",
"category": "사진앨범",
"bookSpecUid": "spec_abc123",
"parameters": ["$title$", "$date$"]
}
]
}
}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배수 단위로만 추가 가능
curl 'https://api.sweetbook.com/v1/book-specs' \
-H 'Authorization: Bearer {YOUR_API_KEY}'{
"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 환경 잔액은 실제 결제와 무관한 테스트 전용 크레딧
curl 'https://api.sweetbook.com/v1/credits' \
-H 'Authorization: Bearer {YOUR_API_KEY}'{
"success": true,
"message": "Success",
"data": {
"balance": 150000,
"env": "live",
"currency": "KRW"
}
}{
"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-Signature | HMAC-SHA256 서명 (sha256=...) |
X-Webhook-Timestamp | 전송 시각 (Unix timestamp) |
X-Webhook-Delivery-Id | 전송 이력 고유 ID |
재시도 정책
수신 서버가 2xx 응답을 반환하지 않으면 최대 3회 재시도합니다. 재시도 간격: 1분 후 → 5분 후 → 30분 후. 3회 모두 실패하면 해당 전송은 실패 처리되며 GET /webhooks/deliveries에서 확인할 수 있습니다.
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"
}'{
"event": "order.shipped",
"timestamp": "2026-03-25T14:30:00Z",
"data": {
"orderUid": "ord_abc123",
"status": "SHIPPED",
"trackingNumber": "1234567890",
"carrier": "CJ대한통운"
}
}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에서 추가됨) |