---
title: "Duplicate a deck from its current plan onto a new draft (free)."
method: POST
path: "/pitch-decks/{jobId}/duplicate"
tags: ["Pitch Deck"]
---

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

`POST /pitch-decks/{jobId}/duplicate`

## Request

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

Duplicating a deck makes a NEW `draft` deck that carries the source deck's CURRENT plan — every chapter with its edits, the deck's intent, its black interludes and montage marks — and the choices made on the deck itself (the narrator cast for it, its delivery class, its strategic target), and leaves the source deck untouched. Nothing rendered rides along: no takes, cuts, masters, 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_pitch_deck_plan on the NEW deck's jobId (CLI: pitch-deck approve-plan <newJobId>). Any status may be duplicated — a draft, a deck in review or complete, a failed deck — as long as its plan reads as a plan today; one that does not is refused with 409 `pitch_deck_state_invalid` (`details.refusal.code: pitch_deck_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

- PitchDeckDuplicateRequest: Everything is optional: an empty body duplicates the deck 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 deck's name.

## Response `200`

The new draft deck.

- PitchDeckDuplicate: Duplicating a deck makes a NEW `draft` deck that carries the source deck's CURRENT plan — every chapter with its edits, the deck's intent, its black interludes and montage marks — and the choices made on the deck itself (the narrator cast for it, its delivery class, its strategic target), and leaves the source deck untouched. Nothing rendered rides along: no takes, cuts, masters, 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_pitch_deck_plan on the NEW deck's jobId (CLI: pitch-deck approve-plan <newJobId>).
  - `sourceJobId` string, required: The deck the plan was copied from. It is untouched.
  - `jobId` string, required: The NEW draft deck. Every deck tool takes this id from here on.
  - `status` 'draft', required
  - `deckMode` 'pitch' | 'showcase', required
  - `title` string, required: The copy's DISPLAY NAME (the name its lists show it by).
  - `chapters` integer, required: How many chapters the copied plan has.
  - `interludes` integer, required: How many black interludes it carries.
  - `narrator` object, required: The narrator cast for the source deck, carried to the copy. A null `voiceId`: it had none, so the copy narrates in the default order (the cast canon's NARRATOR, else the table read's, else the default).
    - `voiceId` string, nullable, required
    - `provider` string, nullable, required
  - `deliveryResolution` string, nullable, required: The delivery class chosen on the source deck, carried; null when it had none.
  - `planCoverage` 'queued' | 'current' | 'failed', required: The copy's plan coverage: `queued` for the new draft, `current` already scored, or `failed` when it could not be queued (request it with POST /pitch-decks/{jobId}/storyboard/coverage; approving an unscored plan is refused).
  - `nextStep` 'approve_pitch_deck_plan', required
  - `reviewUrl` string, nullable, required: A logged-in deep link to the deck list the copy appears in.
  - `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

- `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 pitch deck exists and the request is well-formed, but the deck, its chapter, its cast or its plates are not in a state that allows it (`pitch_deck_state_invalid`), and nothing was reserved: a plan approved outside draft, a take chosen, a chapter edited or rendered outside review/complete, an export before the finish, a finish while a call has no selected take or a footage chapter has not rendered, a text-only chapter asked for footage, a changed chapter asked for one call, a delivery class changed mid-pass, a render the compile blocked, or a finish while the master failed its video coverage (`pitch_deck_video_coverage_failed`, with `details.videoCoverage`). `details.refusal` is `{ code, action, fix }` (see PitchDeckRefusalDetails): `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 chapter a blocked compile could not render. The identical request succeeds once the deck 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/64c1102ccb2f?raw)
