---
title: "Choose the cut's aspect ratio."
method: POST
path: "/trailers/{jobId}/aspect"
tags: ["Trailer"]
---

# Choose the cut's aspect ratio.

`POST /trailers/{jobId}/aspect`

## Request

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

Choose the cut's shape — 9:16 (the default), 16:9 or 1:1 — sent as `{ aspectRatio }`. Free to store, and the useful moment is BEFORE the first render: a shape change never re-renders on its own. On a cut that already rendered, every beat whose takes are at the old shape is kept playable but flagged `clipStale`; rendering it again recompiles at the new shape, and `invalidatedBeats` names the beats now stale. Refused (409) while a render or finish pass is running. Requires `Idempotency-Key`. Scope: `story:write`.

## Headers

- `Idempotency-Key` string, required

## Request body

- object
  - `aspectRatio` '9:16' | '16:9' | '1:1', required: The shape to switch the cut to.

## Response `200`

The cut's shape and the beats now stale at the old one.

- object
  - `aspect` TrailerAspectView, required: The shape the cut renders at, the shape it delivers at the cut's delivery class, and the writer's own pick (null while the default holds). A shape change never re-renders on its own: on a cut that already rendered, every beat whose takes are at the old shape is flagged `clipStale` and named in `invalidatedBeats` (rendering it again recompiles at the new shape).
    - `aspectRatio` '9:16' | '16:9' | '1:1', required: The shape the cut renders at — the writer's choice when chosen, otherwise the default.
    - `chosen` '9:16' | '16:9' | '1:1' | 'null', nullable, required: The raw job column: the writer's choice, or null while the default holds.
    - `width` integer, required: The frame this shape delivers at, in pixels, at the cut's delivery class.
    - `height` integer, required
    - `invalidatedBeats` integer[]: POST only: rendered beats whose takes are at another shape — kept playable, flagged, re-rendered at the new one.

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