---
title: "Read a story project by id, with its readiness preflight."
method: GET
path: "/story-projects/{projectId}"
tags: ["Projects"]
---

# Read a story project by id, with its readiness preflight.

`GET /story-projects/{projectId}`

## Request

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

Returns the project, `project.workspaceGate` — `{ ready, stage, reason, missingFields, canPlan, canStartEpisode, fullCoverage, fullCoverageNotice }` — the same position a gated call (plans, drafting, casting, story jobs, the mood board) refuses with as 409 `project_precondition_failed`, and `project.tableReadReadiness` — `{ ready, audioOnly, reason, narratorVoice, members }` — whether the cast canon lets a table_read job start from a plan (the rule a job refuses with as 409 `cast_precondition_failed`). They are the cheap checks a recurring producer runs before it fetches sources, uploads, plans or creates a job: when `canPlan` or `canStartEpisode` is false, skip the run and finish `stage`; when `tableReadReadiness.ready` is false, complete the cast it names. For a product project, `project.productReadiness` — `{ ready, next, steps }` (null for a story project) — names what is still missing before Sleeper can make its videos by itself (app connected, signed in, features learned, a tour and a recording for every shipped feature) and, as `next`, the one verb to do next. Read-only: reading it never queues or recovers a coverage job.

## Response `200`

Project envelope with its workspace gate.

