Books API — 템플릿 기반
SweetBook 템플릿에 이미지·텍스트를 바인딩하여 책을 생성하는 방식의 API 레퍼런스입니다. 표지·내지 페이지를 템플릿 단위로 추가하고, 명시적인 최종화(finalize) 호출로 주문 가능 상태로 전환합니다.
creationType="PDF_UPLOAD" / "MIX_COVER_TEMPLATE")은 Books — PDF 기반 페이지를 참고하세요. 실제 호출 흐름을 단계별 따라 하기로 보려면 템플릿 기반 시나리오를 참고하세요.Authorization: Bearer {YOUR_API_KEY} 헤더로 제공하세요. 자세한 인증 안내는 인증 가이드를 참고하세요.이 방식이 적합한 경우
- SweetBook이 제공하는 표지·내지 템플릿을 활용하고 싶은 경우
- 이미지·텍스트만 입력하고 레이아웃은 템플릿에 맡기는 경우
- 여러 페이지를 다양한 템플릿(갤러리/베이스 레이어/간지/발행면 등)으로 조합하고 싶은 경우
지원 creationType
creationType | 표지 | 내지 | 비고 |
|---|---|---|---|
TEMPLATE | 템플릿 바인딩 | 템플릿 바인딩 | 이 페이지의 기본 흐름 |
MIX_COVER_TEMPLATE | 템플릿 바인딩 | PDF 직접 업로드 | 표지만 이 페이지의 POST /books/{bookUid}/cover 사용. 내지 PDF 업로드는 Books — PDF 기반의 POST /pdf-contents 사용 |
PDF_UPLOAD 방식은 표지·내지 모두 PDF 직접 업로드로 진행하며, 이 페이지의 템플릿 엔드포인트(/cover, /contents, /photos)는 사용할 수 없습니다.Books — PDF 기반을 참고하세요.
책 생성
/books새로운 책을 생성합니다. 생성 직후 status="draft" 상태이며, 이후 표지·내지 추가와 명시적인 최종화 단계를 거쳐 주문 가능 상태로 진입합니다.
Request Body
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
title | string | O | 책 제목 (1~255자) |
bookSpecUid | string | O | 판형 UID (예: SQUAREBOOK_HC). BookSpecs API로 조회 |
creationType | string | O | "TEMPLATE" 또는 "MIX_COVER_TEMPLATE". 그 외 값은 400 에러 |
pageCount | integer | 조건부 | TEMPLATE: 불필요. 요청에 포함해도 서버에서 무시되며(에러 없음), 실제 pageCount는 0으로 초기화된 뒤 콘텐츠 추가에 따라 자동 산출됩니다. MIX_COVER_TEMPLATE: 필수 (내지 PDF 페이지 수) |
specProfileUid | string | — | SpecProfile UID (선택, 일반적으로 미사용). 사용자별 판형 프로파일이 사전 등록된 경우에만 사용. 제공 시 해당 프로필과 연결, 유효하지 않으면 400 |
externalRef | string | — | 파트너 외부 참조 식별자 (최대 100자). 파트너 시스템의 고유 ID 매핑용 |
bookUid를 사용해 표지(POST /cover)·내지(POST /contents) 추가와 최종화(POST /finalization)를 순차적으로 진행해야 주문 가능한 상태(finalized)가 됩니다.POST /books는 Idempotency-Key 헤더를 지원합니다. 동일한 키로 재요청해도 책이 중복 생성되지 않으므로, 네트워크 오류 등 재시도 상황에 활용하세요. 재시도가 캐시된 응답으로 처리된 경우 응답 헤더에 X-Idempotent-Replayed: true가 포함됩니다. 자세한 동작은 멱등성 가이드를 참고하세요.Request 예시
{
"title": "일기장 샘플",
"bookSpecUid": "SQUAREBOOK_HC",
"creationType": "TEMPLATE",
"externalRef": "PARTNER-ORDER-001"
}{
"title": "혼합 방식 샘플",
"bookSpecUid": "SQUAREBOOK_HC",
"creationType": "MIX_COVER_TEMPLATE",
"pageCount": 24,
"externalRef": "PARTNER-ORDER-002"
}curl -X POST 'https://api-sandbox.sweetbook.com/v1/books' \
-H 'Authorization: Bearer {YOUR_API_KEY}' \
-H 'Idempotency-Key: unique-request-id-001' \
-H 'Content-Type: application/json' \
-d '{
"title": "일기장 샘플",
"bookSpecUid": "SQUAREBOOK_HC",
"creationType": "TEMPLATE",
"externalRef": "PARTNER-ORDER-001"
}'응답 필드
| 필드 | 타입 | 설명 |
|---|---|---|
bookUid | string | 생성된 책의 UID |
pageMeta | object | 페이지 제약 메타. currentPageCount·pageMin·pageMax·pageIncrement·isValid 5개 필드 |
Response 예시
{
"success": true,
"message": "책 생성 완료",
"data": {
"bookUid": "bk_3k2S********",
"pageMeta": {
"currentPageCount": 0,
"pageMin": 24,
"pageMax": 200,
"pageIncrement": 1,
"isValid": false
}
}
}pageMeta: TEMPLATE 방식은 생성 직후 currentPageCount=0, isValid=false로 시작합니다. 콘텐츠 추가(POST /books/{bookUid}/contents) 호출에 따라 자동 증가합니다. MIX_COVER_TEMPLATE은 요청의 pageCount 값이 currentPageCount로 반영됩니다. isValid는 페이지 제약만 판정하며, finalize 가능 여부는 표지·내지 존재 여부 등 다른 조건도 포함되므로 POST /finalization 호출로 최종 확인하세요.
HTTP 상태 코드
| 코드 | errorCode | 설명 |
|---|---|---|
| 201 Created | — | 책 생성 성공 |
| 400 Bad Request | ERR_VALIDATION_FAILED | title/bookSpecUid/creationType 누락 또는 허용되지 않은 값, MIX 방식인데 pageCount 누락, 잘못된 specProfileUid 등 |
| 401 Unauthorized | ERR_UNAUTHORIZED | 인증 실패 |
| 422 Unprocessable Entity | ERR_IDEMPOTENCY_KEY_MISMATCH | 동일 Idempotency-Key로 다른 본문 재요청 |
| 429 Too Many Requests | ERR_TOO_MANY_REQUESTS | 요청 빈도 제한 초과 — Rate Limiting 가이드 참고 |
| 500 Internal Server Error | ERR_INTERNAL_ERROR | 서버 오류 |
본 엔드포인트의 주요 검증 실패 메시지(400 ERR_VALIDATION_FAILED):
creationType누락 또는 허용되지 않은 값 —errors[0]:"유효하지 않은 creationType: <값> (허용: TEMPLATE, PDF_UPLOAD, MIX_COVER_TEMPLATE)"MIX_COVER_TEMPLATE인데pageCount누락 —errors[0]:"creation_type=MIX_COVER_TEMPLATE는 pageCount(내지 페이지수)가 필수입니다."
TEMPLATE은 pageCount가 필요 없으므로 누락해도 에러가 발생하지 않으며, 값을 포함해도 서버에서 무시됩니다(실제 저장값은 0). 응답 6필드 shape, 다른 errorCode, 처리 가이드는 에러 코드 & 트러블슈팅을 참조하세요.
표지 추가
/books/{bookUid}/cover지정한 표지 템플릿에 이미지·텍스트를 바인딩하여 책의 표지를 생성합니다. 이미지는 위 이미지 처리 → 이미지 전달 방식 섹션의 3가지 방식 중 어느 것으로든 제공할 수 있고, 한 요청에서 혼용도 가능합니다.
creationType="MIX_COVER_TEMPLATE" 책의 표지도 이 엔드포인트를 사용합니다 (표지는 템플릿, 내지는 PDF). 단 creationType="PDF_UPLOAD" 책에는 사용할 수 없습니다 (그 경우 Books — PDF 기반의 POST /pdf-cover 사용).Request — multipart/form-data
| 필드 | 위치 | 타입 | 필수 | 설명 |
|---|---|---|---|---|
bookUid | path | string | O | 대상 책 UID |
templateUid | form | string | O | 표지 템플릿 UID. Templates API에서 templateKind=cover로 조회 |
parameters | form | string (JSON) | — | 템플릿 파라미터 (텍스트 값, 이미지 URL, 서버 파일명, $upload 플레이스홀더 포함). 템플릿이 요구하는 변수에 따라 필수성 결정 |
| (이미지 필드명) | form-data | file | — | 템플릿의 이미지 변수명($변수명$)과 동일한 이름으로 multipart 파일 첨부 (예: coverPhoto=@front.jpg) |
템플릿의 변수 목록과 필수 여부는 Templates API의 템플릿 상세 조회로 확인할 수 있습니다. 템플릿 구조와 바인딩 동작 원리는 템플릿 구조와 바인딩을 참고하세요.
Idempotency-Key 헤더를 함께 보내면 동일한 키로 재요청해도 표지가 중복 추가되지 않습니다. 자세한 동작은 멱등성 가이드를 참고하세요.Request 예시
curl -X POST 'https://api-sandbox.sweetbook.com/v1/books/{bookUid}/cover' \
-H 'Authorization: Bearer {YOUR_API_KEY}' \
-F 'templateUid=79yjMH3qRPly' \
-F 'coverPhoto=@front.jpg' \
-F 'parameters={"title":"나의 하루 기록","dateRange":"26.01 - 26.04","coverPhoto":"$upload"}'curl -X POST 'https://api-sandbox.sweetbook.com/v1/books/{bookUid}/cover' \
-H 'Authorization: Bearer {YOUR_API_KEY}' \
-F 'templateUid=79yjMH3qRPly' \
-F 'parameters={"title":"나의 하루 기록","coverPhoto":"https://example.com/front.jpg"}'curl -X POST 'https://api-sandbox.sweetbook.com/v1/books/{bookUid}/cover' \
-H 'Authorization: Bearer {YOUR_API_KEY}' \
-F 'templateUid=79yjMH3qRPly' \
-F 'parameters={"title":"나의 하루 기록","coverPhoto":"photo250105143052123.JPG"}'응답 필드
| 필드 | 타입 | 설명 |
|---|---|---|
result | string | 처리 결과. "inserted" 고정 |
pageMeta | object | 페이지 제약 메타 (참고용 — 표지는 카운트에 미포함) |
Response 예시
{
"success": true,
"message": "표지가 생성되었습니다",
"data": {
"result": "inserted",
"pageMeta": {
"currentPageCount": 0,
"pageMin": 24,
"pageMax": 200,
"pageIncrement": 1,
"isValid": false
}
}
}표지는 내지 카운트(currentPageCount)에 포함되지 않으므로 표지 추가 후에도 값이 변하지 않습니다. pageMeta는 현재 내지 상태를 보고용으로 함께 노출됩니다.
HTTP 상태 코드
| 코드 | errorCode | 설명 |
|---|---|---|
| 201 Created | — | 표지 신규 등록 성공 |
| 400 Bad Request | ERR_VALIDATION_FAILED / ERR_CREATION_TYPE_UNSUPPORTED | templateUid 누락, 필수 이미지 파라미터 누락, parameters JSON 파싱 실패, 이미 표지 등록됨("이미 표지가 존재합니다"), PDF_UPLOAD 책에 사용 시 차단 등 |
| 401 Unauthorized | ERR_UNAUTHORIZED | 인증 실패 |
| 404 Not Found | ERR_NOT_FOUND | 책 또는 템플릿 없음 |
| 429 Too Many Requests | ERR_TOO_MANY_REQUESTS | 업로드 Rate Limit 초과 — Rate Limiting 가이드 참고 |
| 500 Internal Server Error | ERR_INTERNAL_ERROR | 서버 오류 |
본 엔드포인트의 주요 검증 실패 메시지(400 ERR_VALIDATION_FAILED):
- 이미 표지가 등록됨 —
errors[0]:"이미 표지가 존재합니다" - 필수 이미지 파라미터 누락 —
errors[0]:"필수 이미지 파라미터 '<name>' (<설명>)이 제공되지 않았습니다. form-data에 파일을 첨부하거나 parameters에 URL 또는 서버 파일명을 제공해야 합니다."
파라미터 이름(예: coverPhoto)과 설명(예: 앞표지 메인 사진)은 템플릿에 따라 달라집니다. Templates API에서 해당 템플릿의 필수 변수 목록을 먼저 확인하세요. 응답 6필드 shape, 다른 errorCode, 처리 가이드는 에러 코드 & 트러블슈팅을 참조하세요.
콘텐츠(내지) 추가
/books/{bookUid}/contents지정한 콘텐츠(내지) 템플릿에 이미지·텍스트를 바인딩하여 페이지를 추가합니다. 한 번 호출에 한 콘텐츠가 추가되며, 여러 페이지를 만들려면 반복 호출합니다. 이미지 전달 방식은 위 이미지 처리 → 이미지 전달 방식 섹션과 동일합니다.
creationType="PDF_UPLOAD" · "MIX_COVER_TEMPLATE" 책에는 이 엔드포인트를 사용할 수 없습니다. 두 방식은 내지를 PDF로 업로드합니다 (Books — PDF 기반의 POST /pdf-contents 사용).Request — multipart/form-data
| 필드 | 위치 | 타입 | 필수 | 설명 |
|---|---|---|---|---|
bookUid | path | string | O | 대상 책 UID |
templateUid | form | string | O | 콘텐츠/간지/발행면 템플릿 UID. Templates API에서 templateKind=content/divider/publish로 조회 |
parameters | form | string (JSON) | — | 템플릿 파라미터. 갤러리 등 다수 이미지를 받는 변수는 배열로 전달 가능 (예: "galleryPhotos": ["url1", "url2"]) |
breakBefore | query | string | — | 페이지 나누기 방식. page(새 페이지) / column(새 단) / none(이어붙기). 기본값은 템플릿 종류에 따라 다름 (content: none, divider/publish: page). 위 외 값은 400 에러 |
| (이미지 필드명) | form-data | file | — | 템플릿의 이미지 변수명($변수명$)과 동일한 이름으로 multipart 파일 첨부 |
템플릿 종류와 변수 정보는 Templates API에서, 레이아웃 동작 원리(이어붙기 vs 새 페이지)는 레이아웃 동작 원리를 참고하세요. 갤러리 템플릿(다수 이미지 배치)은 갤러리 템플릿을 참고하세요.
Idempotency-Key 헤더로 중복 추가를 방지할 수 있습니다. 자세한 동작은 멱등성 가이드를 참고하세요.Request 예시
curl -X POST 'https://api-sandbox.sweetbook.com/v1/books/{bookUid}/contents?breakBefore=page' \
-H 'Authorization: Bearer {YOUR_API_KEY}' \
-F 'templateUid=46VqZhVNOfAp' \
-F 'photo=@image1.jpg' \
-F 'parameters={"monthNum":"04","dayNum":"14","diaryText":"오늘의 일기","photo":"$upload"}'curl -X POST 'https://api-sandbox.sweetbook.com/v1/books/{bookUid}/contents' \
-H 'Authorization: Bearer {YOUR_API_KEY}' \
-F 'templateUid=46VqZhVNOfAp' \
-F 'parameters={"monthNum":"04","dayNum":"14","diaryText":"오늘의 일기","photo":"https://example.com/photo.jpg"}'curl -X POST 'https://api-sandbox.sweetbook.com/v1/books/{bookUid}/contents' \
-H 'Authorization: Bearer {YOUR_API_KEY}' \
-F 'templateUid={GALLERY_TEMPLATE_UID}' \
-F 'parameters={"date":"2026-04-22","galleryPhotos":["https://example.com/1.jpg","https://example.com/2.jpg","https://example.com/3.jpg"]}'응답 필드
| 필드 | 타입 | 설명 |
|---|---|---|
result | string | 처리 결과. "inserted"(새 페이지 신규 추가) / "updated"(같은 페이지 범위 내 기존 콘텐츠가 있어 left→right로 이동하거나 교체되어 저장됨) |
breakBefore | string | 실제로 적용된 페이지 나누기 값 (요청 값 또는 템플릿별 기본값) |
pageNum | integer | 이번 콘텐츠가 배치된 페이지 번호 (1부터 시작) |
pageSide | string | 페이지 방향. "left" / "right" |
pageMeta | object | 페이지 제약 메타 객체. currentPageCount(누적 내지 페이지 수 — 제본 방식에 따라 계산, 같은 pageNum 안에서 left/right만 채우는 호출은 증가하지 않을 수 있음. 산출 방식 상세는 레이아웃 동작 원리 참고) + pageMin·pageMax·pageIncrement·isValid 필드 포함 |
Response 예시
{
"success": true,
"message": "내지가 생성되었습니다",
"data": {
"result": "inserted",
"breakBefore": "page",
"pageNum": 1,
"pageSide": "right",
"pageMeta": {
"currentPageCount": 1,
"pageMin": 24,
"pageMax": 200,
"pageIncrement": 1,
"isValid": false
}
}
}{
"success": true,
"message": "내지가 갱신되었습니다",
"data": {
"result": "updated",
"breakBefore": "none",
"pageNum": 2,
"pageSide": "right",
"pageMeta": {
"currentPageCount": 2,
"pageMin": 24,
"pageMax": 200,
"pageIncrement": 1,
"isValid": false
}
}
}HTTP 상태 코드
| 코드 | errorCode | 설명 |
|---|---|---|
| 200 OK | — | 같은 페이지 범위 내 기존 콘텐츠에 이어 배치되어 저장된 경우 (응답 메시지 Content updated successfully, result: "updated") |
| 201 Created | — | 새 페이지에 콘텐츠 신규 추가 (응답 메시지 Content created successfully, result: "inserted") |
| 400 Bad Request | ERR_VALIDATION_FAILED / ERR_CREATION_TYPE_UNSUPPORTED | templateUid 누락, 필수 이미지 파라미터 누락, parameters JSON 파싱 실패, 잘못된 breakBefore 값, 이미 최종화된 책("이미 최종화된 책입니다. 콘텐츠를 추가할 수 없습니다."), 삭제된 책, PDF_UPLOAD/MIX_COVER_TEMPLATE 책 등 |
| 401 Unauthorized | ERR_UNAUTHORIZED | 인증 실패 |
| 404 Not Found | ERR_NOT_FOUND | 책 또는 템플릿 없음 |
| 429 Too Many Requests | ERR_TOO_MANY_REQUESTS | 업로드 Rate Limit 초과 — Rate Limiting 가이드 참고 |
| 500 Internal Server Error | ERR_INTERNAL_ERROR | 서버 오류 |
본 엔드포인트의 주요 검증 실패 메시지(400 ERR_VALIDATION_FAILED):
- 이미 최종화된 책 —
errors[0]:"이미 최종화된 책입니다. 콘텐츠를 추가할 수 없습니다." - 필수 이미지 파라미터 누락 —
errors[0]:"필수 이미지 파라미터 '<name>' (<설명>)이 제공되지 않았습니다. form-data에 파일을 첨부하거나 parameters에 URL 또는 서버 파일명을 제공해야 합니다." - 간지/발행면 템플릿에 잘못된
breakBefore—errors[0]:"template_kind='divider'인 특수 페이지에서는 breakBefore='none'를 사용할 수 없습니다. 'page'만 허용됩니다."
파라미터 이름과 설명은 템플릿에 따라 달라집니다. Templates API에서 해당 템플릿의 필수 변수 목록을 먼저 확인하세요. 간지(templateKind=divider)·발행면(templateKind=publish) 템플릿은 breakBefore를 생략하거나 page만 명시해야 합니다. 일반 내지(templateKind=content)는 세 값 모두 허용됩니다. 응답 6필드 shape, 다른 errorCode, 처리 가이드는 에러 코드 & 트러블슈팅을 참조하세요.
책 최종화
/books/{bookUid}/finalization표지·콘텐츠(내지) 추가를 마친 뒤 이 엔드포인트를 호출해 책을 최종화합니다. 호출 시 책의 status가 draft에서 finalized로 전환되어 주문 가능 상태가 됩니다.
pageMin·pageMax·pageIncrement)을 충족해야 합니다.전환 결과: 호출 성공 시
status가 draft → finalized로 전환됩니다 (PDF 렌더링은 시스템이 비동기로 처리). 책의 pdfStatus는 PDF 렌더링이 완료되면 2(COMPLETED)로 갱신됩니다.Request
요청 본문은 비어 있습니다. 다만 IIS 환경 특성상 Content-Length: 0 헤더가 필요합니다 (없으면 411 Length Required).
Request 예시
curl -X POST 'https://api-sandbox.sweetbook.com/v1/books/{bookUid}/finalization' \
-H 'Authorization: Bearer {YOUR_API_KEY}' \
-H 'Content-Length: 0'응답 필드
| 필드 | 타입 | 설명 |
|---|---|---|
result | string | 처리 결과 메시지 (아래 result 값 조건 표 참고) |
pageMeta | object | 페이지 제약 메타. currentPageCount(최종화된 책의 내지 페이지 수, 콘텐츠 추가 결과로 자동 산출) + pageMin·pageMax·pageIncrement·isValid 필드 포함 |
finalizedAt | datetime | 최종화 완료 시각 (ISO 8601) |
result 값 조건
| 값 | 발생 조건 |
|---|---|
"페이지를 추가하고 완료" | 제본 방식 PUR이며 마지막 페이지가 자동 추가되어 finalize 완료된 경우 |
"페이지를 추가하지 않고 완료" | 제본 방식 PUR이며 마지막 페이지가 이미 있어 추가 없이 finalize 완료된 경우 |
"완료" | 제본 방식이 PUR이 아닌 경우 (일반 finalize 완료) |
"updated" | 이미 finalized 상태인 책에 finalize를 다시 호출한 경우 (멱등 응답). 실제 상태는 재변경되지 않음 |
파트너는 result 문자열 자체보다 응답 상태 코드(2xx)와 pageMeta.currentPageCount/finalizedAt 값으로 성공 여부를 확인하는 것을 권장합니다.
Response 예시
{
"success": true,
"message": "책 최종화 완료",
"data": {
"result": "페이지를 추가하고 완료",
"pageMeta": {
"currentPageCount": 26,
"pageMin": 24,
"pageMax": 200,
"pageIncrement": 1,
"isValid": true
},
"finalizedAt": "2026-04-14T07:15:44.613Z"
}
}{
"success": true,
"message": "이미 최종화된 책입니다",
"data": {
"result": "updated",
"pageMeta": {
"currentPageCount": 26,
"pageMin": 24,
"pageMax": 200,
"pageIncrement": 1,
"isValid": true
},
"finalizedAt": "2026-04-14T07:15:44.613Z"
}
}전제조건별 에러코드 매핑
finalize 호출 시 전제조건을 충족하지 못하면 아래 표대로 errorCode + fieldErrors가 반환됩니다. 클라이언트는 fieldErrors[].field·fieldErrors[].constraint로 누락 항목을 식별해 사용자에게 안내하세요.
| 전제조건 | errorCode | fieldErrors[].field | constraint |
|---|---|---|---|
| 책이 DRAFT 상태가 아님 | ERR_FINALIZE_PREREQ_UNMET | status | enum |
| 내지 콘텐츠 미추가 (0건) | ERR_FINALIZE_PREREQ_UNMET | contents | required |
페이지 수 < pageMin | ERR_INSUFFICIENT_PAGES | pageCount | min |
페이지 수 > pageMax | ERR_PAGECOUNT_INVALID | pageCount | max |
| 페이지 증분 규칙 위반 | ERR_PAGECOUNT_INVALID | pageCount | increment |
여러 전제조건이 동시에 깨지면 fieldErrors에 항목들이 함께 반환됩니다. 응답 예시는 위 "주요 에러 응답"과 페이지 제약 위반 에러 섹션을 참조하세요.
pageMeta.isValid 사용 시 주의:isValid는 페이지 수 제약(pageMin·pageMax·pageIncrement)만 판정합니다.- 내지 콘텐츠 추가 여부, 책 상태(DRAFT 여부) 등 다른 전제조건은 finalize 호출 시 별도로 검증되므로
isValid: true여도ERR_FINALIZE_PREREQ_UNMET이 반환될 수 있습니다. - finalize 가능 여부 최종 확정은
POST /finalization호출 결과로만 가능합니다.isValid는 사전 UI 안내(예: "아직 N페이지 부족") 용도로만 사용하세요.
HTTP 상태 코드
| 코드 | errorCode | 설명 |
|---|---|---|
| 200 OK | — | 이미 finalized 상태의 책에 재호출한 경우 (멱등 응답, message: "이미 최종화된 책입니다", result: "updated") |
| 201 Created | — | 최종화 신규 성공 |
| 400 Bad Request | ERR_FINALIZE_PREREQ_UNMET / ERR_INSUFFICIENT_PAGES / ERR_PAGECOUNT_INVALID | 전제조건 미충족 (위 매핑 표 참고) |
| 401 Unauthorized | ERR_UNAUTHORIZED | 인증 실패 |
| 404 Not Found | ERR_NOT_FOUND | 책 없음 |
| 411 Length Required | — | Content-Length: 0 헤더 누락 |
| 500 Internal Server Error | ERR_INTERNAL_ERROR | 서버 오류 |
book.pdfStatus 값
책 조회(GET /books) 응답의 pdfStatus 필드는 PDF 처리 상태를 나타내는 정수값입니다. TEMPLATE 방식은 finalize 후 시스템이 PDF를 비동기 렌더링하므로, finalize 직후엔 1(PENDING) 상태에서 2(COMPLETED)로 전환됩니다. 파트너는 일반적으로 책의 status 필드 또는 주문 상태 흐름의 PDF_READY 전환을 기준으로 처리하면 충분합니다.
| 값 | 의미 | 발생 시점 |
|---|---|---|
null | 미생성 (초기 상태) | 책 생성 직후 또는 콘텐츠만 추가한 상태 (finalize 미호출) |
1 | PENDING (PDF 렌더링 대기) | finalize 호출 직후 (시스템이 PDF 렌더링을 시작한 상태) |
2 | COMPLETED (PDF 준비 완료) | 시스템이 PDF 렌더링을 완료한 시점. 이 시점부터 주문 아이템이 PDF_READY(25)로 자동 승격됨 |
9 | FAILED (처리 실패) | PDF 렌더링 실패 시 (드물게 발생). 발생 시 책을 다시 점검하거나 콘텐츠를 수정하여 재 finalize 시도 |
본 엔드포인트의 finalize 특화 에러:
- 콘텐츠 미추가 상태에서 finalize 호출 —
400 ERR_FINALIZE_PREREQ_UNMET,fieldErrors[0].field: "contents"·constraint: "required".POST /books/{bookUid}/contents로 최소 1개 이상의 내지를 추가한 뒤 finalize를 호출하세요. - 페이지 수 규칙 위반 — 판형의
pageMin/pageMax/pageIncrement검증. 응답 예시는 아래 페이지 제약 위반 에러 섹션을 참조하세요.
응답 6필드 shape, 다른 errorCode, 처리 가이드는 에러 코드 & 트러블슈팅을 참조하세요.
이미지 처리
템플릿 표지·내지 추가 시 사용할 이미지를 어떻게 전달하고, 어떤 제약이 있는지 다룹니다. 본 묶음은 표지(POST /cover)·내지(POST /contents) 추가 단계의 사전 정보입니다.
이미지 전달 방식 (3가지, 혼용 가능)
표지·내지 추가 요청에서 이미지는 다음 3가지 방식 중 어느 것으로든 제공할 수 있고, 한 요청에서 혼용할 수도 있습니다. 템플릿의 이미지 필드명($변수명$)과 요청 필드명이 일치해야 합니다.
| 방식 | 전달 위치 | 적합한 상황 |
|---|---|---|
| ① multipart 파일 직접 첨부 | multipart/form-data의 파일 필드 (예: frontPhoto=@front.jpg) | 한 페이지에 1~2장 이미지를 즉시 업로드할 때 |
| ② URL 전달 | parameters JSON 안에 이미지 URL 문자열 (예: "frontPhoto": "https://...") | 이미지가 외부 호스팅(또는 파트너 CDN)에 이미 있는 경우 |
| ③ 사전 업로드한 서버 파일명 참조 | parameters JSON에 서버가 발급한 파일명 (예: photo250105143052123.JPG) | 여러 페이지에 같은 이미지를 반복 사용하거나, 다수 이미지를 미리 일괄 업로드해 두는 경우 (아래 사진 사전 업로드 섹션 사용) |
혼합 방식과 순서 제어 ($upload 플레이스홀더)
한 요청에서 위 3가지 방식을 섞어 쓸 수 있습니다. parameters의 배열 필드에 $upload 플레이스홀더를 넣으면 multipart로 첨부한 파일이 해당 위치에 차례로 들어갑니다.
{
"photos": [
"$upload",
"https://example.com/photo2.jpg",
"photo250105143052123.JPG",
"$upload"
]
}위 예시는 첫 번째 업로드 파일 → URL 이미지 → 사전 업로드한 서버 파일 → 두 번째 업로드 파일 순으로 배치됩니다. multipart로 첨부한 파일이 $upload 등장 순서대로 매핑됩니다.
EXIF 정보
업로드된 이미지의 EXIF 정보는 항상 보존됩니다. EXIF 보존 여부를 제어하는 별도 파라미터는 제공하지 않습니다.
파일 업로드 제한 (이미지)
표지·내지 추가 요청의 multipart 파일 첨부, 사진 사전 업로드, URL 다운로드 모두에 동일한 이미지 제약이 적용됩니다.
| 항목 | 제한 |
|---|---|
| 파일당 최대 크기 | 50MB |
| 지원 포맷 | JPEG, PNG, GIF, WebP, BMP, HEIC, HEIF |
| 업로드 Rate Limit | upload 정책 (API Key 단위 200 req/분) |
| URL 다운로드 타임아웃 | 10초 (응답 없으면 400) |
파일 검증
- 매직 바이트 검증: 파일 확장자뿐만 아니라 매직 바이트(파일 시그니처)를 확인하여 실제 이미지 파일인지 검증합니다. 확장자만 변경한 파일은 거부됩니다.
- 자동 포맷 변환: GIF·WebP는 PNG로, BMP·HEIC·HEIF는 JPG로 자동 변환되어 저장됩니다.
- EXIF 보존: EXIF 정보는 항상 보존됩니다.
Rate Limit 초과 시 429 응답과 Retry-After 헤더가 반환됩니다. 자세한 정책은 Rate Limiting 가이드를 참고하세요.
사진 사전 업로드 [선택]
이미지를 표지·내지 추가 요청에 직접 첨부하지 않고 미리 업로드해 서버 파일명을 받아두는 보조 API입니다.표지/내지 추가 요청에 이미지를 직접 첨부(방식 ①)하거나 URL로 전달(방식 ②)한다면 이 단계는 생략 가능합니다. 여러 페이지에 같은 이미지를 반복 사용하거나, 다수 이미지를 한 번에 모아 업로드해두고 싶을 때 활용하세요.
호출 도메인 기준
사진 관련 4개 엔드포인트는 모두 API Key의 환경(Sandbox/Live)과 호출 도메인이 일치해야 합니다. 잘못된 조합으로 호출 시 403 ERR_ENV_MISMATCH가 반환됩니다.
| 환경 | 도메인 | 접근 가능 리소스 |
|---|---|---|
| Sandbox | api-sandbox.sweetbook.com | 샌드박스(isTest=true) 책·사진 |
| Live | api.sweetbook.com | 라이브(isTest=false) 책·사진 |
권한 매트릭스
파트너 관점에서 사진 4개 엔드포인트의 호출 가능 여부입니다.
| 액션 | 본인 책 | 환경 불일치 |
|---|---|---|
업로드 POST /photos | ✅ 201 | ❌ 403 ERR_ENV_MISMATCH |
목록 GET /photos | ✅ 200 | ❌ 403 ERR_ENV_MISMATCH |
다운로드 GET /photos/{fileName} | ✅ 200 | ❌ 403 ERR_ENV_MISMATCH |
삭제 DELETE /photos/{fileName} | ✅ 204 | ❌ 403 ERR_ENV_MISMATCH |
사진 업로드
/books/{bookUid}/photos한 번에 한 장씩 업로드하며, 응답으로 서버가 발급한 고유 파일명을 받습니다. 이후 표지·내지 추가 요청의 parameters에 이 파일명을 사용해 이미지를 참조합니다.
Request — multipart/form-data
| 필드 | 위치 | 타입 | 필수 | 설명 |
|---|---|---|---|---|
bookUid | path | string | O | 대상 책 UID |
file | form-data | file | O | 업로드할 이미지 파일 (한 번에 1장) |
제약 사항
- 파일 크기: 50MB 이하 (초과 시 400)
- 책당 최대 200장: 한 책에 사전 업로드할 수 있는 사진은 최대 200장입니다. 초과 전에 사진 목록 조회로 현재 수량을 확인하세요
- 책 상태 제약:
draft상태의 책에만 업로드 가능합니다.finalized(최종화) 또는deleted(삭제) 상태의 책에는 업로드할 수 없습니다 — 최종화 전에 필요한 사진을 모두 업로드하세요 - 지원 포맷: JPEG · PNG · GIF · WebP · BMP · HEIC · HEIF — 그 외 형식은 400 거부. 매직 바이트로 실제 형식을 검증하므로 확장자만 바꾼 파일은 거부됨
Request 예시
curl -X POST 'https://api-sandbox.sweetbook.com/v1/books/{bookUid}/photos' \
-H 'Authorization: Bearer {YOUR_API_KEY}' \
-F 'file=@photo1.jpg'응답 필드
| 필드 | 타입 | 설명 |
|---|---|---|
fileName | string | 서버가 발급한 고유 파일명. 표지·내지 추가 요청의 parameters에 이 값을 사용해 이미지를 참조하거나, 사진 다운로드 URL 경로에 직접 사용 |
originalName | string | 업로드한 원본 파일명 |
size | integer | 저장된 파일 크기 (bytes) |
mimeType | string | MIME 타입 (예: image/jpeg, image/png) |
uploadedAt | datetime | 업로드 완료 시각 (ISO 8601) |
isDuplicate | boolean | 같은 책에 동일 파일(해시 기준)이 이미 업로드되어 있던 경우 true. 이때 fileName은 기존 파일의 파일명을 반환 |
hash | string | 파일 내용의 MD5 해시값 (중복 검사에 사용됨) |
Response 예시
{
"success": true,
"message": "Photo uploaded successfully",
"data": {
"fileName": "photo260423001516528.JPG",
"originalName": "cover.jpg",
"size": 382229,
"mimeType": "image/jpeg",
"uploadedAt": "2026-04-23T00:15:19.136Z",
"isDuplicate": false,
"hash": "1baf5077ae9f5a13787a73a08625a802"
}
}HTTP 상태 코드
| 코드 | errorCode | 설명 |
|---|---|---|
| 201 Created | — | 업로드 성공 (응답에 서버 파일명 포함) |
| 400 Bad Request | ERR_VALIDATION_FAILED | 파일 누락, 지원되지 않는 파일 형식, 50MB 초과 등 |
| 400 Bad Request | ERR_CREATION_TYPE_UNSUPPORTED | PDF_UPLOAD 타입 책에 사진 업로드 시도 — 사진 업로드는 TEMPLATE 또는 MIX_COVER_TEMPLATE 방식에서만 지원 |
| 401 Unauthorized | ERR_UNAUTHORIZED | 인증 실패 |
| 403 Forbidden | ERR_FORBIDDEN | 본인 소유가 아닌 책 |
| 403 Forbidden | ERR_ENV_MISMATCH | 호출 도메인과 API Key의 환경(Sandbox/Live) 불일치 — 호출 도메인 기준 참고 |
| 404 Not Found | ERR_NOT_FOUND | 책 없음 |
| 500 Internal Server Error | ERR_INTERNAL_ERROR | 서버 오류 |
본 엔드포인트의 주요 검증 실패 메시지:
400 ERR_VALIDATION_FAILED지원되지 않는 파일 형식 —errors[0]:"지원되지 않는 파일 형식입니다: <파일명>. (확장자: <확장자>)"400 ERR_VALIDATION_FAILED파일 크기 초과 —errors[0]:"파일 크기가 50MB를 초과합니다"400 ERR_VALIDATION_FAILED파일 누락 —errors[0]:"파일이 없습니다"400 ERR_CREATION_TYPE_UNSUPPORTEDPDF_UPLOAD 타입 책에 사진 업로드 시도 —errors[0]:"PDF_UPLOAD 타입 책에서는 지원하지 않는 API입니다."403 ERR_ENV_MISMATCH환경 불일치 —errors[0]:"환경 불일치: 호출 도메인과 API Key의 환경(sandbox/live)이 일치하지 않습니다. 키에 맞는 도메인으로 재시도하세요."
응답 6필드 shape, 다른 errorCode, 처리 가이드는 에러 코드 & 트러블슈팅을 참조하세요.
사진 목록 조회
/books/{bookUid}/photos해당 책에 사전 업로드한 사진 파일명 목록을 조회합니다.
Request 예시
curl -X GET 'https://api-sandbox.sweetbook.com/v1/books/{bookUid}/photos' \
-H 'Authorization: Bearer {YOUR_API_KEY}'응답 필드
| 필드 | 타입 | 설명 |
|---|---|---|
data | array | 업로드된 사진 항목 배열 (아래 항목 필드 참고). list envelope 평탄화 적용 (이전 data.photos → data) |
pagination.total | integer | 업로드된 사진 총 개수 (이전 data.totalCount → pagination.total로 이전) |
사진 항목 필드 (data[])
| 필드 | 타입 | 설명 |
|---|---|---|
fileName | string | 서버가 발급한 고유 파일명. 표지·내지 추가 요청의 parameters 또는 사진 다운로드 URL에 사용 |
originalName | string | 원본 파일명 |
size | integer | 파일 크기 (bytes) |
mimeType | string | MIME 타입 |
uploadedAt | datetime | 업로드 시각 (ISO 8601) |
hash | string | 파일 내용 MD5 해시값 |
Response 예시
{
"success": true,
"message": "Success",
"data": [
{
"fileName": "photo260423001516528.JPG",
"originalName": "cover.jpg",
"size": 382229,
"mimeType": "image/jpeg",
"uploadedAt": "2026-04-23T00:15:18.977Z",
"hash": "1baf5077ae9f5a13787a73a08625a802"
}
],
"pagination": {
"total": 1,
"limit": 100,
"offset": 0,
"hasNext": false
}
}HTTP 상태 코드
| 코드 | errorCode | 설명 |
|---|---|---|
| 200 OK | — | 조회 성공 (사진이 없으면 data 빈 배열 + pagination.total=0) |
| 401 Unauthorized | ERR_UNAUTHORIZED | 인증 실패 |
| 403 Forbidden | ERR_FORBIDDEN | 본인 소유가 아닌 책 |
| 403 Forbidden | ERR_ENV_MISMATCH | 호출 도메인과 API Key의 환경(Sandbox/Live) 불일치 — 호출 도메인 기준 참고 |
| 404 Not Found | ERR_NOT_FOUND | 책 없음 |
사진 삭제
/books/{bookUid}/photos/{fileName}사전 업로드한 사진을 삭제합니다. 응답 본문 없이 204 No Content를 반환합니다.
Path 파라미터
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
bookUid | string | O | 대상 책 UID |
fileName | string | O | 삭제할 사진의 서버 파일명 (업로드 응답의 fileName) |
Request 예시
curl -X DELETE 'https://api-sandbox.sweetbook.com/v1/books/{bookUid}/photos/photo250105143052123.JPG' \
-H 'Authorization: Bearer {YOUR_API_KEY}'HTTP 상태 코드
| 코드 | errorCode | 설명 |
|---|---|---|
| 204 No Content | — | 삭제 성공 (응답 본문 없음) |
| 400 Bad Request | ERR_VALIDATION_FAILED | bookUid 또는 fileName 형식 오류 |
| 401 Unauthorized | ERR_UNAUTHORIZED | 인증 실패 |
| 403 Forbidden | ERR_FORBIDDEN | 본인 소유가 아닌 책 |
| 403 Forbidden | ERR_ENV_MISMATCH | 호출 도메인과 API Key의 환경(Sandbox/Live) 불일치 — 호출 도메인 기준 참고 |
| 404 Not Found | ERR_NOT_FOUND | 책 또는 파일 없음 |
| 409 Conflict | ERR_CONFLICT | 책이 이미 최종화(finalized)된 상태 — 최종화 이후에는 사진 삭제가 차단됩니다 |
사진 다운로드
/books/{bookUid}/photos/{fileName}업로드한 사진의 800px 썸네일 이미지 바이트를 반환합니다. 긴 변 기준으로 800px로 리사이즈된 썸네일이며, 원본(4000px)은 본 API로 제공되지 않습니다(내부 PDF 렌더링·인쇄 용도로만 사용). 업로드 정상 처리 여부 확인이나 사진 미리보기 UI 구성 용도로 사용하세요.
<img src>에 직접 사용 불가합니다. 인증 헤더를 붙일 수 없기 때문입니다. 파트너 백엔드가 받아 자체 시스템에 저장·프록시해 노출하는 흐름을 권장합니다.Path 파라미터
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
bookUid | string | O | 대상 책 UID |
fileName | string | O | 다운로드할 사진의 서버 파일명 |
Request 예시
curl 'https://api-sandbox.sweetbook.com/v1/books/{bookUid}/photos/photo260424005709732.PNG' \
-H 'Authorization: Bearer {YOUR_API_KEY}' \
--output photo.png응답 헤더
| 헤더 | 값 예시 | 설명 |
|---|---|---|
Content-Type | image/jpeg · image/png · image/webp 등 | 저장된 원본의 MIME 타입 |
Content-Length | 58217 | 썸네일 바이트 크기 |
응답 본문
800px 썸네일 이미지 바이트 (바이너리). curl --output이나 파일 스트림으로 저장해 사용하세요.
Response 예시
HTTP/1.1 200 OK
Content-Type: image/png
Content-Length: 58217
<binary image bytes — 800px 썸네일>HTTP 상태 코드
| 코드 | errorCode | 설명 |
|---|---|---|
| 200 OK | — | 다운로드 성공 (Content-Type: image/* + 이미지 바이트) |
| 400 Bad Request | ERR_VALIDATION_FAILED | bookUid 또는 fileName 형식 오류 |
| 401 Unauthorized | ERR_UNAUTHORIZED | 인증 실패 |
| 403 Forbidden | ERR_FORBIDDEN | 본인 소유가 아닌 책 |
| 403 Forbidden | ERR_ENV_MISMATCH | 호출 도메인과 API Key의 환경(Sandbox/Live) 불일치 — 호출 도메인 기준 참고 |
| 404 Not Found | ERR_NOT_FOUND | 책 또는 파일 없음 (errors: ["사진을 찾을 수 없습니다"] — 예: 삭제된 파일명) |
404 ERR_NOT_FOUND: 파일 없음 (삭제된 fileName 등) — errors[0]: "사진을 찾을 수 없습니다". 응답 shape 상세는 에러 코드 & 트러블슈팅 — ERR_NOT_FOUND를 참조하세요.
PDF 다운로드
책이 최종화되어 시스템이 표지·내지를 PDF로 렌더링한 뒤에는 다음 두 엔드포인트로 인쇄용 PDF를 다운로드할 수 있습니다.
GET /books/{bookUid}/pdf-cover— 표지 PDFGET /books/{bookUid}/pdf-contents— 내지 PDF
POST /finalization 호출 직후에는 PDF가 아직 준비되지 않았을 수 있으며, 응답이 pdfStatus에 따라 분기됩니다 — 일정 시간 후 재시도해야 정상 다운로드가 가능합니다.정상 응답은 JSON이 아닌 application/pdf 바이너리 스트림입니다. 그 외 케이스는 6필드 JSON 에러 응답으로 errorCode·errors·fieldErrors가 포함됩니다.
curl -o cover.pdf \
'https://api-sandbox.sweetbook.com/v1/books/{bookUid}/pdf-cover' \
-H 'Authorization: Bearer {YOUR_API_KEY}'curl -o contents.pdf \
'https://api-sandbox.sweetbook.com/v1/books/{bookUid}/pdf-contents' \
-H 'Authorization: Bearer {YOUR_API_KEY}'응답 매트릭스 (그룹 B)
TEMPLATE 책의 PDF 다운로드는 책 상태(pdfStatus)에 따라 다음과 같이 분기됩니다. 클라이언트는 errorCode로 분기하며 errors[0]의 한글 메시지를 사용자에게 보여줄 수 있습니다.
| 책 상태 | HTTP | 응답 형식 | errorCode | 클라이언트 권장 행동 |
|---|---|---|---|---|
| 책 최종화 전 (PDF 생성 미시작) | 409 | JSON | ERR_PDF_NOT_GENERATED | POST /books/{bookUid}/finalization 호출 후 재시도 |
| PDF 생성 진행 중 | 409 | JSON | ERR_PDF_PENDING | 일정 간격(수 초~수십 초) 후 재시도. 무한 폴링 금지. Retry-After 헤더는 본 응답에 포함되지 않으므로 클라이언트가 자체 대기 간격을 결정해야 합니다. |
| PDF 생성 실패 | 422 | JSON | ERR_PDF_GENERATION_FAILED | 클라이언트 자체 해결 불가 — 사용자 안내 + 고객지원팀 문의 |
| 생성 완료 + 파일 부재 (서버 결함) | 500 | JSON | ERR_PDF_FILE_MISSING | 서버 측 결함 — 고객지원팀 문의 |
| 생성 완료 + 파일 존재 | 200 | application/pdf 바이너리 스트림 | — | 응답 본문을 PDF 파일로 저장 |
공통 사전 검증
| 케이스 | HTTP | errorCode |
|---|---|---|
| 책 미존재 | 404 | ERR_NOT_FOUND |
| 본인 소유가 아닌 책 | 403 | ERR_FORBIDDEN |
| 환경 불일치 (Sandbox/Live 도메인 ↔ 책의 환경 불일치) | 403 | ERR_ENV_MISMATCH |
kind 경로 오류 (/pdf-cover·/pdf-contents 외 호출) | 400 | ERR_MALFORMED_REQUEST |
책의 creationType이 PDF 조회를 지원하지 않음 | 400 | ERR_CREATION_TYPE_UNSUPPORTED |
그룹 B 분기 응답 예시: 409 ERR_PDF_NOT_GENERATED (최종화 전) · 409 ERR_PDF_PENDING (생성 진행 중) · 422 ERR_PDF_GENERATION_FAILED (생성 실패) · 500 ERR_PDF_FILE_MISSING (서버 결함). 처리 가이드 포함 종합 안내는 에러 코드 & 트러블슈팅 — PDF 다운로드 분기를 참조하세요.
책 목록 조회
/books파트너가 생성한 책 목록을 조회합니다. 다양한 쿼리 파라미터로 필터링할 수 있으며, 페이지네이션을 지원합니다. 응답에는 PDF 방식·템플릿 방식 책이 모두 포함되며, creationType 필드로 구분할 수 있습니다.
Query 파라미터
| 파라미터 | 타입 | 기본값 | 설명 |
|---|---|---|---|
bookUid | string | — | 특정 책 UID로 단건 조회 |
status | string | — | 책 상태 필터. draft / finalized / deleted(일반 파트너 조회 결과에서는 삭제된 책이 자동 제외되므로 빈 결과) |
pdfStatus | string | — | PDF 상태 필터. 숫자 값(1/2/9) 또는 null 문자열(PDF 미생성 책) 허용. TEMPLATE 방식은 finalize 후 PDF 렌더링 진행 중인 책(1)과 완료된 책(2)을 구분할 때 활용 |
specProfileUid | string | — | SpecProfile UID로 필터 |
createdFrom | string | — | 생성일 시작 (ISO 8601, 예: 2026-01-01) |
createdTo | string | — | 생성일 종료 (ISO 8601) |
limit | integer | 20 | 조회할 항목 수 (1~100) |
offset | integer | 0 | 건너뛸 항목 수 (≥0) |
페이지네이션 동작과 응답 구조(data.books 배열 + data.pagination 객체)는 페이지네이션 가이드를 참고하세요.
응답 필드
| 필드 | 타입 | 설명 |
|---|---|---|
bookUid | string | 책 고유 UID |
accountUid | string | 책 소유 계정 UID |
title | string | 책 제목 |
author | string | null | 저자명 (선택) |
status | string | 책 상태 — enum 문자열로 반환. "draft"(작성 중, 내부값 1) / "finalized"(최종화 완료, 내부값 2) / "deleted"(삭제됨, 내부값 9) |
pageCount | integer | 내지 페이지 수. TEMPLATE은 콘텐츠 추가 결과로 자동 산출 (finalize 시점에 확정), PDF 방식은 책 생성 시 지정한 값 |
bookSpecUid | string | 판형 UID |
specProfileUid | string | null | SpecProfile UID |
creationType | string | TEMPLATE / PDF_UPLOAD / MIX_COVER_TEMPLATE |
createdAt | datetime | 책 생성 시각 (ISO 8601) |
updatedAt | datetime | 마지막 수정 시각 |
externalRef | string | null | 파트너 외부 참조 식별자 |
isTest | boolean | Sandbox 환경 책 여부 |
pdfStatus | integer | null | PDF 처리 상태 (정수). null(미생성) / 1(PENDING, 렌더링 대기) / 2(COMPLETED, 준비 완료) / 9(FAILED, 실패). 자세한 의미는 위 책 최종화 → book.pdfStatus 값 표 참고. TEMPLATE 방식은 finalize 직후 1을 거쳐 2로 전환됩니다 (PDF 방식은 즉시 2) |
pdfCreatedAt | datetime | null | PDF 파일이 마지막으로 갱신된 시각 |
pdfRequestedAt | datetime | null | 시스템이 PDF 렌더링 큐에 요청을 등록한 시각. TEMPLATE 방식은 finalize 호출 직후 시스템이 내부적으로 갱신하며, PDF 방식은 일반적으로 null을 유지합니다. 파트너가 직접 제어하는 필드가 아닙니다 |
thumbnailStatus | integer | null | 책 페이지 썸네일 처리 상태. null(NONE, 미생성) / 1(PENDING, 생성 진행 중) / 2(COMPLETED, 생성 완료) / 9(FAILED, 생성 실패) |
Response 예시
{
"success": true,
"message": "성공",
"data": [
{
"bookUid": "bk_2dyG********",
"accountUid": "u_b4b9********************",
"title": "템플릿 방식 책",
"author": null,
"status": "draft",
"pageCount": 0,
"bookSpecUid": "SQUAREBOOK_HC",
"specProfileUid": null,
"creationType": "TEMPLATE",
"createdAt": "2026-04-22T05:06:05.989Z",
"updatedAt": "2026-04-22T05:06:05.989Z",
"externalRef": null,
"isTest": true,
"pdfStatus": null,
"pdfCreatedAt": null,
"pdfRequestedAt": null,
"thumbnailStatus": null
},
{
"bookUid": "bk_2h4L********",
"title": "PDF 업로드 샘플",
"status": "finalized",
"creationType": "PDF_UPLOAD",
"pageCount": 24,
"pdfStatus": 2,
"pdfCreatedAt": "2026-04-22T07:46:24.000Z"
/* ... 나머지 필드 생략 ... */
}
],
"pagination": {
"total": 15,
"limit": 5,
"offset": 0,
"hasNext": true
}
}HTTP 상태 코드
| 코드 | errorCode | 설명 |
|---|---|---|
| 200 OK | — | 조회 성공 |
| 400 Bad Request | ERR_VALIDATION_FAILED | limit/offset 범위 위반 등 파라미터 오류 |
| 401 Unauthorized | ERR_UNAUTHORIZED | 인증 실패 |
| 500 Internal Server Error | ERR_INTERNAL_ERROR | 서버 오류 |
책 단건 조회
/books/{bookUid}특정 책의 상세 정보를 조회합니다. v1.2에 신설된 RESTful 단건 조회 엔드포인트로, 편집 화면 진입이나 현재 페이지 수 제약 확인에 사용합니다. 응답에 pageMeta가 포함되어 "아직 N페이지 부족" 같은 힌트를 UI에 즉시 반영할 수 있습니다.
Path 파라미터
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
bookUid | string | O | 조회할 책 UID |
Request 예시
curl -X GET 'https://api-sandbox.sweetbook.com/v1/books/{bookUid}' \
-H 'Authorization: Bearer {YOUR_API_KEY}'응답 필드
| 필드 | 타입 | 설명 |
|---|---|---|
bookUid | string | 책 UID |
accountUid | string | 책을 생성한 계정의 UID (파트너 본인 계정) |
title | string | 책 제목 |
bookSpecUid | string | 책 규격 UID |
bookSpecName | string | 규격 이름 (예: "A5 소프트커버 포토북") |
specProfileUid | string | null | SpecProfile UID (사용 시) |
creationType | string | TEMPLATE / PDF_UPLOAD / MIX_COVER_TEMPLATE |
status | integer | 1=작성 중(DRAFT) / 2=최종화 완료(FINALIZED). status가 1인 책은 주문을 생성할 수 없으며, POST /books/{bookUid}/finalization을 호출해 2로 전이해야 합니다. 목록 조회(GET /books)는 동일 값을 문자열("draft" / "finalized")로 반환합니다 |
coverTemplateUid | string | null | 템플릿 방식에서 바인딩된 표지 템플릿 UID. 표지 추가 전이나 PDF 방식은 null |
externalRef | string | null | 파트너 외부 참조 식별자 |
isTest | boolean | Sandbox 환경의 책이면 true |
pageMeta | object | 페이지 제약 메타. currentPageCount·pageMin·pageMax·pageIncrement·isValid 5개 필드 |
createdAt | datetime | 생성 시각 (ISO 8601) |
updatedAt | datetime | 최종 수정 시각 (ISO 8601) |
Response 예시
{
"success": true,
"message": "성공",
"data": {
"bookUid": "bk_3k2S********",
"accountUid": "u_b4b9********************",
"title": "일기장 샘플",
"bookSpecUid": "SQUAREBOOK_HC",
"bookSpecName": "고화질 스퀘어북 (하드커버)",
"specProfileUid": null,
"creationType": "TEMPLATE",
"status": 1,
"coverTemplateUid": "tpl_cover_abc",
"externalRef": "PARTNER-ORDER-001",
"isTest": true,
"pageMeta": {
"currentPageCount": 18,
"pageMin": 24,
"pageMax": 200,
"pageIncrement": 1,
"isValid": false
},
"createdAt": "2026-04-22T03:00:00.000Z",
"updatedAt": "2026-04-22T04:00:00.000Z"
}
}HTTP 상태 코드
| 상태 코드 | errorCode | 설명 |
|---|---|---|
| 200 OK | — | 조회 성공 |
| 401 Unauthorized | ERR_UNAUTHORIZED | 인증 실패 |
| 403 Forbidden | ERR_FORBIDDEN | 다른 파트너의 책 접근 시도 |
| 403 Forbidden | ERR_ENV_MISMATCH | Sandbox 도메인에서 Live 책 조회(또는 반대) |
| 404 Not Found | ERR_NOT_FOUND | 책 UID가 존재하지 않음 |
단건 조회 vs 목록 조회 (bookUid 필터) 차이
기존 목록 조회의 bookUid 필터(GET /books?bookUid=...)와 본 단건 조회는 의미·응답 타입·권한 처리가 다릅니다. 용도에 맞게 선택하세요.
| 항목 | GET /books/{uid} (단건) | GET /books?bookUid=... (목록 필터) |
|---|---|---|
| 의미론 | RESTful 리소스 단건 조회 | 목록 조회 + bookUid 동등 필터 (결과 0~1건) |
응답 data 타입 | 객체 | 배열 + pagination 메타 |
| 응답 필드 | 상세 필드 + pageMeta, bookSpecName, coverTemplateUid 등 편집 화면용 풀셋 | 목록용 요약 필드 (pageCount 유지, pageMeta 없음) |
| 결과 없을 때 | 404 ERR_NOT_FOUND | 200 + 빈 배열 |
| 다른 파트너의 책 | 403 ERR_FORBIDDEN | 200 + 빈 배열 (필터 결과) |
| 환경 불일치 (sandbox/live) | 403 ERR_ENV_MISMATCH | 빈 배열 (필터에 환경 적용) |
status 필드 타입 | 숫자 (1/2) | 문자열 ("draft"/"finalized") |
| 주 용도 | 책 편집 페이지 진입, 상세 패널 렌더링, finalize 전 상태 확인 | 목록/검색 UI, 페이지네이션, 여러 조건 조합 필터링 |
- 책 UID를 알고 있고 상세 정보(특히
pageMeta)가 필요하면 → 단건 조회 - 존재 여부만 빠르게 확인하거나 여러 조건과 조합해야 하면 → 목록 조회
- 없는 책과 권한 없는 책을 명확히 구별해야 하면 → 단건 조회 (목록은 둘 다 빈 배열로 동일)
404 ERR_NOT_FOUND: 존재하지 않는 bookUid — errors[0]: "책을 찾을 수 없습니다: bk_xxx". 응답 shape 상세는 에러 코드 & 트러블슈팅 — ERR_NOT_FOUND를 참조하세요.
페이지 제약 위반 에러
콘텐츠(내지) 추가·최종화 시 페이지 제약을 위반하면 아래 3종 에러 중 하나가 반환됩니다. fieldErrors[0].constraint로 어떤 제약이 위반됐는지 분기할 수 있습니다. 전체 에러 체계 상세는 에러 코드 & 트러블슈팅을 참고하세요.
ERR_INSUFFICIENT_PAGES(constraint: "min") — finalize 시점에 최소 페이지 미달ERR_PAGECOUNT_INVALID(constraint: "max") — 콘텐츠 추가·finalize 시점에 최대 페이지 초과ERR_PAGECOUNT_INVALID(constraint: "increment") — 증분 규칙 위반.requiredValue는{min, increment}객체 형태
응답 예시(fieldErrors 배열에 currentValue·requiredValue·constraint 포함)는 errors 페이지의 각 errorCode 카드를 참조하세요: ERR_INSUFFICIENT_PAGES, ERR_PAGECOUNT_INVALID.
책 삭제
/books/{bookUid}책을 삭제 처리합니다. 물리적 삭제가 아닌 소프트 삭제(상태값 변경)로 처리되어, 이후 목록 조회 결과에서 제외됩니다. 표지·콘텐츠 페이지·사전 업로드한 사진은 별도 정리되지 않고 보관 상태로 남으며, 책 자체에 대한 추가 작업(표지·콘텐츠 추가/수정/finalize/주문)은 모두 차단됩니다.
상태 제약 없음:
draft·finalized 어느 상태에서도 삭제 가능합니다 (단 본인 소유 책에 한함).Path 파라미터
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
bookUid | string | O | 삭제할 책 UID |
Request 예시
curl -X DELETE 'https://api-sandbox.sweetbook.com/v1/books/{bookUid}' \
-H 'Authorization: Bearer {YOUR_API_KEY}'응답 필드
| 필드 | 타입 | 설명 |
|---|---|---|
bookUid | string | 삭제된 책 UID |
status | string | 삭제 처리 결과 ("deleted") |
Response 예시
{
"success": true,
"message": "책이 삭제되었습니다",
"data": {
"bookUid": "bk_3k2S********",
"status": "deleted"
}
}HTTP 상태 코드
| 코드 | errorCode | 설명 |
|---|---|---|
| 200 OK | — | 삭제 성공 (이미 삭제된 책에 대한 재호출 포함) |
| 400 Bad Request | ERR_VALIDATION_FAILED | bookUid 형식 오류 |
| 401 Unauthorized | ERR_UNAUTHORIZED | 인증 실패 |
| 403 Forbidden | ERR_FORBIDDEN | 본인 소유가 아닌 책 |
| 404 Not Found | ERR_NOT_FOUND | 책 없음 |
| 500 Internal Server Error | ERR_INTERNAL_ERROR | 서버 오류 |
404 ERR_NOT_FOUND: 존재하지 않는 bookUid — 응답 shape 상세는 에러 코드 & 트러블슈팅 — ERR_NOT_FOUND를 참조하세요.