---
title: "List a project's headshot candidate designs."
method: GET
path: "/story-projects/{projectId}/cast-portraits/designs"
tags: ["Projects"]
---

# List a project's headshot candidate designs.

`GET /story-projects/{projectId}/cast-portraits/designs`

## Request

- Base URL: `https://docs.sleeperhit.studio/api/v1`
- URL: `https://docs.sleeperhit.studio/api/v1/story-projects/{projectId}/cast-portraits/designs`
- Auth: HTTP bearer

The project's portrait designs, newest first (at most 50): each with its `status` (queued, drawing, complete, failed), the person it is for (`character`, `castPersonId`), the direction it was drawn from, its candidates (a stable `candidateId`, `index`, `imageUrl`) and the one chosen. `?designId=` reads one design (poll it after a confirmed design); `?character=` narrows to one person. Free. Scope: `story:read`.

## Query parameters

- `designId` string
- `character` string

## Response `200`

The designs.

- CastPortraitDesignListResponse
  - `designs` CastPortraitDesign[], required
    - `designId` string, required
    - `projectId` string, required
    - `castPersonId` string, nullable, required: The cast canon person's stable id, when the canon knew them.
    - `character` string, required
    - `direction` string, required: The look the candidates were drawn from.
    - `directionSource` 'request' | 'cast_canon' | 'series_bible', required
    - `age` string, nullable, required
    - `status` 'queued' | 'drawing' | 'complete' | 'failed', required
    - `error` string, nullable, required
    - `candidateCount` integer, required: How many candidates were bought.
    - `candidates` CastPortraitCandidate[], required
      - `candidateId` string, required: Stable across reads (`<designId>-c<index>`): what a judge scores.
      - `index` integer, required: The number POST .../cast-portraits/choose takes.
      - `status` 'drawn' | 'failed', required
      - `imageUrl` string, nullable, required: The headshot. Null for a candidate that could not be drawn (not charged).
      - `error` string, nullable, required
      - `drawnAt` string, date-time, nullable, required
    - `chosen` object, nullable, required
      - `index` integer, required
      - `candidateId` string, required
      - `imageUrl` string, required
    - `credits` integer, required: Charged for the candidates drawn.
    - `createdAt` string, date-time, required
    - `updatedAt` string, date-time, required
    - `coverage` CastingPortraitCoverage: PORTRAIT CASTING COVERAGE of a portrait design: a model looked at every drawn headshot blind, beside the faces already chosen for the cast, and scored each on emblematic fit, period truth, naturalness (not generated) and distinctness. Choosing a headshot in `failingCandidates` is refused unless the writer chooses it anyway.
      - `status` 'missing' | 'generating' | 'complete' | 'failed', required
      - `kind` 'portrait', required
      - `projectId` string, required
      - `designId` string, required
      - `character` string, required
      - `keyCharacter` boolean, required
      - `available` boolean, required
      - `gateThreshold` number, required
      - `vetoDimensions` string[], required
      - `recommended` integer, nullable, required
      - `failingCandidates` integer[], required
      - `summary` string, required
      - `trigger` 'auto' | 'manual' | 'null', nullable, required
      - `reportId` string, nullable, required
      - `reportVersion` integer, nullable, required
      - `rubricVersion` integer, nullable, required
      - `model` string, nullable, required
      - `progressDetail` string, nullable, required
      - `failureMessage` string, nullable, required: Why the run stopped, as one plain sentence for the writer — never a provider's or the database's raw wording. Populated when `status: failed`.
      - `report` object, nullable, required: The ranking, every headshot (`candidate`, `candidateId`, `imageUrl`, `score`, `passed`, `flags`, `dimensions`, `problems`, `closestCastFace`), `recommended`, `runnerUp`, `close`, `allFail`, `redesign` ({ why, revisedDirection }), `verdict`, `references` and `judging`.
      - `createdAt` string, date-time, nullable, required
      - `updatedAt` string, date-time, nullable, required
    - `restyledFrom` string, nullable, required: A restyle that keeps the face (`keepFace`): the headshot each candidate was edited from. Null for candidates drawn as new faces.

## 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`: No portrait design with that id in this project (`portrait_design_not_found`), or the project is not yours (`project_not_found`).
- `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/86e084144cef?raw)
