---
title: "Read one product video plan run."
method: GET
path: "/story-projects/{projectId}/product-video-plans/{runId}"
tags: ["Trailer"]
---

# Read one product video plan run.

`GET /story-projects/{projectId}/product-video-plans/{runId}`

## Request

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

Where one plan run is (`queued` → `planning` → `ready`, or `failed` — a run left behind by an interrupted worker reads `failed` with a plain sentence to ask again), the request it runs, and once ready its `trailerJobId`, `reviewUrl`, the conversation bound to the draft, `nextStep: approve_trailer_plan` and its live plan check (`coverage`, which follows later beat edits). Another account's or project's run is 404 `product_video_plan_not_found`. Planning a product video turns one feature of the project's feature map, or a named release and its features, and the project's recorded captures into an ordinary `draft` trailer — each beat names its capture, the stretch of it it plays, a narrated line, whether the beat keeps its own sound, and its depth — and it is free: it answers at once, the run is polled until it is `ready`, and the result is an ordinary capture-only draft trailer approved with `approve_trailer_plan`. A read: it never plans, renders or edits. Scope: `story:read`.

## Response `200`

The run.

- object
  - `run` ProductVideoPlanRun, required: One plan run: where it is, the request it runs, and the draft trailer it made.
    - `id` string, required
    - `projectId` string, required
    - `status` 'queued' | 'planning' | 'ready' | 'failed', required: `queued` to `planning` to `ready`, or `failed`. A run left behind by an interrupted worker reads `failed` with a plain sentence to ask again.
    - `request` PlanProductVideoRequest, required: The request one plan run stores and runs. Planning a product video turns one feature of the project's feature map, or a named release and its features, and the project's recorded captures into an ordinary `draft` trailer — each beat names its capture, the stretch of it it plays, a narrated line, whether the beat keeps its own sound, and its depth — and it is free: it answers at once, the run is polled until it is `ready`, and the result is an ordinary capture-only draft trailer approved with `approve_trailer_plan`. A strict body: an unknown key is 400 `validation_failed` naming it.
      - `scope` union, required: What the video covers: one feature of the feature map, or a named release and the features it ships. Planning a product video turns one feature of the project's feature map, or a named release and its features, and the project's recorded captures into an ordinary `draft` trailer — each beat names its capture, the stretch of it it plays, a narrated line, whether the beat keeps its own sound, and its depth — and it is free: it answers at once, the run is polled until it is `ready`, and the result is an ordinary capture-only draft trailer approved with `approve_trailer_plan`.
        - object: One feature of the feature map.
          - `kind` 'feature', required: `feature` (one feature of the feature map).
          - `featureId` string, required: The feature's id, as the feature map lists it. 400 `validation_failed` (`details.features`) when it is not on the map; a `planned` feature is refused the same way (`details.availability`): a video never shows something not shipped.
        - object: A named release and the features it ships.
          - `kind` 'release', required: `release` (a named release and its features).
          - `name` string, required: The release's name. A release with a feature the plan does not cover is named in `uncoveredFeatures` with its reason, and the plan check warns.
          - `featureIds` string[], required: The distinct features the release ships (2 to 8).
      - `targetSeconds` integer: Seconds of finished cut the planner aims for (10–360); default 30 for a feature, 60 for a release (the default follows the scope kind, so none is fixed here).
      - `aspectRatio` '16:9' | '9:16' | '1:1': The shape it plays at; every capture it plays must have it.
      - `title` string: The draft trailer's own name; omitted: the planner names it after the scope.
      - `notes` string: Free notes for the planner — the audience, the moment that matters, what to lead with (at most 2000 characters).
      - `reference` object: Pace the plan by a reference film (references by refs; product projects only): ONLY its REF id travels, from a card POST /story-projects/{projectId}/references showed. The planner reads its pacing numbers, never its content.
        - `refsId` string, required: A REF id, e.g. `REF-3007`.
      - `destinationKey` string: The destination this plan is cut for: a video destination key, as `destinations[].key` lists it. Omitted: the plan follows the deliverable it is made from, resolved when the run plans it.
      - `music` 'score' | 'none': The music the draft carries. `music` is `score` (the default: the draft is scored to picture, free — a sketch to the planned cut plays before anything renders, and the score is composed to the first cut and laid under it) or `none` (no music bed). Only `none` is stored on the run's request.
    - `trailerJobId` string, nullable, required: The draft trailer it made (`TrailerJob.id`), once ready.
    - `reviewUrl` string, nullable, required: A logged-in deep link to the draft trailer on the project's Videos page, once ready.
    - `conversationId` string, nullable, required: The Slug conversation bound to the draft trailer, when the workspace gives it one.
    - `error` string, nullable, required: A plain sentence for the writer when it failed; null until then.
    - `modelUsed` string, nullable, required
    - `nextStep` 'approve_trailer_plan' | 'null', nullable, required: Always `approve_trailer_plan` once ready.
    - `coverage` ProductVideoPlanCoverage, required: The plan check of one planned draft: what it covers, what is wrong, and whether it may be approved. Blocking findings gate `approve_trailer_plan`.
      - `status` 'pass' | 'warn' | 'blocked', required: `blocked` when anything blocks, otherwise `warn` when anything warns, otherwise `pass`.
      - `totalSeconds` number, required: The length the plan cuts to.
      - `targetSeconds` number, required: The length the request aimed for.
      - `features` object[], required: The scope's features, with the beats (1-based) that cover each.
        - `featureId` string, required
        - `name` string, required
        - `availability` string, required
        - `beats` integer[], required
        - `covered` boolean, required
      - `findings` object[], required: Everything the check found, each with its fix. Blocking findings exist for an unplayable capture, a blank beat, a feature outside the Bible or now `planned`, a scope feature or release covered by no beat, and a cut over 90 seconds; the rest warn.
        - `severity` 'blocking' | 'warning', required
        - `code` 'capture_unplayable' | 'blank_beat' | 'feature_not_in_bible' | 'feature_planned' | 'feature_uncovered' | 'release_uncovered' | 'over_max_seconds' | 'release_feature_uncovered' | 'narration_too_long' | 'keeps_sound_silent' | 'beat_unlinked' | 'feature_beta' | 'narrator_missing' | 'runtime_off_target' | 'pace_off_reference', required
        - `beat` integer: The 1-based beat number, when one beat is named.
        - `featureId` string: The feature id, when one feature is named.
        - `message` string, required
        - `fix` string, required: What puts it right.
    - `reference` ReferencePick, required: The reference chosen for a video or a plan: its card as it was when chosen.
      - `refsId` string, required
      - `url` string, required
      - `credit` 'References by refs', required
      - `title` string, required
      - `by` string, required
      - `category` string, required
      - `durationSeconds` number, nullable, required
      - `aspect` '16:9' | '9:16' | '1:1' | 'null', nullable, required
      - `pacing` ReferencePacing, required: A reference film's pacing NUMBERS — the whole of what a reference lends a plan. `maxShotSeconds` is our bound (twice the average shot); the rest are the film's measured metrics. Loudness is shown for information: delivery loudness follows the export target.
        - `avgShotSeconds` number, nullable, required
        - `maxShotSeconds` number, nullable, required
        - `cutsPerMinute` number, nullable, required
        - `firstCutSeconds` number, nullable, required
        - `shots` integer, nullable, required
        - `hasVoice` boolean, nullable, required
        - `referenceLufs` number, nullable, required
      - `thumbnailUrl` string, nullable, required: The film's poster still from our storage, or null (see ReferenceCard).
      - `stillUrls` string[], required
      - `embed` ReferenceEmbed, required: How to play a reference film in place: its original post, through that platform's own player. Frame `embedUrl` (muted where the platform allows it, never autoplaying); never download, proxy or rehost the film.
        - `provider` 'youtube' | 'x' | 'vimeo', required
        - `videoId` string, required: The platform's id of the video or post.
        - `embedUrl` string, uri, required: The player to frame: `https://www.youtube-nocookie.com/embed/<id>`, `https://platform.twitter.com/embed/Tweet.html?id=<id>` or `https://player.vimeo.com/video/<id>`, with its muting and privacy parameters.
        - `sourceUrl` string, uri, required: The original post.
      - `pickedAt` string, required
    - `createdAt` string, required
    - `updatedAt` string, required
    - `finishedAt` string, nullable, required

## 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)
