KDPBot API — Developer Portal
KDPBot AI turns a book concept into a finished, publish-ready manuscript: outline, chapters, cover art, chapter illustrations, and an export file you can upload to Amazon KDP. Everything the web app does is driven by the same public HTTP JSON API documented on this page — so scripts, pipelines and autonomous agents can drive the whole pipeline without a browser.
API base URL https://kdpbot.com/api/v1 — same-origin and version-pinned. https://bookgen-backend-5zuf.onrender.com/api/v1 reaches the same backend directly.
- /openapi.jsonOpenAPI 3.1 specification (JSON). Import into Postman, Insomnia, an SDK generator, or an agent tool loader.
- /openapi.yamlThe same OpenAPI 3.1 specification in YAML, for tooling that prefers it.
- /llms.txtCompact, llmstxt.org-format map of KDPBot for language models and crawlers.
- /agents.mdExtended agent instructions: when to use KDPBot, task recipes, and hard constraints.
- /.well-known/api-catalogRFC 9727 API catalog: every machine-readable KDPBot resource, at one predictable URL.
- /docs/mcp.mdThe official KDPBot MCP server:
npx -y kdpbot mcp, client config and all eleven tools.
What KDPBot does, and when to use the KDPBot API
KDPBot AI is a book-production system for self-publishers. A book moves through a fixed lifecycle, and the API exposes every stage of it:
- Concept — create a
Bookrecord with a title, genre, target audience, chapter count, target word count, trim size and content language. - Outline — an LLM produces the chapter structure and writes it back as real
Chapterrows, each with its own title, summary and per-chapter word budget. - Content — a background worker writes every chapter in sequence, updating a progress record you can poll.
- Art — AI cover variants for the book and optional illustrations for individual chapters.
- Export — the finished manuscript rendered as PDF, DOCX or EPUB, sized to the trim you chose.
Concrete jobs the KDPBot API is good at
- Batch production. Feed a list of titles and briefs from a spreadsheet and produce a manuscript per row overnight, without touching the UI.
- Outline-only research. Call
POST /api/books/{id}/generate-outline/to get a structured chapter breakdown for a topic, then throw the book away or keep iterating. This step is synchronous and returns the chapters inline. - Editorial pipelines. Generate a draft, pull each chapter with
GET /api/chapters/, run it through your own review step, and write corrections back withPATCH /api/chapters/{id}/. That is the exact endpoint the in-app editor autosaves to. - Selective regeneration. Rewrite one weak chapter with
POST /api/chapters/{id}/regenerate/instead of regenerating the entire book. - Cover A/B testing. Generate cover variants programmatically, score them with your own model or with real click data, and select the winner.
- Export automation. Produce KDP-ready PDF interiors and EPUB files on a schedule and drop them straight into your upload workflow.
- Usage and billing telemetry. Read plan limits, quota consumption and credit balance so an unattended job can stop before it hits a hard limit.
Things to know before you build
- Trailing slashes are mandatory. Every path ends in
/. APOSTto a slashless path is redirected and the request body is lost. Always send/api/books/, never/api/books. - List endpoints are not paginated.
GET /api/books/,GET /api/chapters/, plans, credit packages and add-ons all return a bare JSON array — not a{count, next, previous, results}envelope. - Login and registration return a nested token object (
tokens.access,tokens.refresh), while the refresh endpoint returns flataccessandrefreshkeys. Handle both shapes. - Full book generation is asynchronous.
POST /api/books/{id}/generate/returns202immediately; the work continues in a background worker and can run for many minutes on a long book. Poll for completion. - Three export actions use underscores —
export_pdf,export_docx,export_epub— while most other actions use hyphens (generate-outline,generation-status). Copy paths from the endpoint table below rather than guessing. - Exports return binary bodies, not JSON. Write the response to a file.
The KDPBot API surface: REST over HTTPS, and nothing else
So that nobody has to discover it by probing: KDPBot exposes exactly one API surface — a REST API over HTTPS that speaks JSON, except the four export actions, which return binary file bodies.
- There is no GraphQL endpoint. No
/graphql, no schema introspection, no persisted queries. A probe returns404 NOT_FOUNDbecause the endpoint does not exist, not because it is gated behind authentication. - There is no gRPC or SOAP surface, and no WebSocket API. Long-running generation is observed by polling
GET /api/books/{id}/generation-status/, not by subscribing to a stream. - There is no outbound webhook API. KDPBot receives a Stripe webhook; it does not deliver callbacks to your endpoints.
- There is an official KDPBot MCP server. It ships inside the
kdpbotnpm package and runs over stdio withnpx -y kdpbot mcp— a client of this same REST API, not a second surface. /docs/mcp.md carries the client configuration, all eleven tools and a worked example. - The machine-readable contract is the KDPBot OpenAPI specification at /openapi.json (YAML) — OpenAPI 3.1, 67 paths, 75 operations, every one carrying an
operationId, a summary, a description and typed responses. Where this page and the spec disagree, the spec wins. - Stability guarantees — what may change inside v1, what may not, and how a sunset is announced — are in the KDPBot API versioning and deprecation policy.
KDPBot API quickstart
The sequence below takes an account from login to a downloaded PDF using nothing but curl. It runs against the production API base URL. Substitute your own credentials; create an account first at kdpbot.com or via POST /api/auth/register/.
Step 1 — Authenticate and capture a token
BASE="https://kdpbot.com/api/v1"
TOKEN=$(curl -s -X POST "$BASE/auth/login/" \
-H "Content-Type: application/json" \
-d '{"email":"you@example.com","password":"your-password"}' \
| python3 -c "import sys,json; print(json.load(sys.stdin)['tokens']['access'])")
echo "${TOKEN:0:24}..."
The full login response also contains the user object and the user's current subscription, so a client can decide up front whether the account has quota left.
Step 2 — Create a book
BOOK_ID=$(curl -s -X POST "$BASE/books/" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"title": "The Complete Guide to Remote Work",
"subtitle": "Strategies for Distributed Teams",
"genre": "business",
"target_audience": "Managers leading distributed teams",
"description": "A practical playbook for hiring, onboarding and running remote teams.",
"chapter_count": 10,
"target_word_count": 30000,
"trim_size": "6x9",
"content_language": "en"
}' \
| python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")
echo "book id: $BOOK_ID"
If the account is out of book quota this returns 402 with error: "quota_exceeded" and an upgrade object pointing at /pricing. Quota is not consumed at creation time — it is consumed when generation finishes.
Step 3 — Generate the outline
curl -s -X POST "$BASE/books/$BOOK_ID/generate-outline/" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Length: 0"
This call is synchronous and may take tens of seconds. It returns the full book object with a populated chapters array and sets status to outline. Note that it replaces any chapters that already exist on the book. To edit titles or summaries before writing content, send your revisions to POST /api/books/{id}/update-outline/.
Step 4 — Start content generation
curl -s -X POST "$BASE/books/$BOOK_ID/generate/" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Length: 0"
# => 202 {"message":"Generation started","book_id":123,"task_id":"...","mode":"celery"}
A book must have an outline before this succeeds. Starting a second generation while one is already running returns 400.
Step 5 — Poll progress until it completes
while true; do
STATUS=$(curl -s "$BASE/books/$BOOK_ID/generation-status/" \
-H "Authorization: Bearer $TOKEN")
echo "$STATUS" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('generation_status'), str(d.get('percentage'))+'%', d.get('status_message',''))"
echo "$STATUS" | grep -q '"generation_status": *"completed"' && break
sleep 20
done
Poll no more often than every 10–20 seconds. The response carries completed_chapters, total_chapters, percentage, a human-readable status_message, an outline array showing which chapters already have content, and generation_status, one of running, paused, stopped, completed or error. A book with no generation record yet returns 404.
Step 6 — Generate a cover, then export
# Optional: AI cover variants
curl -s -X POST "$BASE/books/$BOOK_ID/generate-cover/" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" -d '{}'
# Export — note the UNDERSCORE in export_pdf, and the binary response body
curl -s -X POST "$BASE/books/$BOOK_ID/export_pdf/" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"settings":{}}' \
--output "book-$BOOK_ID.pdf"
file "book-$BOOK_ID.pdf"
Swap export_pdf for export_docx or export_epub for the other formats. Free-tier exports carry a watermark; paid plans do not.
Authentication in the KDPBot API
KDPBot uses JWT bearer tokens issued by djangorestframework-simplejwt. Send the access token on every authenticated request:
Authorization: Bearer <access_token>
There are no API keys and no OAuth client credentials flow. A token represents a user account, and every request is scoped to that user's own books and chapters.
Getting a token
POST /api/auth/login/- Accepts
emailorusername, pluspassword. Returns{"user": {...}, "tokens": {"access": "...", "refresh": "..."}}. POST /api/auth/register/- Creates the account and returns the same nested shape with
201. If email verification is enforced, tokens are withheld andemail_verification_required: trueis returned instead — verify the address before retrying. POST /api/auth/google/- Exchanges a Google OAuth2 access token for a KDPBot token pair.
Token lifetimes and refresh
| Token | Lifetime | Behaviour |
|---|---|---|
access | 24 hours | Sent as Authorization: Bearer … on every protected call. Signed HS256. |
refresh | 30 days | Exchanged for a fresh access token. Rotation is enabled, so each refresh also returns a new refresh token — store it and discard the old one. |
curl -s -X POST "$BASE/auth/token/refresh/" \
-H "Content-Type: application/json" \
-d '{"refresh":"<your_refresh_token>"}'
# => {"access":"<new access>","refresh":"<new refresh>"} # flat, not nested
For a long-running job, refresh proactively — for example every few hours — rather than waiting for a 401. An expired or malformed token returns 401 with code: "token_not_valid". A logout endpoint exists for symmetry, but tokens are stateless: the practical way to sign out is to discard them client-side.
Full detail lives in /docs/authentication.md.
Machine-readable KDPBot API resources for agents and tooling
If you are an AI agent, an SDK generator or a crawler, start with these files rather than scraping this page. They are static, versioned alongside the site, and served from the same origin:
| Resource | Format | Use it for |
|---|---|---|
| /.well-known/api-catalog | RFC 9727 linkset, application/linkset+json | The index of everything in this table, at a predictable URL. Start here when discovering KDPBot programmatically. |
| /openapi.json | OpenAPI 3.1, JSON | Client generation, request validation, agent tool definitions, Postman/Insomnia import. |
| /openapi.yaml | OpenAPI 3.1, YAML | The same contract for YAML-first toolchains and CI linting. |
| /llms.txt | llmstxt.org Markdown | A compact index of what KDPBot is and where its canonical documents live. |
| /agents.md | Markdown | Extended agent guidance: when to reach for KDPBot, recipes, and constraints to respect. |
| /docs/mcp.md | Markdown | The official KDPBot MCP server — install, client configuration, tool reference and a worked example. |
| /sitemap.xml | XML | Every indexable KDPBot URL. |
| /robots.txt | Text | Crawl rules, including for AI crawlers. |
KDPBot AI documentation — human-readable guides
- /docs/quickstart.md — the curl walkthrough above in Markdown form.
- /docs/authentication.md — tokens, refresh, and failure modes.
- /docs/api.md — the full API reference with request and response fields.
- /docs/errors.md — error codes and the JSON error envelope.
- /docs/rate-limits.md · Versioning & deprecation policy — limits, headers and backoff conventions.
- /docs/mcp.md — the official KDPBot MCP server:
npx -y kdpbot mcp, client config and tool reference.
KDPBot API error format
Errors are returned as JSON with an HTTP status code that carries the primary signal. The documented envelope is:
{
"error": {
"code": "quota_exceeded",
"message": "You have used all books included in your current plan.",
"status": 402,
"details": {
"quota_type": "books",
"limit": 3,
"used": 3,
"remaining": 0
},
"documentation_url": "https://kdpbot.com/docs/errors.md#quota_exceeded"
}
}
code- A stable, machine-readable identifier. Branch on this, never on the message text.
message- A human-readable sentence, safe to surface to an end user.
status- The HTTP status code, repeated in the body so it survives logging and message queues.
details- Optional structured context — the offending fields on a validation error, or the quota numbers on a
402. documentation_url- A deep link into /docs/errors.md for that specific code.
Status codes you should handle
| Status | Meaning | What to do |
|---|---|---|
400 | Invalid or missing fields, or an invalid state transition — for example generating content on a book with no outline. | Fix the request. Do not retry unchanged. |
401 | Missing, expired or malformed access token. | Refresh the token once, then retry. If refresh also fails, re-authenticate. |
402 | Plan quota exhausted, or the requested word count exceeds the plan limit. | Stop. Upgrade at /pricing or buy credits. |
403 | Authenticated but not permitted — including anti-abuse blocks on registration. | Do not retry programmatically. Contact support if unexpected. |
404 | No such resource, or it belongs to another account. Also returned by generation-status when no generation has ever been started for the book. | Check the id and the owning account. |
429 | Too many requests. | Back off and retry after the interval given by Retry-After. |
500 | Server-side failure, including an upstream model provider error during generation. | Retry with exponential backoff. If it persists, email support@kdpbot.com with the request path and timestamp. |
Compatibility note. Some older endpoints still answer with a flat {"error": "message text"} body, and framework-level failures may return {"detail": "…"} or a field-keyed validation map such as {"title": ["This field is required."]}. A robust client should read error.code when present, then fall back to error, then detail, and finally treat the object as a field-to-messages map. In all cases the HTTP status code is authoritative.
KDPBot API rate limits
Be a good citizen: run one book generation at a time per account, poll status no more than once every 10–20 seconds, and back off on any 429 or 5xx. Rate-limited responses expose standard headers:
| Header | Meaning |
|---|---|
RateLimit-Limit | Requests permitted in the current window. |
RateLimit-Remaining | Requests still available in the current window. |
RateLimit-Reset | Seconds until the window resets and the allowance is restored. |
Retry-After | Sent with 429. Seconds to wait before retrying. Always honour this value over your own schedule. |
HTTP/1.1 429 Too Many Requests
RateLimit-Limit: 120
RateLimit-Remaining: 0
RateLimit-Reset: 44
Retry-After: 44
Content-Type: application/json
{"error":{"code":"rate_limited","message":"Too many requests. Retry in 44 seconds.","status":429,"details":{"retry_after":44},"documentation_url":"https://kdpbot.com/docs/rate-limits.md"}}
Quotas are separate from rate limits
Rate limits govern request frequency. Quotas govern how much you may produce: books per period, images, and editing operations, all set by your subscription plan. Quota exhaustion is a 402, not a 429, and waiting will not clear it — the period must roll over, the plan must be upgraded, or credits must be purchased. Check your headroom before a long batch with GET /api/auth/subscriptions/current/, GET /api/auth/subscriptions/book-creation-options/ and GET /api/auth/credits/balance/. See /docs/rate-limits.md.
Sandbox — try the KDPBot API without an account
These endpoints are public: no API key, no token, no sign-up. They are the fastest way for an agent or a developer to confirm connectivity, inspect real response shapes, and check the error and rate-limit headers before writing any integration code.
| Endpoint | Returns |
|---|---|
GET /api/v1/books/demo/ | A complete demo book with chapters — the real response shape of a generated book. |
GET /api/v1/auth/subscriptions/plans/ | All subscription plans with quotas and features. |
GET /api/v1/auth/credits/packages/ | Pay-as-you-go credit packages and prices. |
GET /api/v1/auth/addons/available/ | Purchasable add-ons. |
GET /api/v1/public-settings/ | Public feature flags used by the web app. |
# No credentials required — copy and run:
curl -s https://kdpbot.com/api/v1/auth/subscriptions/plans/
# Inspect the JSON error envelope on a protected endpoint:
curl -s https://kdpbot.com/api/v1/books/
# Inspect the rate-limit and version headers:
curl -sI https://kdpbot.com/api/v1/auth/subscriptions/plans/
Everything beyond this list requires authentication. There are no separate API keys to provision — see Authentication, or jump straight to the quickstart.
API credentials
KDPBot does not issue static API keys. Access is granted with short-lived JWT bearer tokens minted from the same account you use in the web app, which means a token can never outlive the account’s permissions or plan.
- Get a token —
POST /api/v1/auth/login/with your email and password returns{"tokens": {"access", "refresh"}}. - Use it — send
Authorization: Bearer <access>on every request. - Lifetime — the access token lives 24 hours; the refresh token lives 30 days and rotates on each use.
- Refresh —
POST /api/v1/auth/token/refresh/returns a flat{"access", "refresh"}pair. Note the shape differs from login. - Revoke — change the account password to invalidate outstanding refresh tokens.
- Storage — treat tokens as credentials: keep them out of version control, store them with
0600permissions, and never log or print them.
KDPBot API versioning and deprecation
The API is versioned in the URL path. The current version is v1 at
https://kdpbot.com/api/v1. The unversioned /api/ prefix is a
permanent alias of the current version, kept for existing clients — new
integrations should pin /api/v1/.
Every response carries X-API-Version and X-API-Version-Latest.
A version scheduled for removal additionally returns Deprecation,
Sunset (RFC 8594) and Link: <…>; rel="deprecation",
with at least six months of notice. Full policy:
versioning and deprecation.
KDPBot API endpoint reference
All paths are relative to https://kdpbot.com/api/v1. The trailing slash is part of the path. “Auth” means an Authorization: Bearer access token is required.
Authentication endpoints
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /api/auth/register/ | Public | Create an account. Returns the user plus a nested tokens pair, unless email verification is required. |
| POST | /api/auth/login/ | Public | Log in with email or username and password. Returns the user (with subscription) and a token pair. |
| POST | /api/auth/token/refresh/ | Public | Exchange a refresh token for a new access token. Rotation returns a new refresh token too. |
| POST | /api/auth/google/ | Public | Sign in or sign up with a Google OAuth2 access token. |
| GET | /api/auth/profile/ | JWT | The current user's profile, including the nested subscription and its plan feature map. |
| PATCH | /api/auth/profile/ | JWT | Update first_name, last_name or email. |
| POST | /api/auth/change-password/ | JWT | Change the password of the authenticated user. |
| POST | /api/auth/forgot-password/ | Public | Send a password-reset email. |
| POST | /api/auth/reset-password/{uid}/{token}/ | Public | Complete a password reset using the uid and token from the emailed link. |
| GET | /api/auth/verify-email/{uid}/{token}/ | Public | Verify an email address from the registration link. |
| POST | /api/auth/logout/ | Public | Symmetric logout endpoint. Tokens are stateless — discard them client-side. |
Books endpoints
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /api/books/ | JWT | List the caller's books, newest update first. Bare JSON array, with chapters_count and word_count annotated. |
| POST | /api/books/ | JWT | Create a book. Returns 402 quota_exceeded when the plan's book allowance is spent. |
| GET | /api/books/{id}/ | JWT | Retrieve one book with all chapters, generation progress and cover fields. |
| PATCH | /api/books/{id}/ | JWT | Partially update book metadata. |
| DELETE | /api/books/{id}/ | JWT | Delete a book. Cascades to its chapters, progress record and saved covers. |
| GET | /api/books/dropdown/ | JWT | Lightweight selector list: id and title only. |
| POST | /api/books/{id}/generate-outline/ | JWT | Synchronously generate the chapter outline. Replaces existing chapters and sets status to outline. |
| POST | /api/books/{id}/update-outline/ | JWT | Persist your edits to chapter titles and summaries. |
| POST | /api/books/{id}/generate/ | JWT | Start asynchronous generation of all chapter content. Returns 202 with a task id. |
| GET | /api/books/{id}/generation-status/ | JWT | Poll progress: percentage, completed chapters, status message and per-chapter outline state. |
| POST | /api/books/{id}/pause-generation/ | JWT | Pause a running generation. |
| POST | /api/books/{id}/generate-cover/ | JWT | Generate AI cover variants for the book. |
| POST | /api/books/{id}/export_pdf/ | JWT | Export as PDF. Binary application/pdf body. Note the underscore. |
| POST | /api/books/{id}/export_docx/ | JWT | Export as DOCX. Binary body. |
| POST | /api/books/{id}/export_epub/ | JWT | Export as EPUB. Binary body. |
| GET | /api/books/{id}/preview-data/ | JWT | Aggregated pages, cover URLs and trim size used by the book preview. |
| POST | /api/books/{id}/duplicate/ | JWT | Deep-copy a book and its chapters into a new draft. |
| GET | /api/books/demo/ | Public | The public demo book used on the marketing site — handy for testing a client without an account. |
Chapters endpoints
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /api/chapters/ | JWT | Every chapter across all of the caller's books. |
| GET | /api/chapters/{id}/ | JWT | Retrieve a single chapter with its content. |
| PATCH | /api/chapters/{id}/ | JWT | Update chapter content or title. This is the editor's save path — use it to write edits back. |
| POST | /api/chapters/{id}/regenerate/ | JWT | Synchronously rewrite this one chapter with the model and save the result. |
| POST | /api/chapters/{id}/generate-image/ | JWT | Generate an AI illustration for the chapter. |
Subscriptions and add-ons endpoints
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /api/auth/subscriptions/plans/ | Public | All active subscription plans with their limits and features. |
| GET | /api/auth/subscriptions/current/ | JWT | The caller's subscription, this period's quota usage and the plan's limit map. |
| GET | /api/auth/subscriptions/usage/ | JWT | Usage history: the current period plus recent past periods. |
| GET | /api/auth/subscriptions/book-creation-options/ | JWT | Whether a new book can be started right now, and whether it would draw on plan quota or credits. |
| POST | /api/auth/subscriptions/checkout/ | JWT | Create a Stripe Checkout session for a paid plan. |
| POST | /api/auth/subscriptions/portal/ | JWT | Create a Stripe Customer Portal session and return its URL. |
| GET | /api/auth/subscriptions/payments/ | JWT | Recent payment and invoice history. |
| GET | /api/auth/addons/available/ | Public | Active add-ons, such as Autopilot. |
| GET | /api/auth/addons/my_addons/ | JWT | The caller's active add-ons. Note the underscore in the path. |
| POST | /api/auth/addons/checkout/ | JWT | Purchase an add-on via Stripe Checkout. |
Credits endpoints
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /api/auth/credits/packages/ | Public | Active pay-as-you-go credit packages in display order. |
| GET | /api/auth/credits/balance/ | JWT | The caller's current credit balance. |
| GET | /api/auth/credits/transactions/ | JWT | Credit history — purchases, usage, refunds and bonuses, newest first. |
| POST | /api/auth/credits/checkout/ | JWT | Create a Stripe Checkout session to buy a credit package. |
| POST | /api/auth/credits/guest-checkout/ | Public | Buy credits without an account. |
Utility endpoints
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /api/stats/ | JWT | Dashboard statistics for the authenticated user. |
| GET | /api/public-settings/ | Public | Public site settings and feature toggles. |
| POST | /api/chatbot/ask/ | Public | Ask the KDPBot support assistant a question about the product. |
Support and contact
Questions about the KDPBot API, a bug in a response shape, or a quota that looks wrong? Reach a human on any of these channels — email is best for anything that needs a request path, timestamp and payload attached.
- Emailsupport@kdpbot.com
- Telegramt.me/blabla_ecommerce
- WhatsApp+380 99 401 9521
- Contact pagekdpbot.com/contacts
Elsewhere on KDPBot
- Home — what KDPBot AI does, with a live demo book.
- Pricing — plans, quotas and what each tier includes.
- Credits — pay-as-you-go credit packages.
- KDPBot Academy — courses on publishing and selling on Amazon KDP.
- Blog — guides on AI-assisted writing and self-publishing.
- Terms · Privacy · Refund policy