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. Upgrade to Pro or Premium. Free plans cannot issue API keys. See pricing.
- 2. Open the dashboard and click Generate API key. Copy it — you won't see it again.
- 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_….
| Header | Required | Description |
|---|---|---|
| content-type | Yes | Must be application/json. |
| Idempotency-Key | No | Optional client id (e.g. UUID). Same key within 24h returns the original task instead of enqueueing a duplicate. Max length 128 characters. |
| X-Request-Id | No | If set, echoed in responses and logs for tracing. Max length 64; otherwise the server generates one. |
JSON body
| Field | Type | Constraints | Details & allowed values |
|---|---|---|---|
| storyIdea | string | Required. 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. |
| ageRange | string (enum) | Required. Must match exactly one allowed string (case-sensitive). | Target reading age band (vocabulary & themes): 0-3, 4-7, 8-12 |
| style | string (enum) | Required. One enumerated value. Case-sensitive — use 3d, not "3D". | Visual art style for illustrations.
|
| pageCount | integer | Required. Integer 5–15 inclusive. 1 credit per page. | Total pages including the cover. Monthly quota counts each page toward your plan credits. |
| tone | string (enum) | Required. Snake_case enum — send the string exactly as defined. | Narrative mood / genre bucket.
|
| language | string (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 -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.
{
"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
| Parameter | In | Rules |
|---|---|---|
| id | path | The 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 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.
{
"ok": true,
"requestId": "01HZXK3M6Q8EXAMPLE00RVW5T9A",
"data": {
"id": "660e8400-e29b-41d4-a716-446655440001",
"title": "The Little Fox Who Shared",
"slug": null,
"coverImage": "https://cdn.example.com/covers/660e8400.jpg",
"summary": null,
"storyIdea": "A little fox who learns to share carrots with forest friends.",
"ageRange": "4-7",
"style": "watercolor",
"pageCount": 7,
"tone": "heartwarming",
"language": "english",
"source": "api",
"storageProvider": "r2",
"createdAt": "2026-04-19T12:00:00.000Z",
"updatedAt": "2026-04-19T12:02:15.000Z",
"status": "processing",
"progress": 42,
"errorMessage": null,
"completedAt": null,
"pages": [
{
"index": 0,
"title": "The Sharing Fox",
"content": "Once upon a time, in a green forest...",
"imageUrl": "https://cdn.example.com/pages/660e8400-0.png"
},
{
"index": 1,
"title": "New Friends",
"content": null,
"imageUrl": null
}
]
}
}{
"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
| Field | Type | Description |
|---|---|---|
| ok | boolean | Always true for this response. |
| requestId | string | Correlation id (echo of X-Request-Id or server-generated). |
| data.taskId | string (uuid) | Background generation task id (queue correlation). |
| data.bookId | string (uuid) | Storybook id — use as GET /v1/stories/{id} path parameter. |
| data.status | string | Initial job status. Typically pending immediately after accept. Values: pending, processing, completed, failed. |
Field tables — GET 200 data object, pages[] items, and page fields· expand
| Field | Type | Description |
|---|---|---|
| id | string (uuid) | Book id (same as the path id). |
| title | string | null | Generated or edited title. |
| slug | string | null | URL slug for the book on the website, when present. |
| coverImage | string | null | Cover image URL. |
| summary | string | null | Short synopsis. |
| storyIdea | string | null | The story prompt / idea stored on the book. |
| ageRange | string | null | Echo of request input (e.g. 4-7). |
| style | string | null | Illustration style key. |
| pageCount | integer | null | Target page count for the book (includes cover). |
| tone | string | null | Tone / genre key. |
| language | string | null | Story language key. |
| source | string | null | Where the book was created: web, api, hf (or null). |
| storageProvider | string | null | Storage backend identifier for assets, when applicable. |
| createdAt | string | null | ISO 8601 timestamp when the book row was created. |
| updatedAt | string | null | ISO 8601 timestamp of last update to the book record. |
| status | string | Latest generation task status. pending, processing, completed, failed, unknown. unknown if no task row exists yet. |
| progress | integer | Rough completion percentage 0–100 from the latest task (defaults to 0). |
| errorMessage | string | null | Human-readable failure reason when status is failed. |
| completedAt | string | null | ISO 8601 timestamp when generation completed, when set. |
| pages | array | Ordered list of page objects (see next table). Grows as illustrations and text are written. |
data.pages[] — each element
| Field | Type | Description |
|---|---|---|
| index | integer | Page order index from storage (sorted ascending with other pages). |
| title | string | null | Page title or heading. |
| content | string | null | Page body text. |
| imageUrl | string | null | Rendered illustration URL for this page. |
Error body
Use error.code for logic; error.message is display-only.
Field table — error object· expand
| Field | Type | Description |
|---|---|---|
| ok | boolean | Always false. |
| requestId | string | Same correlation id pattern as success responses. |
| error.code | string | Machine-readable error code (see list below). |
| error.message | string | Human-readable message (do not rely on exact wording for logic). |
| error.fields | object | undefined | Optional map of field name → validation message (common for VALIDATION_ERROR). |
| error.meta | object | undefined | Optional 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
| Plan | Per minute | Per day (books) | Monthly quota |
|---|---|---|---|
| Pro | 60 req | 50 books | Shared with your plan credits |
| Premium | 200 req | 200 books | Shared 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.