- StoryProjectDetailEnvelope
  - `project` StoryProjectDetail, required: A project as `getStoryProject` returns it: the project fields plus its `workspaceGate` and `tableReadReadiness`, and on a product project `productReadiness` (null for a story project).
    - `id` string, required
    - `name` string, required
    - `description` string, nullable, required
    - `metadata` object, nullable, required
    - `kind` 'story' | 'product', required: What this project is: `story` or `product`. It picks the coverage rubric its Bible is judged by (`series_bible` for story, `product_bible` for product).
    - `workspaceRole` 'writer' | 'creator' | 'business', nullable, required: Every project is stamped with the workspace role it was made under (`writer`, `creator` or `business`): the creator's current role, or the role the create names. The sidebar's project list shows the current role's projects first, with one click to all of them. Null for a project made before roles were stamped, which shows under every role.
    - `seasonCadence` 'monthly', nullable, required: How a new episode is filed into a season. `monthly`: the season named for the month (UTC) its source material was made (`originatedAt` on the source, else when the source was added, else when the episode was made), created after the last season when the month is new. Null: numbered seasons (the season the plan, its season run or its Series Bible entry names, else Season 1). Stored as `metadata.seasonCadence`.
    - `medium` 'audio' | 'video', nullable, required: What the story is made as: `audio` (a podcast or audio drama: voices, music and sound, no picture) or `video` (for the screen). Read from the Series Bible's `productionMedium` (`audio` is audio, any visual medium is video); null until the Bible says.
    - `recurring` boolean, required: A recurring show: new episodes on a schedule from its sources. True when the project's show is made by Sleeper or by an outside producer under a standing approval.
    - `showSeriesId` string, nullable: The show's publishing series: the id `GET /publishing-series/{seriesId}/show` (MCP get_show, `sleeperhit show get`) takes. Null when the project is not a show.
    - `contentGuard` boolean, required: Keeps every script, plan and Series Bible written for the project suitable for ages 13 and up: no strong profanity, no graphic violence, no sexual content. On for a project started from ChatGPT; off otherwise unless set.
    - `brandLogoUrl` string, nullable, required: The project's brand logo on the studio's media host, or null. A closing sequence can end on it (`logoCard`).
    - `clickSound` object, nullable, required: The project's own click sound, or null for the stock click. A project's click sound is the product's own interface click, played on every press in every screen beat of the project's trailers instead of the studio's stock click: a sound from My Library (`librarySoundId`, that sound's id — import the product's own file there first), with `trimMs` (0–2000) skipping silence at its start and `gainDb` (-24 to +12) levelling it against the stock click once; each click plays at most 400 ms of it. Sent as `clickSound` on the project update, or null to go back to the stock click. A sound that is gone, or too short once trimmed, plays the stock click and the beat says why. Free; the next render of each trailer plays it.
      - `librarySoundId` string, required: The My Library sound it plays.
      - `label` string, required: The sound's name in My Library when it was picked.
      - `url` string, required: The sound's file on the studio's media host.
      - `trimMs` number, required: Milliseconds skipped at its start.
      - `gainDb` number, required: dB over each click's own level.
      - `durationMs` number, nullable, required: Its length, when My Library knows it.
    - `archivedAt` string, date-time, nullable, required
    - `createdAt` string, date-time, required
    - `updatedAt` string, date-time, required
    - `sourceCount` integer
    - `workspaceGate` ProjectWorkspaceGate, required: Where the project stands in development — the readiness preflight. Read-only: reading it never queues or recovers coverage. A gated call refuses with 409 `project_precondition_failed` carrying the same `stage`, `missingFields`, `canPlan` and `canStartEpisode`, so this predicts it exactly. When `ready` is false, finish `stage` before planning, drafting, casting or creating jobs.
      - `ready` boolean, required: Every development stage is finished.
      - `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.
      - `reason` string, nullable, required: How to finish `stage`; null once `ready`.
      - `missingFields` string[], required: What the stage still lacks, when the gate can name it. Often empty: a coverage stage is finished by an act, not a field.
      - `canPlan` boolean, required: Plans, casting and the episode map are allowed now.
      - `canStartEpisode` boolean, required: Episode drafting, story jobs for project media, and publishing are allowed now.
      - `fullCoverage` 'required' | 'advisory', required: `required`: full Series Bible coverage must pass before episodes, project media and publishing. `advisory`: the project is a recurring show (a live publishing series that runs a recurring cadence or holds a standing approval), so premise coverage alone opens it and full coverage is shown but blocks nothing.
      - `fullCoverageNotice` string, nullable, required: For a recurring show: "Full coverage advisory (recurring show): …" plus where full coverage stands. Null for every other project.
      - `acknowledgedCoverage` string[]: Present only when the gate is past a coverage stage because the writer acknowledged a report under the bar (POST .../series-bible/coverage/acknowledge): which ones (`premise`, `full` or `product`).
    - `tableReadReadiness` ProjectTableReadReadiness, required: Whether a table_read story job can start FROM A PLAN right now — the canon-cast rule a job refuses with as 409 `cast_precondition_failed`, read without starting anything. The project's cast canon must cover every character: a voice for everyone and, unless the project is audio-only (Series Bible `productionMedium: "audio"`), a headshot, body shot and character sheet. A narrated read also needs a narrator voice. The job's own `voiceMap` can supply voices the canon lacks, and once the job has written its screenplay any speaker the cast does not cover fails it before any audio, releasing its credits.
      - `ready` boolean, required: Every cast canon character is cast for this medium, so a speaker-only read can start from a plan.
      - `audioOnly` boolean, required: The project is audio-only: members need a voice and nothing else.
      - `reason` string, required: What to finish, or that the cast is complete.
      - `narratorVoice` boolean, required: The canon carries a NARRATOR voice, so a narrated read can start too. Otherwise pass a NARRATOR voice in the job's voiceMap or keep the read speaker-only.
      - `members` object[], required: Each cast canon member and what it still lacks.
        - `name` string, required
        - `narrator` boolean, required
        - `ready` boolean, required
        - `missing` string[], required
    - `productReadiness` ProductReadiness, required: For a product project: What this product still needs before Sleeper can make its videos by itself. The five steps in the order they get done; `next` names the one verb that fixes the first step that is not done. Null for a story project.
      - `ready` boolean, required: Every step is done: nothing stands between this product and videos made by itself.
      - `next` 'connect_app' | 'test_app_login' | 'learn_from_site' | 'draft_tour' | 'record_tour', nullable, required: The first step that is not done, as the verb that fixes it (`connect_app`, `test_app_login`, `learn_from_site`, `draft_tour`, `record_tour`); null when `ready`.
      - `steps` ProductReadinessStep[], required: The five steps in their order: connect the app, sign in, learn the features, a tour for every feature, a recording for every feature.
        - `key` 'app_connected' | 'app_signed_in' | 'features_learned' | 'tours' | 'recordings', required: Which step this is, in list order.
        - `status` 'done' | 'todo' | 'blocked', required: `done`: in place. `todo`: still to do. `blocked`: something failed, and `detail` says what in its own words.
        - `detail` string, required: What is true of this step — "4 of 6 features", the failed sign-in's own message, or when it last signed in. Empty when there is nothing to say.
        - `missing` string[], required: The shipped features a `tours` or `recordings` step still lacks, by name, one entry per feature (a name may hold a comma). Its length is the shortfall `detail` counts. Empty for every other step and for a step that is done.

## Other responses

- `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.
- `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/4534f5d25540?raw)
