Developer API · v1

Generate AI storybooks from your code.

A REST API for Pro and Premium subscribers. Kick off a generation job, poll for status, and the finished book automatically shows up in your ChildrenBooks library alongside anything you created from the dashboard.

Secure by default

API keys are shown once, hashed with SHA-256 at rest. Rotation and instant revoke from the dashboard. All requests require TLS.

Rate-limited, abuse-resistant

Per-minute, per-day and per-month limits protect your quota from leaks. Responses include x-ratelimit-* headers so SDKs can back off gracefully.

One library, one quota

Books you generate via the API are visible in the same library as dashboard-created books. Quota is shared with your Pro or Premium plan.

Quickstart & API reference

Get a Pro or Premium key from the dashboard, then run the examples. Invalid bodies return 400 / VALIDATION_ERROR; enums must match exactly (case-sensitive). Responses use ok, optional requestId, and data or error. Respect x-ratelimit-* and retry-after on 429.

Prerequisites

  1. 1. Upgrade to Pro or Premium. Free plans cannot issue API keys. See pricing.
  2. 2. Open the dashboard and click Generate API key. Copy it — you won't see it again.
  3. 3. Send your first request. Replace cbk_live_XXX with your key:

Request

POST /v1/stories

Creates an asynchronous generation job for an illustrated children's storybook. The server queues the work and responds right away with 202 Accepted; the body returns taskId and bookId so you can poll GET /v1/stories/{bookId} for progress. Each page (cover included) consumes one credit from your plan quota.

Headers

Authentication: x-api-key: cbk_live_… (preferred) or Authorization: Bearer cbk_live_….

HeaderRequiredDescription
content-typeYesMust be application/json.
Idempotency-KeyNoOptional unique key per logical create (e.g. UUID). Same key within 24h with the same JSON body returns the original taskId / bookId (no second book). Same key with a different body returns 409 / IDEMPOTENCY_CONFLICT. Max length 128. Requires API-side Redis; if Redis is down, deduplication is skipped.
X-Request-IdNoIf set, echoed in responses and logs for tracing. Max length 64; otherwise the server generates one.
JSON body
FieldTypeConstraintsDetails & allowed values
storyIdeastringRequired. Length 10–2000 characters.Plain-language description of the book (plot, characters, setting). Not a model prompt template — write what you want the story to be about.
ageRangestring (enum)Required. Must match exactly one allowed string (case-sensitive).Target reading age band (vocabulary & themes): 0-3, 4-7, 8-12
stylestring (enum)Required. One enumerated value. Case-sensitive — use 3d, not "3D".

Visual art style for illustrations.

  • watercolorSoft watercolor illustration look.
  • oil_paintingOil painting texture and brushwork.
  • 3d3D-rendered / stylized CGI look (send the string 3d).
  • comic_styleComic or graphic-novel panels and inks.
  • crayonCrayon-like strokes, playful child-art feel.
  • colored_pencilColored pencil texture and hatching.
  • paper_cutPaper-cut / layered silhouette style.
pageCountintegerRequired. Integer 5–15 inclusive. 1 credit per page.Total pages including the cover. Monthly quota counts each page toward your plan credits.
tonestring (enum)Required. Snake_case enum — send the string exactly as defined.

Narrative mood / genre bucket.

  • playful_funnyHumor-driven, light and silly.
  • fantasy_magicFairy tales, magic, imaginary worlds.
  • animalAnimal characters and nature-focused plots.
  • heartwarmingGentle emotions, empathy and kindness.
  • sci_fiSpace, robots, simple future-tech (still kid-appropriate).
  • daily_life_basicsEveryday routines, family, school, feelings.
  • adventurousExploration, quests, mild suspense.
  • educationalSoft teaching angle (numbers, habits, social skills).
languagestring (enum)Required. Lowercase English keys only (e.g. english, not en).

Spoken/written language of the generated story text:

english, spanish, french, german, chinese, japanese, korean, russian, portuguese, italian

Minimal call using the headers and JSON fields above (replace the key with yours). cURL and TypeScript are the same request — pick a tab. Use an env var for the key on the server; never expose it in a browser bundle.

cURL — create a storybook
bash
curl -X POST https://api.childrenbooks.online/v1/stories \
  -H "x-api-key: cbk_live_XXXXXXXXXXXX" \
  -H "content-type: application/json" \
  -d '{
    "storyIdea": "A little fox who learns to share carrots with forest friends.",
    "ageRange": "4-7",
    "style": "watercolor",
    "pageCount": 7,
    "tone": "heartwarming",
    "language": "english"
  }'

Response

Returned with 202 Accepted when the job is queued — same ok / data envelope as other success paths. Example payload; collapsible field tables (POST 202 & more) live under Response.

POST /v1/stories — 202 Accepted (body)
json
{
  "ok": true,
  "requestId": "01HZXK3M6Q8EXAMPLE00RVW5T9A",
  "data": {
    "taskId": "550e8400-e29b-41d4-a716-446655440000",
    "bookId": "660e8400-e29b-41d4-a716-446655440001",
    "status": "pending"
  }
}

GET /v1/stories/{id}

