---
title: "Save the project Series Bible."
method: PATCH
path: "/story-projects/{projectId}/series-bible"
tags: ["Projects"]
---

# Save the project Series Bible.

`PATCH /story-projects/{projectId}/series-bible`

## Request

- Base URL: `https://docs.sleeperhit.studio/api/v1`
- URL: `https://docs.sleeperhit.studio/api/v1/story-projects/{projectId}/series-bible`
- Auth: HTTP bearer

Stores caller-authored project canon, episode map, character roster, style, and audio direction. This is the same project document the web UI edits and the MCP/CLI tools read. Complete the full bible before screenplay generation when possible; that is guidance, not an enforcement block. One change IS gated: writing the episode map before the project can plan (premise coverage passed, canon complete) is refused with 409 `project_precondition_failed`, and `details.stage` names the stage to finish. Every save returns `gateChange` { before, after, staleCoverage }: what it did to the project's gate. Appending (episodes for a new season, a new character) never re-locks anything. An edit to canon a coverage report scored puts that report out of date (`staleCoverage`) and re-locks what it opened: after full coverage, paid work on every episode already written (coverage, casting, table reads, videos, decks, trailers, publishing) until full coverage passes again. When `after.stage` comes before `before.stage`, tell the user.

## Request body

- SeriesBiblePatch
  - `title` string
  - `content` SeriesBibleContentPatch, required: Partial Series Bible content payload accepted by PATCH; the server fills missing fields with their normalized defaults.
    - `logline` string
    - `format` string
    - `genre` string
    - `audience` string
    - `tone` string
    - `premise` string
    - `seasonArc` string
    - `themes` string
    - `productionMedium` 'live_action' | 'two_d_animation' | 'three_d_animation' | 'stop_motion' | 'claymation' | 'anime' | 'documentary' | 'hybrid' | 'audio' | 'unknown'
    - `characterReferencePolicy` 'identity_only' | 'identity_and_style' | 'model_sheet_reference' | 'ignore_style_use_identity'
    - `visualStyle` string
    - `characterDesign` string
    - `visualTruths` string
    - `productionDesign` string
    - `colorPalette` string
    - `lightingRules` string
    - `cameraLanguage` string
    - `directorStyle` '' | 'malick' | 'fincher' | 'coen' | 'villeneuve' | 'tarantino' | 'wes_anderson'
    - `typography` SeriesBibleTypographyPatch: Partial typography block accepted by PATCH. Keys you send are merged over the saved block; keys you omit are preserved.
      - `direction` string
      - `titleFace` '' | 'chunky_sans' | 'grotesque_sans' | 'condensed_sans' | 'classical_serif' | 'typewriter'
      - `titleColor` string
      - `titleCase` '' | 'upper' | 'as_written'
      - `titleWeight` integer
      - `bodyFace` '' | 'chunky_sans' | 'grotesque_sans' | 'condensed_sans' | 'classical_serif' | 'typewriter'
      - `bodyColor` string
    - `locationTruths` string
    - `audioStyle` string
    - `writingStyle` string
    - `worldRules` string
    - `canonTimeline` string
    - `openQuestions` string
    - `notes` string
    - `product` SeriesBibleProductBlockPatch: Partial product block accepted by PATCH. Keys you send are merged over the saved block; keys you omit are preserved.
      - `alternatives` string
      - `positioning` string
      - `cta` string
      - `doNotClaim` string
      - `compliance` string
    - `episodes` SeriesBibleEpisodePatch[]
      - `id` string
      - `label` string
      - `title` string
      - `summary` string
      - `status` string
      - `availability` '' | 'unknown' | 'shipped' | 'beta' | 'planned'
      - `evidenceIds` string[]
      - `seasonNumber` integer
    - `seasons` SeriesBibleSeason[]: Season arcs by `number`: arrayMode merge replaces the arcs sent and keeps the rest; replace sends them all.
      - `number` integer, required
      - `arc` string, required: What happens in this season.
    - `characters` SeriesBibleCharacterPatch[]
      - `id` string
      - `name` string
      - `role` string
      - `want` string
      - `wound` string
      - `arc` string
      - `voice` string
      - `relationships` string
      - `appearance` string
      - `wardrobe` string
      - `movement` string
  - `arrayMode` 'merge' | 'replace': How episodes[]/characters[] reconcile with the stored arrays. Defaults to "merge" (upsert by id, unsent items survive). Send "replace" with a whole-document save so items you removed disappear.

