---
title: "Start a tour draft for one feature of the project, or for one product moment of a story film."
method: POST
path: "/story-projects/{projectId}/tours/drafts"
tags: ["Sources"]
---

# Start a tour draft for one feature of the project, or for one product moment of a story film.

`POST /story-projects/{projectId}/tours/drafts`

## Request

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

A tour draft is written from the feature’s Bible entry, its pages and the app’s address, is checked by the recorder’s own rules and saved as a drafted tour for you to edit, never opens the app, is for product projects only, and is free — up to 50 a day. A story film’s product moment that still needs a recording can be drafted as its own tour: it types the story’s own names into the app and hesitates where the scene says to, and when its recording is finished it becomes that moment’s recording. `featureId` names the feature (a Series Bible episode); or `source: { kind: 'story_beat', storyId, captureRequestId }` names a story film's product moment that still needs a recording (it names its own feature; one drafting run per moment). `connectionId` optionally names the app connection whose address the draft reads. 202 with the new run; 200 with `alreadyRunning: true` and the run already drafting (no second run starts, so no Idempotency-Key). Poll GET until the run is `ready` or `failed`. 409 `project_not_product` for a story project; 409 `script_state_invalid` for a film with no script or a moment that already uses a recording; 400 for a moment whose side effects a recording may not perform; 403 `usage_limit_reached` past the daily limit.

## Request body

- union: What to draft a tour for — a feature (`featureId`), or one product moment of a story film that still needs a recording (`source`) — and optionally the app connection to read its address through.
  - object
    - `featureId` string, required: The feature (a Series Bible episode) the draft walks through.
    - `connectionId` string: The app connection whose address the draft reads; the run records the connection it used.
  - object
    - `source` StoryBeatTourDraftSource, required: A story film’s product moment that still needs a recording can be drafted as its own tour: it types the story’s own names into the app and hesitates where the scene says to, and when its recording is finished it becomes that moment’s recording.
      - `kind` 'story_beat', required
      - `storyId` string, required: The scripted story film.
      - `captureRequestId` string, required: The product moment (its `[[capture:<id>]]` note in the script) that still needs a recording.
    - `connectionId` string: The app connection whose address the draft reads; the run records the connection it used.

## Response `200`

A run was already drafting: this is it (`alreadyRunning: true`).

- TourDraftStarted: What starting a draft answers: 202 with `alreadyRunning: false` when a run starts, 200 with `alreadyRunning: true` when one was already drafting — the same shape on both.
  - `projectId` string, required
  - `run` TourDraftRun, required: One draft run: what it was drafted from, what came of it, and why (when it failed).
    - `id` string, required
    - `projectId` string, required
    - `featureId` string, required: The product feature (a Series Bible episode) the draft walks through.
    - `source` union, required: What the run was drafted from: the feature itself, or one product moment of a story film that needed a recording.
      - object
        - `kind` 'feature', required
        - `featureId` string, required
      - StoryBeatTourDraftSource: A story film’s product moment that still needs a recording can be drafted as its own tour: it types the story’s own names into the app and hesitates where the scene says to, and when its recording is finished it becomes that moment’s recording.
        - `kind` 'story_beat', required
        - `storyId` string, required: The scripted story film.
        - `captureRequestId` string, required: The product moment (its `[[capture:<id>]]` note in the script) that still needs a recording.
    - `feature` object, nullable, required: The feature as the Bible lists it, or null when the Bible lists it no more.
      - `id` string, required
      - `name` string, required
    - `connectionId` string, nullable, required: The app connection the pages and address were read through, or null when none was named.
    - `origin` string, required: The app connection's origin (the app's https address), snapshotted when the run started.
    - `status` 'drafting' | 'ready' | 'failed', required
    - `interrupted` boolean, required: True when a finished run was cut short.
    - `error` string, nullable, required: The one line that says why the run failed. Null unless `failed`.
    - `errors` string[], required: Everything the check refused in the drafts, readable: the run fails when these cannot be repaired.
    - `tourId` string, nullable, required: The staged tour the draft saved, or null until one (or ever, when `failed`).
    - `repairRounds` integer, required: How many times the drafted document was repaired before it passed the check.
    - `modelId` string, nullable, required
    - `notes` object, nullable, required: What the drafting held back and passed along. Null until `ready` or `failed`.
      - `assumptions` string[], required
      - `questions` string[], required
      - `steps` string[], required
      - `repairNote` string, nullable: BL-615: the line a run re-drafted because the app moved carries, so every read of the run says why. Absent on a run that was not repaired.
    - `startedAt` string, date-time, required
    - `finishedAt` string, date-time, nullable, required
  - `alreadyRunning` boolean, required

## Other responses

- `202`: The new run, `drafting`.
- `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`: `project_not_product` — the project is a story project. PATCH its `kind` to `product` first; nothing was started. `product_video_not_ready` — a story film moment's new tour waits on an app connection Sleeper has proven signed in (`details.step` `app_connected` or `app_signed_in`, `details.next` its verb); `message` is the one shared sentence. Nothing was started.
- `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)
