Browse docs
Getting Started
Guides
Explainers
API Reference: Books
Local endpoints for listing, creating, reading, updating, and deleting books, plus stats, the per-book style guide, and the cover image.
These endpoints manage book projects. Each book is a folder under your local books/ directory, identified by its slug. Metadata lives in book.json and is described by the BookMetadata type (which extends Partial<KDPMetadata>); list and read responses return a Book, which adds slug, folderPath, and optional counts.
Collection
GET /api/books
List all books found in your books/ directory.
Response
Returns { books: Book[] }. Each entry includes slug, folderPath, and the book’s metadata fields.
{
"books": [
{
"slug": "my-first-book",
"title": "My First Book",
"author": "Anonymous",
"language": "en",
"folderPath": "/Users/you/books/my-first-book",
"status": "draft"
}
]
}
curl http://localhost:3000/api/books
POST /api/books
Create a new book. The server generates the slug and scaffolds the project folder.
Request body
title is required. author defaults to "Anonymous" if omitted. Any additional fields are passed through as creation options.
{
"title": "My First Book",
"author": "Jane Doe"
}
Response — 201 Created
{
"slug": "my-first-book",
"message": "Book created successfully"
}
Returns 400 with { "error": "Title is required" } if title is missing or not a string.
curl -X POST http://localhost:3000/api/books \
-H "Content-Type: application/json" \
-d '{"title":"My First Book","author":"Jane Doe"}'
Single book
GET /api/books/{slug}
Get a single book’s metadata.
Path parameters
slug— the book’s folder name.
Response
Returns { book: Book }, or 404 { "error": "Book not found" }.
curl http://localhost:3000/api/books/my-first-book
PATCH /api/books/{slug}
Update book metadata. Send only the fields you want to change; they are merged into book.json. Note this is PATCH, not PUT.
Path parameters
slug— the book’s folder name.
Request body
A partial BookMetadata object. For example, KDP fields such as subtitle, keywords, categories, audience, and printSpecs may be set here, alongside core fields like title, author, description, and status.
{
"description": "An updated blurb.",
"status": "ready",
"keywords": ["fantasy", "epic"]
}
Response
Returns { book, message } where book is the existing book merged with the updated metadata.
{
"book": { "slug": "my-first-book", "status": "ready" },
"message": "Book updated successfully"
}
curl -X PATCH http://localhost:3000/api/books/my-first-book \
-H "Content-Type: application/json" \
-d '{"status":"ready"}'
DELETE /api/books/{slug}
Delete a book and all of its contents from disk.
Path parameters
slug— the book’s folder name.
Response
{ "message": "Book deleted successfully" }
Returns 404 if the book does not exist.
curl -X DELETE http://localhost:3000/api/books/my-first-book
Stats
GET /api/books/{slug}/stats
Compute the total word count and an estimated page count across all manuscript files. The estimate divides total words by 250 words per page (standard 6×9 KDP paperback) and rounds up.
Path parameters
slug— the book’s folder name.
Response
{
"wordCount": 42000,
"pageCount": 168,
"fileCount": 12,
"wordsPerPage": 250
}
curl http://localhost:3000/api/books/my-first-book/stats
Style guide
The style guide is a single Markdown document stored alongside the book. There is no POST; saving uses PUT.
GET /api/books/{slug}/style
Read the style guide document.
Response
{
"content": "# Style Guide\n\nUse en dashes...",
"lastModified": "2026-06-03T12:00:00.000Z",
"exists": true
}
If the style file does not exist yet, returns { "content": "", "lastModified": null, "exists": false }. Returns 404 if the book itself is not found.
curl http://localhost:3000/api/books/my-first-book/style
PUT /api/books/{slug}/style
Create or overwrite the style guide document.
Request body
content(string, required) — the full Markdown text.
{ "content": "# Style Guide\n\nUse en dashes..." }
Response
{ "message": "Style guide saved successfully" }
Returns 400 { "error": "content is required" } if content is omitted, or 404 if the book is not found.
curl -X PUT http://localhost:3000/api/books/my-first-book/style \
-H "Content-Type: application/json" \
-d '{"content":"# Style Guide\n"}'
Cover image
The cover is managed with GET, POST, and DELETE. Uploads use multipart/form-data — there is no JSON PUT. The cover reference is stored on the book’s cover metadata field as a path like assets/cover.jpg.
GET /api/books/{slug}/cover
Return the cover image bytes.
Response
The raw image with a matching Content-Type (image/jpeg, image/png, image/gif, or image/webp) and Cache-Control: public, max-age=3600. Returns 404 { "error": "No cover set" } if the book has no cover, or { "error": "Cover file not found" } if the referenced file is missing.
curl http://localhost:3000/api/books/my-first-book/cover --output cover.jpg
POST /api/books/{slug}/cover
Upload (or replace) the cover image. Existing cover.* files are removed first, the new file is saved into the book’s assets/ folder, and book.json is updated.
Request body — multipart/form-data
cover(file, required) — must be JPEG, PNG, GIF, or WebP.
Response
{
"success": true,
"cover": "assets/cover.jpg",
"filename": "cover.jpg"
}
Returns 400 for a missing file ({ "error": "No file provided" }) or an unsupported type ({ "error": "Invalid file type. Must be JPEG, PNG, GIF, or WebP" }), and 404 if the book is not found.
curl -X POST http://localhost:3000/api/books/my-first-book/cover \
-F "cover=@./cover.jpg"
DELETE /api/books/{slug}/cover
Remove the cover image files and clear the cover reference from book.json.
Response
{ "success": true }
curl -X DELETE http://localhost:3000/api/books/my-first-book/cover