Retrieves one storybook's metadata, generation status, progress, and any page rows written so far. Use the bookId from POST /v1/stories. You only receive books that belong to the same user as your API key; missing or other users' ids return 404.

Path parameters
ParameterInRules
idpathThe bookId returned from POST. Must be a UUID. You only see books owned by the API key's user.
Polling

Generation is asynchronous — poll with GET /v1/stories/{bookId} until data.status is completed or failed. The full 200 JSON body is shown once under Response. cURL and TypeScript below are the same poll — use the tab to switch.

cURL — poll status
bash
curl https://api.childrenbooks.online/v1/stories/<bookId> \
  -H "x-api-key: cbk_live_XXXXXXXXXXXX"

Response

Examples and field reference for success and error envelopes. Field order may vary; null may be explicit or omitted.

GET /v1/stories/{id} — 200 OK (example body, e.g. while processing)
json
{
  "ok": true,
  "requestId": "efa24798-b66a-405a-b3c9-956893531fe3",
  "data": {
    "id": "4cf184ed-0a29-4860-a257-0f8998357121",
    "title": "Finn's Carrot Patch",
    "slug": "finns-carrot-patch",
    "coverImage": "https://3fyspdsbp21eloyx.public.blob.vercel-storage.com/stories/4cf184ed-0a29-4860-a257-0f8998357121/storybook-4cf184ed0a294860a2570f8998357121-cover-uHWi4JpCATyXGczHi4uAJa1m24i62q.webp",
    "summary": "A little fox named Finn discovers that sharing his bountiful carrot harvest with his hungry forest friends makes him feel even happier than keeping them all for himself.",
    "storyIdea": "A little fox who learns to share carrots with forest friends.",
    "ageRange": "4-7",
    "style": "watercolor",
    "pageCount": 5,
    "tone": "heartwarming",
    "language": "english",
    "source": "api",
    "storageProvider": null,
    "createdAt": "2026-04-19T11:47:16.327Z",
    "updatedAt": "2026-04-19T11:58:15.877Z",
    "status": "completed",
    "progress": 100,
    "errorMessage": null,
    "completedAt": "2026-04-19T11:48:20.894Z",
    "pages": [
      {
        "index": 0,
        "title": null,
        "content": "In a sun-dappled corner of Whispering Woods, a little fox named Finn had the most wonderful carrot patch. He watered it every day, and the carrots grew big, orange, and crunchy. One morning, Finn pulled up the very last, perfect carrot. \"My carrots!\" he said proudly, piling them into a big basket. He planned to eat them all himself. Just then, he heard a soft sniffle. His friend Thumper the Rabbit was nearby, looking sadly at his own garden, which was just dry dirt. \"My seeds didn't grow,\" Thumper sighed, his tummy rumbling.",
        "imageUrl": "https://3fyspdsbp21eloyx.public.blob.vercel-storage.com/stories/4cf184ed-0a29-4860-a257-0f8998357121/storybook-4cf184ed0a294860a2570f8998357121-0-g8dJ8dzaQbBVfhl5zGc4X74YBwGQqC.webp"
      },
      {
        "index": 1,
        "title": null,
        "content": "Finn looked at his huge basket and then at his hungry friend. He didn't want to share his special carrots. They were *his* prize. But Thumper's sad eyes made his own heart feel funny. \"Well,\" Finn said slowly, scratching his ear. \"Maybe... maybe one carrot wouldn't be missed.\" He picked out a nice, medium-sized carrot and held it out. Thumper's eyes grew wide. \"For me?\" he squeaked. He took the carrot and munched happily. \"Oh, thank you, Finn! This is the best carrot ever!\" Seeing Thumper's joy made a warm, fizzy feeling bubble up in Finn's chest. It felt even better than crunching the carrot himself!",
        "imageUrl": "https://3fyspdsbp21eloyx.public.blob.vercel-storage.com/stories/4cf184ed-0a29-4860-a257-0f8998357121/storybook-4cf184ed0a294860a2570f8998357121-1-HKXNIJm9pHRjGcnJfvlmU5jHFHrb0s.webp"
      },
      {
        "index": 2,
        "title": null,
        "content": "The warm, fizzy feeling was so nice that Finn wanted to feel it again. He saw Bella the Deer walking slowly. \"Are you okay, Bella?\" Finn asked. \"I'm just a little tired from looking for berries,\" she said. Finn didn't hesitate this time. He picked two more carrots from his basket. \"Here, these will give you energy!\" Bella nuzzled him gratefully. \"You are so kind, Finn.\" Next, Oliver the Owl landed on a branch. \"Ahem, long night of studying the stars,\" he said, yawning. Finn offered him a carrot too. \"For your wisdom!\" Oliver hooted happily. Finn's basket was getting lighter, but his heart felt wonderfully full.",
        "imageUrl": "https://3fyspdsbp21eloyx.public.blob.vercel-storage.com/stories/4cf184ed-0a29-4860-a257-0f8998357121/storybook-4cf184ed0a294860a2570f8998357121-2-1qtunfUGjYz83GaofvzvrBin6HiHsB.webp"
      },
      {
        "index": 3,
        "title": null,
        "content": "Soon, Finn's basket was empty, but he was surrounded by happy friends. Thumper was bouncing, Bella was strong again, and Oliver was wide awake. \"Let's have a picnic!\" suggested Thumper. They all agreed. Finn thought his carrots were gone, but then his friends brought things to share! Thumper found sweet clover, Bella brought juicy blackberries, and Oliver shared shiny nuts. They had the best feast ever, laughing and talking. Finn realized something wonderful. Sharing his carrots didn't mean he had less; it meant he had more—more smiles, more laughter, and the best friends in the whole forest.",
        "imageUrl": "https://3fyspdsbp21eloyx.public.blob.vercel-storage.com/stories/4cf184ed-0a29-4860-a257-0f8998357121/storybook-4cf184ed0a294860a2570f8998357121-3-6vOoqqtHK3eyV6VJ3njHaipkGrS1az.webp"
      }
    ]
  }
}
Error — 400 / 401 / 429 / … (body)
json
{
  "ok": false,
  "requestId": "01HZXK3M6Q8EXAMPLE00RVW5T9A",
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request body failed validation.",
    "fields": {
      "pageCount": "Expected number between 5 and 15"
    }
  }
}
Field tables — POST 202 body (taskId, bookId, status)· expand
FieldTypeDescription
okbooleanAlways true for this response.
requestIdstringCorrelation id (echo of X-Request-Id or server-generated).
data.taskIdstring (uuid)Background generation task id (queue correlation).
data.bookIdstring (uuid)Storybook id — use as GET /v1/stories/{id} path parameter.
data.statusstringInitial job status. Typically pending immediately after accept. Values: pending, processing, completed, failed.
Field tables — GET 200 data object, pages[] items, and page fields· expand
FieldTypeDescription
idstring (uuid)Book id (same as the path id).
titlestring | nullGenerated or edited title.
slugstring | nullURL slug for the book on the website, when present.
coverImagestring | nullCover image URL.
summarystring | nullShort synopsis.
storyIdeastring | nullThe story prompt / idea stored on the book.
ageRangestring | nullEcho of request input (e.g. 4-7).
stylestring | nullIllustration style key.
pageCountinteger | nullTarget page count for the book (includes cover).
tonestring | nullTone / genre key.
languagestring | nullStory language key.
sourcestring | nullWhere the book was created: web, api, hf (or null).
storageProviderstring | nullStorage backend identifier for assets, when applicable.
createdAtstring | nullISO 8601 timestamp when the book row was created.
updatedAtstring | nullISO 8601 timestamp of last update to the book record.
statusstringLatest generation task status. pending, processing, completed, failed, unknown. unknown if no task row exists yet.
progressintegerRough completion percentage 0–100 from the latest task (defaults to 0).
errorMessagestring | nullHuman-readable failure reason when status is failed.
completedAtstring | nullISO 8601 timestamp when generation completed, when set.
pagesarrayOrdered list of page objects (see next table). Grows as illustrations and text are written.

