---
title: "Price, then run, the finish of a trailer."
method: POST
path: "/trailers/{jobId}/finish"
tags: ["Trailer"]
---

# Price, then run, the finish of a trailer.

`POST /trailers/{jobId}/finish`

## Request

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

Finishes the cut: every selected take is upscaled from its 480p render to the delivery class — 720p unless the writer asked for 1080p (`deliveryResolution`, else the trailer's own class) — the on-screen text layers are composited over the finished cut, and the finished master is stitched. Nothing is generated again, and a take already finished at the class is reused, not charged twice. TWO CALLS, PRICE FIRST: sent WITHOUT `confirmed` it prices the finish and reserves nothing (`quotedOnly: true`, the `lines`, and a `warnings` entry per flagged take the writer kept); sent again with `confirmed: true` it reserves exactly those lines and starts the finish (`finishing`, then `complete`). Refused before the price while any call has no selected take (a call with no accepted take: render it again), and while the master the writer is looking at FAILED its video coverage (`trailer_video_coverage_failed`, `details.videoCoverage`: the score, the bar and the findings with their fixes) — unless `acknowledgeVideoCoverage: true`, which only the writer's own choice to finish anyway may set. Coverage still running, one that could not run, or one of an earlier master never holds the finish: the quote's `warnings` say so. A trailer with no screenplay is finished from its app captures and title cards with no take to upscale, and is refused (`trailer_capture_only`, naming the beats) while any beat is blank or no beat plays a capture. Review or complete (finishing again at a new class) only. Requires `Idempotency-Key`. Scope: `artifact:publish`.

## Headers

- `Idempotency-Key` string, required

## Request body

- TrailerFinishRequest: Finish the cut at the delivery class, and say whether this call is the price or the purchase.
  - `deliveryResolution` '720p' | '1080p': Omit to finish at the trailer's delivery class (720p unless chosen).
  - `confirmed` boolean: Omit (or false) to get the finish price WITHOUT spending anything. Send true only after the writer has seen that price and said go.
  - `acknowledgeVideoCoverage` boolean: Finish although the master the writer is looking at FAILED its video coverage (otherwise refused with 409 `trailer_video_coverage_failed`, `details.videoCoverage` carrying the score, the bar and the findings). Send true ONLY after the writer has seen those findings and chosen, in their own words, to finish anyway — never on your own.

## Response `200`

The finish price (no `confirmed`) or the running finish.

- TrailerFinishAnswer: Either the PRICE of the finish or the running finish — branch on `quotedOnly`.
  - `quotedOnly` boolean, required
  - `queued` boolean: Confirmed call only.
  - `jobId` string, required
  - `deliveryResolution` '720p' | '1080p', required
  - `credits` number, required
  - `costLabel` string, nullable: Quote only.
  - `lines` object[]: Quote only. One line per selected take upscaled (a take already finished at the class is not charged again) and one per beat's on-screen text layer.
    - `idempotencyKey` string
    - `label` string
    - `credits` number
    - `kind` 'finish' | 'text'
    - `callId` string, nullable
    - `take` integer, nullable
    - `beatIndex` integer, nullable
    - `seconds` number, nullable
  - `takes` integer: Confirmed call only: how many selected takes the finish upscales.
  - `warnings` string[], required: One per selected take the writer kept although it was flagged (a line not heard or in another character's voice, an opening off its plan).
  - `balanceAfter` integer: Quote only. Studio Credits the writer would have left once this is spent: the balance available now (as Billing shows it) minus the price. Negative means they are that many short.
  - `sufficient` boolean: Quote only. True when the available balance covers the price. False means the writer must top up first (the note names the Billing link) — do not confirm; the reserve would refuse.
  - `note` string: Quote only: the price in the writer's words and how to proceed.
  - `message` string: Confirmed call only.

## Other responses

- `400`: Request payload failed validation. The error message names the offending field.
- `401`: Missing, malformed, revoked, or expired API key.
- `402`: Not enough Studio Credits to reserve this job (`insufficient_credits`), and nothing was reserved. `details` is InsufficientCreditsDetails: `required` and `available`, and `autoTopup` when auto top-up is on but did not cover it — `pending` (retry in a moment), `over_cap` (raise the monthly spending cap), `too_small` (buy a bigger pack) or `failed`.
- `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/64c1102ccb2f?raw)
