← Books

Spine-Zai API

Book-generation engine. Creates a "project" (book) from a premise, bootstraps a spine/outline, then generates chapters one at a time.

Version: Spine-Zai App 0.17.0

Access

From Base URL
The .21 host itself http://127.0.0.1:9120
The .22 server (forgeloops) http://172.24.0.1:19120 (SSH tunnel)
A container on offertest_web http://zaispine-proxy:80
Public https://zaispine.forgeloops.com (Traefik basic auth)

The API runs as spine-zai-prod-api:8000 on 192.168.0.21, host-published on port 9120. The books.forgeloops.com tool reaches it via zaispine-proxy.

Auth: dev bypass is on in prod (AUTH_DEV_BYPASS=true) — no bearer token needed. The seed user 00000000-0000-0000-0000-000000000001 owns most projects.

Endpoints

Projects

Method Path Notes
GET /projects List all projects (books).
POST /projects Create a project.
GET /projects/{project_id} Project detail.
PUT /projects/{project_id} Update a project.
DELETE /projects/{project_id} Delete a project.

Bootstrap & generation

Method Path Notes
POST /projects/{project_id}/bootstrap Build spine/outline from a premise. Streams SSE events.
POST /projects/{project_id}/generate Generate the whole book synchronously over SSE (~20 min — blocks the connection).
POST /projects/{project_id}/chapters/{chapter_index}/generate Generate one chapter.
POST /projects/{project_id}/chapters/{chapter_index}/regenerate?cascade=<bool> Re-run a chapter. index=0 + cascade=true rebuilds the whole book. Returns 202 + a queued Generation.
GET /projects/{project_id}/generations List generation jobs.
POST /projects/{project_id}/generations Queue a generation job.
GET /projects/{project_id}/generations/{generation_id} Job status.

Content

Method Path Notes
GET /projects/{project_id}/chapters List chapters.
GET /projects/{project_id}/chapter/{chapter_id} One chapter (prose + metadata).
GET /projects/{project_id}/characters Character list.
GET /projects/{project_id}/export Export the book.

Cover

Method Path Notes
POST /projects/{project_id}/cover Upload a cover image.
GET /projects/{project_id}/cover Fetch the cover image.
DELETE /projects/{project_id}/cover Remove the cover.
POST /projects/{project_id}/cover/generate Generate a cover.
GET /projects/{project_id}/cover/prompt-preview Preview the cover prompt.
GET /projects/{project_id}/cover/with_text Cover with title text rendered.

System

Method Path Notes
GET /health Liveness check.
GET /me Current (seed) user.
GET /system/status DB health, worker activity, 24h job counts.
GET /title-pool Candidate title pool.

Request bodies

POST /projectsname is required.

{
  "name": "motif-registry-verify",
  "title": "Motif Registry Verify",
  "subtitle": null,
  "author_name": null,
  "chapters_total": 10
}

POST /projects/{project_id}/bootstrap — all three fields required.

{
  "premise": "Three estranged siblings empty their late mother's lake house...",
  "genre": "Family drama, Literary fiction",
  "chapter_count": 10
}

Streams Server-Sent Events; each carries a "type" (e.g. motif_registry, error). A run with no "type": "error" event succeeded.

Object shapes

Project

{
  "id": "d8f70bd0-486d-4165-acc5-77cda0f95a44",
  "user_id": "00000000-0000-0000-0000-000000000001",
  "name": "motif-registry-verify",
  "title": "Motif Registry Verify",
  "subtitle": null,
  "state_version": "STATE_V2",
  "chapters_total": 10,
  "cover_image_mime": "image/png",
  "created_at": "2026-05-18T01:06:44.291876Z",
  "updated_at": "2026-05-18T01:17:23.669522Z"
}

Chapter

{
  "id": "34e8327d-0263-4b5d-a148-a82519698aaf",
  "project_id": "d8f70bd0-486d-4165-acc5-77cda0f95a44",
  "chapter_index": 0,
  "title": "Arrivals",
  "summary": "Nora arrives first on Friday afternoon...",
  "primary_beat": "setup",
  "status": "done",
  "attempts": 2
}

Notes