## Response `200`

The saved Series Bible and what the save did to the project's gate.

- SeriesBibleSaveResult
  - `document` SeriesBibleDocument, required
    - `id` string, required
    - `projectId` string, required
    - `kind` 'series_bible', required
    - `title` string, nullable, required
    - `content` SeriesBibleContent, required: Project-level canon and continuity shared by UI, API, CLI, and MCP.
      - `logline` string, required
      - `format` string, required
      - `genre` string, required
      - `audience` string, required
      - `tone` string, required
      - `premise` string, required
      - `seasonArc` string, required
      - `themes` string, required
      - `productionMedium` 'live_action' | 'two_d_animation' | 'three_d_animation' | 'stop_motion' | 'claymation' | 'anime' | 'documentary' | 'hybrid' | 'audio' | 'unknown', required: Binding production medium. Image and video rendering require a value other than unknown.
      - `characterReferencePolicy` 'identity_only' | 'identity_and_style' | 'model_sheet_reference' | 'ignore_style_use_identity', required: How canonical portrait, body, and character-sheet assets constrain generated production images.
      - `visualStyle` string, required
      - `characterDesign` string, required: Project-wide portrait and body-design language used with canonical cast assets.
      - `visualTruths` string, required: Non-negotiable visual facts and forbidden drift for every generated image.
      - `productionDesign` string, required: Sets, props, textures, materials, signage, and recurring production-design vocabulary.
      - `colorPalette` string, required: Canonical color, saturation, contrast, and accent-color rules.
      - `lightingRules` string, required: Motivated light sources, time-of-day logic, exposure, contrast, and atmosphere.
      - `cameraLanguage` string, required: Canonical shot sizes, lenses, heights, movements, speeds, tracking rules, and forbidden camera behavior.
      - `directorStyle` '' | 'malick' | 'fincher' | 'coen' | 'villeneuve' | 'tarantino' | 'wes_anderson', required: Optional camera-grammar layer applied to generated shots. Empty string means no director layer.
      - `typography` SeriesBibleTypography, required: Type identity inherited by every trailer, pitch deck, and episode rendered for this project.
        - `direction` string, required: Prose direction for how the type should feel and behave on screen. Read by prompts, not by the compositor.
        - `titleFace` '' | 'chunky_sans' | 'grotesque_sans' | 'condensed_sans' | 'classical_serif' | 'typewriter', required: Face for titles, credits, and on-screen text. Empty string means the renderer default.
        - `titleColor` string, required: Hex colour such as "#8A0303". Empty string means the renderer default.
        - `titleCase` '' | 'upper' | 'as_written', required: Whether a title card forces capitals or preserves the copy as written.
        - `titleWeight` integer, required: CSS weight 100-900. 0 means unset, and the renderer picks the weight the chosen face exists for.
        - `bodyFace` '' | 'chunky_sans' | 'grotesque_sans' | 'condensed_sans' | 'classical_serif' | 'typewriter', required: Face for subtitles, lower thirds, and supporting copy.
        - `bodyColor` string, required: Hex colour for body copy. Empty string means the renderer default.
      - `locationTruths` string, required: Stable location geography, entrances, sightlines, recurring zones, and location-specific facts.
      - `audioStyle` string, required
      - `writingStyle` string, required
      - `worldRules` string, required
      - `canonTimeline` string, required
      - `openQuestions` string, required
      - `notes` string, required
      - `product` SeriesBibleProductBlock, required: The product block of a product project’s Bible: what the buyer uses today, where the product sits, the one action the audience takes, what may never be claimed, and the compliance boundaries.
        - `alternatives` string, required
        - `positioning` string, required
        - `cta` string, required
        - `doNotClaim` string, required
        - `compliance` string, required
      - `episodes` SeriesBibleEpisode[], required
        - `id` string, required: The episode's id: stored once and never changed, never reused for another entry.
        - `label` string, required: Episode/installment label such as "Episode 1" or "Pilot".
        - `title` string, required
        - `summary` string, required
        - `status` string, required: Planning state, e.g. planned, drafted, table read ready, complete.
        - `availability` '' | 'unknown' | 'shipped' | 'beta' | 'planned', required: Whether the thing exists for a user (a product project's feature): shipped, beta, planned or unknown. Its own axis, deliberately not `status`; empty for a story installment.
        - `evidenceIds` string[], required: The discovery evidence this feature is claimed on (feature-inventory evidence ids), one id per entry.
        - `seasonNumber` integer, required: The season this episode is planned in: its one season number (a script written for it moves with it).
      - `seasons` SeriesBibleSeason[], required: Each season's arc, in season order. `seasonArc` is the whole show's arc.
        - `number` integer, required
        - `arc` string, required: What happens in this season.
      - `characters` SeriesBibleCharacter[], required
        - `id` string, required
        - `name` string, required
        - `role` string, required
        - `want` string, required
        - `wound` string, required
        - `arc` string, required
        - `voice` string, required
        - `relationships` string, required
        - `appearance` string, required: Binding visual identity details that supplement the canonical avatar and model sheet.
        - `wardrobe` string, required: Canonical wardrobe silhouette, materials, colors, and permitted changes.
        - `movement` string, required: Posture, gait, gesture vocabulary, and recurring physical behavior.
    - `references` SeriesBibleReference[], required: Project-scoped human names and safe links for reading canonical reference keys. Not Bible content: never PATCH this index or replace evidenceIds with labels. GET leaves canon and its version unchanged.
      - `id` string, required: Canonical key, unchanged in content/evidenceIds.
      - `kind` 'source' | 'page' | 'claim' | 'feature', required
      - `label` string, required: Project-owned human name; Source unavailable when its target cannot be read.
      - `href` string, uri, nullable, required
      - `available` boolean, required: Whether this reference target resolves. This does not confirm a claim or change feature availability; those remain in canonical content and the claims ledger.
    - `readiness` object, required
      - `development` object, required
        - `ready` boolean, required
        - `completedFields` integer, required
        - `totalFields` integer, required
        - `missingFields` string[], required
      - `moodBoard` object, required
        - `ready` boolean, required
        - `missingFields` string[], required
    - `generatedFrom` object, nullable, required
    - `currentVersion` integer, required
    - `createdAt` string, date-time, required
    - `updatedAt` string, date-time, required
    - `renderContext` SeriesRenderContext, required: What renders derive FROM the Series Bible and keep, per Bible version. Read-only: it is derived, never written through the Bible.
      - `periodNegatives` object, required: This series' period world, derived from the Bible's period, place and tone once per Bible version: the world as it is (`indoors`, `outdoors`), which every reference render (decks, trailers and their re-renders) is told after the series canon, and the anachronisms it never has (`negatives`), which every take is checked for and which are never sent to the video model as a list. Empty for a contemporary series.
        - `status` 'current' | 'stale' | 'not_derived' | 'no_bible', required: current: derived from this Bible version, sent by every render. stale: derived from an earlier version; the next render derives it again first. not_derived: no render has derived it yet; the first one will. no_bible: no Series Bible, nothing excluded.
        - `derivedFromBibleVersion` integer, nullable, required
        - `world` string, required: When and where the Bible sets this world, as the list was derived from it (e.g. "1870s provincial Russia").
        - `indoors` string, required: The world as it is indoors, in positive words — what lights, heats and furnishes its rooms. What every render of an interior is told. Empty for a contemporary series.
        - `outdoors` string, required: The world as it is outdoors, in positive words — its streets, roads, transport and skyline. What every render of an exterior is told. Empty for a contemporary series.
        - `negatives` string[], required: What this world never has: what every take is checked for. Never sent to the video model.
        - `derivedAt` string, date-time, nullable, required
  - `gateChange` SeriesBibleGateChange, required: Every save returns `gateChange` { before, after, staleCoverage }: what it did to the project's gate. Appending (episodes for a new season, a new character) never re-locks anything. An edit to canon a coverage report scored puts that report out of date (`staleCoverage`) and re-locks what it opened: after full coverage, paid work on every episode already written (coverage, casting, table reads, videos, decks, trailers, publishing) until full coverage passes again. When `after.stage` comes before `before.stage`, tell the user.
    - `before` SeriesBibleGatePosition, required: The project's workspace gate at one moment.
      - `stage` 'premise' | 'premise_coverage' | 'planning' | 'full_coverage' | 'ready', required: The project development stage, in order: develop the premise, pass premise coverage, plan the episode map, pass full Series Bible coverage, then `ready`. The mood board is not a stage: it opens after premise coverage and blocks nothing.
      - `ready` boolean, required
      - `canPlan` boolean, required: Planning seasons and casting at project level.
      - `canStartEpisode` boolean, required
      - `canGenerateProjectMedia` boolean, required: Paid work on every episode already written (coverage, casting, table reads, videos, decks, trailers, publishing) and project media.
      - `reason` string, nullable, required: What to do next when the gate is closed; null when it is open.
    - `after` SeriesBibleGatePosition, required: The project's workspace gate at one moment.
      - `stage` 'premise' | 'premise_coverage' | 'planning' | 'full_coverage' | 'ready', required: The project development stage, in order: develop the premise, pass premise coverage, plan the episode map, pass full Series Bible coverage, then `ready`. The mood board is not a stage: it opens after premise coverage and blocks nothing.
      - `ready` boolean, required
      - `canPlan` boolean, required: Planning seasons and casting at project level.
      - `canStartEpisode` boolean, required
      - `canGenerateProjectMedia` boolean, required: Paid work on every episode already written (coverage, casting, table reads, videos, decks, trailers, publishing) and project media.
      - `reason` string, nullable, required: What to do next when the gate is closed; null when it is open.
    - `staleCoverage` string[], required: The coverage reports that spoke for the Bible before this save and no longer do (`premise` and `full` on a story project; `product`, the one product-Bible report, on a product project). Empty for an append or a visual edit.

## Other responses

- `400`: Request payload failed validation. The error message names the offending field.
- `401`: Missing, malformed, revoked, or expired API key.
- `403`: API key is valid but lacks the scope, is blocked by IP allowlist, or the account is disabled.
- `404`: The named project or source does not exist or is owned by another account.
- `409`: The project has not reached the development stage this call needs (`project_precondition_failed`), and nothing was created, queued or charged. `details` is ProjectPreconditionDetails: `stage` names the stage to finish, `missingFields` what it still lacks, `canPlan` / `canStartEpisode` what the project can do now. Finish the named stage — do not retry; the identical call refuses the same way until it is done.
- `429`: Rate limit for this API key + IP + route family was exceeded.
- `500`: The API failed unexpectedly. Safe to retry with the same Idempotency-Key.

---

[API](https://skmtc.dev/sleeperhit/apis/sleeper-hit-studio-story-api.md) · [All operations](https://skmtc.dev/sleeperhit/apis/sleeper-hit-studio-story-api/llms.txt) · [OpenAPI document](https://skmtc.dev/sleeperhit/apis/sleeper-hit-studio-story-api/revisions/64c1102ccb2f?raw)
