Calliope

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": … }.

StatusWhen
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 endpoints

Grounded manuscript data. No credits, no subscription.

get /books

List your books

Responses

  • 200 — Your books (id + title).
get /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.
get /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.
get /books/{bookId}/facts

List the story map (facts / cast)

Parameters

  • bookId · path · required

Responses

  • 200 — The book's facts.
get /facts/{factId}

Get one fact + its mentions

Parameters

  • factId · path · required

Responses

  • 200 — The fact + where it's mentioned.
get /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.
get /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 endpoints

Calls Calliope's own AI. Metered against your credits (or your subscription allowance). No subscription needed.

post /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).
post /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).
post /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 endpoints

Persists into your manuscript — including your chapter prose. Needs an active subscription.

post /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.
patch /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.
post /facts/merge

Merge two facts (keepId absorbs dropId)

Request body (required)

Content types: application/json

Responses

  • 200 — Merged.
post /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.
patch /snippets/{snippetId}

Replace a snippet's content

Parameters

  • snippetId · path · required

Request body (required)

Content types: application/json

Responses

  • 200 — Updated.
delete /snippets/{snippetId}

Delete a snippet

Parameters

  • snippetId · path · required

Responses

  • 200 — Deleted.
put /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.
patch /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).
put /chapters/{chapterId}/status

Set chapter status

Parameters

  • chapterId · path · required

Request body (required)

Content types: application/json

Responses

  • 200 — Updated.
put /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.'