The Writer API
Endpoint reference
Every endpoint, grouped by what it costs. Generated from Calliope's OpenAPI 3.1 contract, so it always matches the live API.
Base URL https://app.writecalliope.ink/api/v1. Authenticate every request with your personal key as
Authorization: Bearer cal_… — create one at /account/api.
The machine-readable contract is at
/api/v1/openapi.json; hand it,
plus /api/v1/llms.txt, to an LLM to
have it build your integration.
Authentication
A single bearer scheme (apiKey):
send your key on every call. Keys are shown once, on creation, and only their hash is
stored — see Setup.
Errors
Errors return a stable JSON shape: { "error": code, "message": … }.
| Status | When |
|---|---|
401 | Missing or invalid API key. |
403 | This write needs an active Calliope subscription. |
402 | Out of AI credits (top up to continue). |
404 | Not found, or you don't own it. |
Read — free
7 endpointsGrounded manuscript data. No credits, no subscription.
/books List your books
Responses
-
200— Your books (id + title).
/books/{bookId} Get a book's outline + goal + progress
Parameters
-
bookId· path · required
Responses
-
200— Outline: parts, chapters, goal, recent progress. -
404— Not found, or you don't own it.
/books/{bookId}/search Keyword search across prose + cast (no AI)
Parameters
-
bookId· path · required -
q· query · required — The search text. -
limit· query · optional — Max hits (default 20, max 50).
Responses
-
200— Matching chapters (excerpts) + facts.
/books/{bookId}/facts List the story map (facts / cast)
Parameters
-
bookId· path · required
Responses
-
200— The book's facts.
/facts/{factId} Get one fact + its mentions
Parameters
-
factId· path · required
Responses
-
200— The fact + where it's mentioned.
/books/{bookId}/snippets List marginalia (notes/todos/refs/research)
Parameters
-
bookId· path · required -
chapterId· query · optional — Limit to one chapter.
Responses
-
200— The book's snippets.
/chapters/{chapterId} Read a chapter (prose as text + metadata)
Parameters
-
chapterId· path · required -
format· query · optional — Set to `doc` to get the raw document with paragraph blockIds (needed to target PATCH …/paragraphs).
Responses
-
200— The chapter.
Example
# Free: read a chapter as plain text
curl https://app.writecalliope.ink/api/v1/chapters/CHAPTER_ID \
-H "Authorization: Bearer cal_your_key" AI — spends credits
3 endpointsCalls Calliope's own AI. Metered against your credits (or your subscription allowance). No subscription needed.
/chapters/{chapterId}/synopsis Generate a synopsis (SPENDS CREDITS)
Returns the text only — it does NOT save it. Use PUT to save.
Parameters
-
chapterId· path · required
Responses
-
200— { synopsis }. -
402— Out of AI credits (top up to continue).
/chapters/{chapterId}/detect Detect entities (SPENDS CREDITS)
Proposes map additions. Writes nothing.
Parameters
-
chapterId· path · required
Responses
-
200— Detection proposals. -
402— Out of AI credits (top up to continue).
/chapters/{chapterId}/check Consistency check (SPENDS CREDITS)
Surfaces contradictions + name drift. Writes nothing.
Parameters
-
chapterId· path · required
Responses
-
200— Consistency findings. -
402— Out of AI credits (top up to continue).
Example
# Spends credits: detect entities in a chapter
curl -X POST https://app.writecalliope.ink/api/v1/chapters/CHAPTER_ID/detect \
-H "Authorization: Bearer cal_your_key" Write — subscription only
10 endpointsPersists into your manuscript — including your chapter prose. Needs an active subscription.
/books/{bookId}/facts Add a fact to the map
Parameters
-
bookId· path · required
Request body (required)
Content types: application/json
Responses
-
201— Created (returns the new fact id). -
403— This write needs an active Calliope subscription.
/facts/{factId} Edit a fact
Parameters
-
factId· path · required
Request body (required)
Content types: application/json
Responses
-
200— Updated. -
403— This write needs an active Calliope subscription.
/facts/merge Merge two facts (keepId absorbs dropId)
Request body (required)
Content types: application/json
Responses
-
200— Merged.
/books/{bookId}/snippets Add a snippet (beside the prose, never in it)
Parameters
-
bookId· path · required
Request body (required)
Content types: application/json
Responses
-
201— Created.
/snippets/{snippetId} Replace a snippet's content
Parameters
-
snippetId· path · required
Request body (required)
Content types: application/json
Responses
-
200— Updated.
/snippets/{snippetId} Delete a snippet
Parameters
-
snippetId· path · required
Responses
-
200— Deleted.
/chapters/{chapterId}/prose Replace a chapter's whole prose (your own hand)
Body: `text/markdown` (default) or JSON `{markdown}` or `{doc}` (native document). BlockIds are reconciled so unchanged paragraphs keep their marginalia. Mention marks are dropped (see `mentionsDropped` in the response). Prefer PATCH …/paragraphs/{blockId} for targeted edits.
Parameters
-
chapterId· path · required
Request body (required)
Content types: text/markdown , application/json
Responses
-
200— Saved. Returns { wordCount, blocks, mentionsDropped }. -
403— This write needs an active Calliope subscription.
/chapters/{chapterId}/paragraphs/{blockId} Update ONE paragraph (anchor-safe)
The surgical edit: the paragraph's blockId is kept, so its marginalia survives. Find blockIds via GET /chapters/{id}?format=doc.
Parameters
-
chapterId· path · required -
blockId· path · required
Request body (required)
Content types: text/markdown , application/json
Responses
-
200— Saved. Returns { wordCount, mentionsDropped }. -
404— No paragraph with that blockId (or chapter not yours).
/chapters/{chapterId}/status Set chapter status
Parameters
-
chapterId· path · required
Request body (required)
Content types: application/json
Responses
-
200— Updated.
/chapters/{chapterId}/synopsis Save the synopsis field (never prose)
Parameters
-
chapterId· path · required
Request body (required)
Content types: application/json
Responses
-
200— Saved.
Example
# Subscription: edit ONE paragraph (anchor-safe — marginalia survives)
curl -X PATCH https://app.writecalliope.ink/api/v1/chapters/CHAPTER_ID/paragraphs/BLOCK_ID \
-H "Authorization: Bearer cal_your_key" \
-H "Content-Type: text/markdown" \
--data 'The rewritten paragraph text.'