PDF 업로드 시나리오
파트너가 직접 제작한 PDF를 업로드해 책을 만들고 주문까지 완료하는 전체 흐름입니다. 표지·내지 PDF 업로드 후 POST /books/{bookUid}/finalization으로 책을 최종화하면 FINALIZED 상태가 되고, 주문 생성 시 즉시 PDF_READY 상태로 진입합니다.
개요
호출 시퀀스
- 책 생성 —
creationType=PDF_UPLOAD,pageCount지정 - 표지 PDF 업로드 + 내지 PDF 업로드 (순서 무관)
- 책 최종화 —
POST /books/{bookUid}/finalization호출로 책을 FINALIZED 상태로 전환 - 주문 생성 — finalize 후 주문 시 즉시
PDF_READY상태 진입 - 주문 상태 추적 — 웹훅으로 배송 진행 수신
사용 케이스
이미 자체 편집 도구로 PDF를 직접 제작하고 있거나, 템플릿 기반 렌더링 없이 파트너 쪽에서 최종 레이아웃을 제어하고 싶을 때 사용합니다.
예시 환경
이 페이지의 모든 curl 예시는 아래 값을 기준으로 작성되어 있습니다. 코드 블록 우측 상단의 Sandbox / Live 탭으로 환경이 전환됩니다.
복붙해서 실행할 때는 {YOUR_API_KEY}를 본인 API Key로, {bookUid} 플레이스홀더를 실제 값으로 교체하세요.
| 항목 | 예시 값 |
|---|---|
판형 UID (bookSpecUid) | SQUAREBOOK_HC (하드커버 243×248mm) |
페이지 수 (pageCount) | 24 |
| 표지 PDF | hardcover24.pdf (544×288mm, 24p 기준) |
| 내지 PDF | hardcontents24.pdf (249×254mm, 24p) |
PDF 준비 요건
업로드 시 PDF 크기·페이지 수·파일 무결성이 동기 검증됩니다. 검증 실패 시 400 에러로 업로드가 차단됩니다.
판형별 PDF 규격
이 페이지의 예시는 SQUAREBOOK_HC(하드커버) 기준 고정 규격을 사용합니다 (위 예시 환경 블록 참조). 다른 판형의 PDF 규격은 파트너 포털에서 확인하세요. 커버 타입(하드/소프트)에 따라 규격 규칙이 다릅니다.
| 커버 타입 | 표지 규격 | 내지 규격 |
|---|---|---|
| 소프트커버 | 고정 크기 (단일 객체) | 고정 크기 |
| 하드커버 | 페이지 수 범위별 (배열) — 책등 너비에 따라 가변 | 고정 크기 |
허용 오차
| 항목 | 허용 오차 |
|---|---|
| 소프트커버 표지 (너비·높이 공통) | ±1mm |
| 하드커버 표지 너비 (width) | ±2mm |
| 하드커버 표지 높이 (height) | ±1mm |
| 내지 크기 (너비·높이 공통) | ±1mm |
제본 타입별 내지 PDF 형식
| 제본 타입 | 내지 PDF 형식 | 업로드 PDF 페이지수 |
|---|---|---|
PUR (예: SQUAREBOOK_HC, PHOTOBOOK_A4_SC) | 단면 (page-by-page) | book.pageCount 그대로 |
LAYFLAT (예: SQUAREBOOK_LAYFLAT_HC) | 펼침면 (spread, 좌·우 펼침) | book.pageCount / 2 |
※ 표지 PDF는 제본 타입과 관계없이 항상 펼침면 1페이지(앞표지 + 책등 + 뒤표지 한 장)입니다.book.pageCount·bookSpec.pageMin·bookSpec.pageMax·bookSpec.pageIncrement는 모두 책 페이지 단위로 저장됩니다. 업로드 검증 시점에만 PDF 페이지수로 환산됩니다.
공통 제약 (업로드 차단)
- 파일 크기: 500MB 이하
- 파일 형식: PDF (시그니처
%PDF-확인) - PDF 구조 무결성: 손상/파싱 실패 시 업로드 차단
- 내지 페이지 수: 책 생성 시
pageCount와 정확히 일치해야 함 (LAYFLAT은pageCount / 2PDF 페이지 — 불일치 시 400) - PDF 크기: 허용 오차 내 (위 표 참조)
페이지 수 주의사항 (업로드는 성공, 주문 시 차단)
책 생성 시 지정한 pageCount는 판형의 페이지 규칙을 따라야 합니다. 규칙에 맞지 않아도 PDF 업로드 자체는 성공하지만 (응답의 warnings 배열에 경고 포함), 주문 생성 시 400 에러로 차단됩니다.
| 규칙 | 설명 | 예시 (SQUAREBOOK_HC) |
|---|---|---|
| 페이지 수 범위 | pageCount가 판형의 pageMin ~ pageMax 사이여야 함 | 24 ~ 130 |
| 페이지 수 배수 | pageCount가 pageIncrement의 배수여야 함 | 2의 배수 (24, 26, 28, ...) |
예를 들어 SQUAREBOOK_HC에서 pageCount=23으로 책을 생성하면 23p PDF 업로드는 성공하지만, pageIncrement=2의 배수가 아니므로 주문이 거부됩니다. 반드시 짝수이면서 판형 범위 내인 페이지 수를 지정하세요.
{
"cover": [
{ "minPage": 24, "maxPage": 64, "width": 544, "height": 288 },
{ "minPage": 65, "maxPage": 130, "width": 550, "height": 288 }
],
"inner": { "width": 249, "height": 254 }
}{
"cover": { "width": 332, "height": 216 },
"inner": { "width": 148, "height": 210 }
}1. 책 생성
/booksPDF 업로드 방식으로 책을 생성합니다. creationType="PDF_UPLOAD"와 pageCount(내지 페이지 수)를 지정하는 것이 템플릿 기반 방식과의 차이점입니다.
Request Body
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
title | string | O | 책 제목 (1~255자) |
bookSpecUid | string | O | 판형 UID |
creationType | string | O | "TEMPLATE" / "PDF_UPLOAD" / "MIX_COVER_TEMPLATE" 중 하나. PDF 업로드 방식에선 "PDF_UPLOAD" 지정 |
pageCount | integer | - | 내지 페이지 수 (단페이지 기준). creationType=PDF_UPLOAD 또는 MIX_COVER_TEMPLATE일 때 필수 |
externalRef | string | - | 파트너 외부 참조 식별자 (최대 100자). 파트너 시스템의 고유 ID를 저장하는 용도 |
상태 전이: (없음) → DRAFT(편집중). 응답에서 받은 bookUid를 이후 모든 단계에서 사용합니다.
POST /books 요청 시 Idempotency-Key 헤더를 제공하면 동일한 키로 재요청해도 책이 중복 생성되지 않습니다. 네트워크 오류 등으로 인한 재시도 시 활용하세요.에러 응답
| 상황 | 상태 코드 | 응답 메시지 |
|---|---|---|
creationType=PDF_UPLOAD인데 pageCount 누락 | 400 | creation_type=PDF_UPLOAD는 pageCount(내지 페이지수)가 필수입니다. |
유효하지 않은 creationType 값 | 400 | 유효하지 않은 creationType: INVALID_TYPE (허용: TEMPLATE, PDF_UPLOAD, MIX_COVER_TEMPLATE) |
curl -X POST 'https://api-sandbox.sweetbook.com/v1/books' \
-H 'Authorization: Bearer {YOUR_API_KEY}' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: unique-request-id-001' \
-d '{
"title": "PDF 업로드 샘플",
"bookSpecUid": "SQUAREBOOK_HC",
"creationType": "PDF_UPLOAD",
"pageCount": 24,
"externalRef": "PARTNER-ORDER-001"
}'{
"success": true,
"message": "책 생성 완료",
"data": {
"bookUid": "bk_3lOO********"
}
}2. 표지 PDF 업로드
/books/{bookUid}/pdf-cover표지 PDF를 업로드하고 동기 검증합니다. 메서드에 따라 동작이 분리되어 있습니다.
POST— 신규 등록 전용. 이미 등록되어 있으면409 ConflictPUT— 교체 전용. 등록되어 있지 않으면404 Not Found
교체 실패 시 기존 파일 보존 — PUT 요청의 검증이 실패해도, 이미 성공적으로 업로드되어 있던 파일은 그대로 유지됩니다.
Request (multipart/form-data)
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
file | file (application/pdf) | O | 표지 PDF 파일 (1페이지 고정) |
응답 필드
| 필드 | 타입 | 설명 |
|---|---|---|
valid | boolean | 검증 통과 여부 |
pageCount | integer | PDF의 실제 페이지 수 (표지는 1) |
pdfSizeMm | object | PDF 실제 크기 (width, height, mm 단위) |
messages | string[] | 안내 메시지 배열 |
warnings | string[] | 경고 메시지 배열 |
bookStatus | integer | 책의 현재 상태. 1=DRAFT(편집중) / 2=FINALIZED(최종화) |
url | string | 업로드된 PDF 조회 URL |
에러 응답
| 상황 | 상태 코드 | 응답 메시지 |
|---|---|---|
| POST 호출 시 표지 PDF가 이미 등록됨 | 409 | 표지 PDF가 이미 등록되어 있습니다. 교체하려면 PUT 메서드를 사용하세요. |
| PUT 호출 시 표지 PDF가 등록되어 있지 않음 | 404 | 표지 PDF가 등록되어 있지 않습니다. 신규 등록은 POST 메서드를 사용하세요. |
| PDF 크기 불일치 | 400 | PDF 너비 불일치: 실제 148.0mm, 허용 규격 249mm (+/-1mm) |
curl -X POST 'https://api-sandbox.sweetbook.com/v1/books/{bookUid}/pdf-cover' \
-H 'Authorization: Bearer {YOUR_API_KEY}' \
-F 'file=@hardcover24.pdf;type=application/pdf'{
"success": true,
"message": "cover PDF uploaded successfully",
"data": {
"bookUid": "bk_3lOO********",
"kind": "cover",
"valid": true,
"pageCount": 1,
"pdfSizeMm": { "width": 544, "height": 288 },
"messages": [],
"warnings": [],
"bookStatus": 1,
"url": "https://api-sandbox.sweetbook.com/v1/books/bk_3lOO********/pdf-cover"
}
}curl -X PUT 'https://api-sandbox.sweetbook.com/v1/books/{bookUid}/pdf-cover' \
-H 'Authorization: Bearer {YOUR_API_KEY}' \
-F 'file=@hardcover24.pdf;type=application/pdf'{
"success": true,
"message": "cover PDF replaced successfully",
"data": {
"bookUid": "bk_3lOO********",
"kind": "cover",
"valid": true,
"pageCount": 1,
"pdfSizeMm": { "width": 544, "height": 288 },
"messages": [],
"warnings": [],
"bookStatus": 1,
"url": "https://api-sandbox.sweetbook.com/v1/books/bk_3lOO********/pdf-cover"
}
}3. 내지 PDF 업로드
/books/{bookUid}/pdf-contents내지 PDF를 업로드합니다. 실제 페이지 수가 책 생성 시 지정한 pageCount와 정확히 일치해야 합니다 (불일치 시 400).
POST— 신규 등록 전용. 이미 등록되어 있으면409 ConflictPUT— 교체 전용. 등록되어 있지 않으면404 Not Found
Request (multipart/form-data)
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
file | file (application/pdf) | O | 내지 PDF 파일. 페이지 수가 pageCount와 일치해야 함 |
응답 필드
표지 업로드와 동일한 구조 (kind만 "contents"). 응답 필드 상세는 2. 표지 PDF 업로드 섹션 참조.
에러 응답
| 상황 | 상태 코드 | 응답 메시지 |
|---|---|---|
| POST 호출 시 내지 PDF가 이미 등록됨 | 409 | 내지 PDF가 이미 등록되어 있습니다. 교체하려면 PUT 메서드를 사용하세요. |
| PUT 호출 시 내지 PDF가 등록되어 있지 않음 | 404 | 내지 PDF가 등록되어 있지 않습니다. 신규 등록은 POST 메서드를 사용하세요. |
| PDF 크기 불일치 | 400 | PDF 너비 불일치: 실제 148.0mm, 허용 규격 249mm (+/-1mm) |
| 내지 PDF 페이지 수 불일치 | 400 | 내지 PDF 페이지수 불일치: 올바른 페이지수 24p, 업로드된 페이지수 30p (LAYFLAT은 책 페이지 환산값 부가) |
curl -X POST 'https://api-sandbox.sweetbook.com/v1/books/{bookUid}/pdf-contents' \
-H 'Authorization: Bearer {YOUR_API_KEY}' \
-F 'file=@hardcontents24.pdf;type=application/pdf'{
"success": true,
"message": "contents PDF uploaded successfully",
"data": {
"bookUid": "bk_3lOO********",
"kind": "contents",
"valid": true,
"pageCount": 24,
"pdfSizeMm": { "width": 249, "height": 254 },
"messages": [],
"warnings": [],
"bookStatus": 1,
"url": "https://api-sandbox.sweetbook.com/v1/books/bk_3lOO********/pdf-contents"
}
}curl -X PUT 'https://api-sandbox.sweetbook.com/v1/books/{bookUid}/pdf-contents' \
-H 'Authorization: Bearer {YOUR_API_KEY}' \
-F 'file=@hardcontents24.pdf;type=application/pdf'{
"success": true,
"message": "contents PDF replaced successfully",
"data": {
"bookUid": "bk_3lOO********",
"kind": "contents",
"valid": true,
"pageCount": 24,
"pdfSizeMm": { "width": 249, "height": 254 },
"messages": [],
"warnings": [],
"bookStatus": 1,
"url": "https://api-sandbox.sweetbook.com/v1/books/bk_3lOO********/pdf-contents"
}
}4. 책 최종화
/books/{bookUid}/finalization표지·내지 PDF가 모두 업로드된 후 호출합니다. 호출 성공 시 책의 status가 draft → finalized로, pdfStatus가 null → 2(COMPLETED)로 전환되어 주문 가능 상태가 됩니다.
표지·내지 PDF 업로드 후 이 엔드포인트를 호출해야 책이 FINALIZED 상태가 됩니다. 호출 누락 시 주문 생성은
400 ERR_FINALIZE_PREREQ_UNMET으로 차단됩니다.curl -X POST 'https://api-sandbox.sweetbook.com/v1/books/{bookUid}/finalization' \
-H 'Authorization: Bearer {YOUR_API_KEY}' \
-H 'Content-Length: 0'상세 응답 필드·에러 분기·재호출 멱등 동작은 Books — PDF 기반 → 책 최종화를 참고하세요.
5. 주문 생성
/orders책이 FINALIZED(최종화) 상태인 경우에만 주문 생성이 가능합니다. PDF 업로드 방식의 책은 PDF가 이미 준비되어 있으므로 주문 생성 시점에 즉시 PDF_READY 상태로 진입합니다.
주문 전 금액 확인이 필요하면 POST /orders/estimate를 먼저 호출하세요. 충전금 잔액 부족 시 402 Insufficient Credit이 반환됩니다.
필드 상세는 Orders API 레퍼런스 참조.
POST /orders 요청 시 Idempotency-Key 헤더를 제공하면 동일한 키로 재요청해도 주문이 중복 생성되지 않습니다. 네트워크 오류 등으로 인한 재시도 시 활용하세요.에러 응답
| 상황 | 상태 코드 | 응답 메시지 |
|---|---|---|
| DRAFT(편집중) 상태 책을 주문 시도 | 400 | Book이 FINALIZED 상태가 아닙니다: bk_588b******** |
| 충전금 부족 | 402 | 잔액이 부족합니다. 필요: 3420, 잔액: 760.00 |
curl -X POST 'https://api-sandbox.sweetbook.com/v1/orders' \
-H 'Authorization: Bearer {YOUR_API_KEY}' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: unique-request-id-002' \
-d '{
"items": [{ "bookUid": "{bookUid}", "quantity": 1 }],
"shipping": {
"recipientName": "김영수",
"recipientPhone": "010-0000-0000",
"postalCode": "06134",
"address1": "서울시 강남구 테헤란로 100",
"address2": "101호",
"memo": ""
},
"externalRef": "PARTNER-ORDER-001"
}'{
"success": false,
"message": "Insufficient Credit",
"data": {
"required": 3420,
"balance": 760.00,
"currency": "KRW"
},
"errors": [
"잔액이 부족합니다. 필요: 3420, 잔액: 760.00"
]
}{
"success": true,
"message": "주문이 생성되었습니다",
"data": {
"orderUid": "or_7Bjt********",
"accountName": "김영수",
"accountOrganizationName": null,
"externalRef": "PARTNER-ORDER-001",
"orderStatus": "PDF_READY",
"orderStatusDisplay": "PDF준비완료",
"isTest": true,
"totalProductAmount": 100.00,
"totalShippingFee": 3000,
"totalPackagingFee": 0,
"totalAmount": 3100.00,
"paidCreditAmount": 3410,
"creditBalanceAfter": 98250.00,
"recipientName": "김영수",
"recipientPhone": "010-0000-0000",
"postalCode": "06134",
"address1": "서울시 강남구 테헤란로 100",
"address2": "101호",
"shippingMemo": "",
"trackingNumber": null,
"trackingCarrier": null,
"cancelReason": null,
"refundAmount": null,
"orderedAt": "2026-04-15T06:16:49.813Z",
"paidAt": "2026-04-15T06:16:49.813Z",
"cancelledAt": null,
"shippedAt": null,
"deliveredAt": null,
"createdAt": "2026-04-15T06:16:49.813Z",
"items": [
{
"itemUid": "oi_34CN********",
"bookUid": "bk_3lOO********",
"bookTitle": "PDF 업로드 샘플",
"bookSpecUid": "SQUAREBOOK_HC",
"bookSpecName": "고화질 스퀘어북 (하드커버)",
"quantity": 1,
"pageCount": 24,
"unitPrice": 100.00,
"itemAmount": 100.00,
"itemStatus": "PDF_READY",
"itemStatusDisplay": "PDF준비완료",
"trackingNumber": null,
"trackingCarrier": null,
"shippedAt": null,
"createdAt": "2026-04-15T06:16:49.813Z"
}
]
}
}6. 주문 상태 추적
주문이 생성된 이후 제작·배송 진행은 웹훅 이벤트로 수신합니다. PDF 업로드 방식 주문은 PDF_READY에서 시작하며, 이후 상태 전이 체계는 주문 상태 흐름 페이지 참조.
- 수신 이벤트 목록: Webhook Events 레퍼런스
- 서명 검증: Webhooks API
- 상태 전이 전체도: 주문 상태 흐름
PDF 다운로드 (선택)
/books/{bookUid}/pdf-cover/books/{bookUid}/pdf-contents업로드한 PDF를 다시 다운로드합니다. 인증 필요. 성공 시 Content-Type: application/pdf 바이너리 스트림이 반환됩니다.
한쪽만 업로드된 상태에서도 해당 파일은 다운로드 가능합니다.
에러 응답
| 상황 | 상태 코드 | 응답 메시지 |
|---|---|---|
| 파일이 존재하지 않음 | 404 | PDF 파일이 존재하지 않습니다. |
| 권한 없음 | 403 | 해당 책에 대한 권한이 없습니다. |
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}'