---
title: "Duplicate a trailer from its current plan onto a new draft (free)."
method: POST
path: "/trailers/{jobId}/duplicate"
tags: ["Trailer"]
---

# Duplicate a trailer from its current plan onto a new draft (free).

`POST /trailers/{jobId}/duplicate`

## Request

- Base URL: `https://docs.sleeperhit.studio/api/v1`
- URL: `https://docs.sleeperhit.studio/api/v1/trailers/{jobId}/duplicate`
- Auth: HTTP bearer

Duplicating a trailer makes a NEW `draft` trailer that carries the source trailer's CURRENT plan — every beat with its edits, its hook, its intent, its montage marks, its black interludes and its closing sequence — and the choices made on the trailer itself (its shape, its audio policy, the narrator cast for it, its delivery class, its film finish, its quiet track and its name), and leaves the source trailer untouched. Nothing rendered rides along: no takes, cuts, masters, versions, share links or coverage reports. It is free and renders and reserves nothing; the copy's plan is queued for coverage, and its next step is approve_trailer_plan on the NEW trailer's jobId (CLI: trailer approve-plan <newJobId>). Any status may be duplicated — a draft, a trailer in review or complete, a failed one — as long as its plan reads as a plan today; one that does not is refused with 409 `trailer_state_invalid` (`details.refusal.code: trailer_duplicate_no_plan`) and nothing is created. A given `title` is the copy's DISPLAY NAME — the name its lists show it by — and never a title for its plan, which comes along unchanged; without one the copy keeps the source's name. NOT metered and NOT confirmed. Requires `Idempotency-Key`. Scope: `story:write`.

## Headers

- `Idempotency-Key` string, required

## Request body

- TrailerDuplicateRequest: Everything is optional: an empty body duplicates the trailer under the source's name.
  - `title` string: The copy's DISPLAY NAME — the name its lists show it by; its plan comes along unchanged. Omitted: the copy keeps the source trailer's name.

## Response `200`

The new draft trailer.

- TrailerDuplicate: Duplicating a trailer makes a NEW `draft` trailer that carries the source trailer's CURRENT plan — every beat with its edits, its hook, its intent, its montage marks, its black interludes and its closing sequence — and the choices made on the trailer itself (its shape, its audio policy, the narrator cast for it, its delivery class, its film finish, its quiet track and its name), and leaves the source trailer untouched. Nothing rendered rides along: no takes, cuts, masters, versions, share links or coverage reports. It is free and renders and reserves nothing; the copy's plan is queued for coverage, and its next step is approve_trailer_plan on the NEW trailer's jobId (CLI: trailer approve-plan <newJobId>).
  - `sourceJobId` string, required: The trailer the plan was copied from. It is untouched.
  - `jobId` string, required: The NEW draft trailer. Every trailer tool takes this id from here on.
  - `status` 'draft', required
  - `title` string, required: The copy's DISPLAY NAME (the name its lists show it by).
  - `beats` integer, required: How many beats the copied plan has.
  - `interludes` integer, required: How many black interludes the copied plan holds.
  - `aspectRatio` string, required: The shape it renders at, carried from the source.
  - `audioPolicy` string, required: `narrate` or `suppress`, carried from the source.
  - `narrator` object, required: The narrator cast for the source trailer, carried to the copy. A null `voiceId`: it had none, so the copy narrates in the default order.
    - `voiceId` string, nullable, required
    - `provider` string, nullable, required
  - `deliveryResolution` string, nullable, required: The delivery class chosen on the source trailer, carried; null when it had none.
  - `planCoverage` 'queued' | 'current' | 'failed' | 'not_needed', required: The copy's plan coverage: `queued` for the new draft, `current` already scored, `failed` when it could not be queued (request it with POST /trailers/{jobId}/storyboard/coverage; approving an unscored plan is refused), or `not_needed` for a trailer with no screenplay (app captures and title cards only), whose plan is never scored.
  - `nextStep` 'approve_trailer_plan', required
  - `reviewUrl` string, nullable, required: A logged-in deep link that opens the copy.
  - `credits` 0, required: Always 0: a duplicate renders and reserves nothing.
  - `note` string, required: What was copied and what happens next, in one paragraph to read out.

## 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 trailer exists and the request is well-formed, but the trailer, its beat, its cast or its plates are not in a state that allows it (`trailer_state_invalid`), and nothing was reserved: a plan approved outside draft, a take chosen or a beat rendered outside review/complete, an export before the finish, a finish while a call has no selected take, a narrated cut with no narrator, a render the compile blocked, or a finish while the master failed its video coverage (`trailer_video_coverage_failed`, with `details.videoCoverage`). `details.refusal` is `{ code, action, fix }` (see TrailerRefusalDetails): `action` is what unblocks it — `recast_figure`, `add_signature_items`, `recast_voice` or `remake_location_plate` — and `fix` names the MCP tool and CLI command that take it; `details.blocked[]` lists every beat a blocked compile could not render. The identical request succeeds once the trailer is put right.
- `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)