data.pages[] — each element

FieldTypeDescription
indexintegerPage order index from storage (sorted ascending with other pages).
titlestring | nullPage title or heading.
contentstring | nullPage body text.
imageUrlstring | nullRendered illustration URL for this page.

Error body

Use error.code for logic; error.message is display-only.

Field table — error object· expand
FieldTypeDescription
okbooleanAlways false.
requestIdstringSame correlation id pattern as success responses.
error.codestringMachine-readable error code (see list below).
error.messagestringHuman-readable message (do not rely on exact wording for logic).
error.fieldsobject | undefinedOptional map of field name → validation message (common for VALIDATION_ERROR).
error.metaobject | undefinedOptional extra context from the server (structure may vary).

error.code values include: UNAUTHORIZED, INVALID_API_KEY, PLAN_REQUIRED, FORBIDDEN, VALIDATION_ERROR, NOT_FOUND, ALREADY_EXISTS, RATE_LIMIT_EXCEEDED, DAILY_CAP_EXCEEDED, INSUFFICIENT_CREDITS, EXTERNAL_SERVICE_ERROR, INTERNAL_ERROR, BAD_REQUEST, METHOD_NOT_ALLOWED

Limits

PlanPer minutePer day (books)Monthly quota
Pro60 req50 booksShared with your plan credits
Premium200 req200 booksShared with your plan credits

When a limit is hit the API returns 429 with retry-after seconds. Every response also includes x-ratelimit-remaining so your client can preemptively slow down.

Usage policy

  • • API keys are tied to a single user. Don't share them across accounts.
  • • Do not generate content that violates our Terms of Service, including sexual content involving minors, real-world violence, or copyrighted characters.
  • • Keep secrets in server-side env vars. Never embed an API key in a browser bundle.
  • • We may rotate or revoke a key after abusive patterns (burst traffic, cross-continent IP jumps within minutes) and contact you by email.
  • • Downgrading to Free instantly revokes the key.

Ready to build?

Log in, activate your API key in the dashboard, and ship your first storybook integration in under 10 minutes.

ChildrenBooks Developer API – Generate AI Storybooks Programmatically | ChildrenBooks