> ## Documentation Index
> Fetch the complete documentation index at: https://docs.aurous-labs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Remove a view from a draft

> Empty one named view on a draft so the next build renders it instead of keeping your photo.

`DELETE /v1/characters/{id}/refs/{view}` empties **one** of the eight named views on a `draft`, so the next [`POST /v1/characters/{id}/build`](/api-reference/characters/build-character) renders that view instead of keeping the photo you filed. The response is the full character with the updated `views[]` and a recalculated `build` — the emptied view is back in `build.missing_views`, and `build.cost_credits` has gone up by one view's price.

**Drafts only.** Any other status returns `400 character_status_invalid` with `param: character_id` — replace the view with a new upload instead of removing it.

Never charges, and **idempotent**: a view that holds no reference returns `200` with the character unchanged.

## When to use

* You filed the wrong photo into a view and would rather the platform render it.
* You want to shrink an assembled draft back toward "let the platform do it" before building.

To *replace* a view rather than empty it, `PUT` a new photo into it — see [Put a photo into a view](/api-reference/characters/put-ref). That works on `draft`, `failed`, `reviewing` and `ready` alike.

## Examples

<CodeGroup>
  ```bash cURL theme={null}
  curl -X DELETE https://api.aurous-labs.com/v1/characters/char_01HXMQ7Z3K8Y2VNABCDEFGHJKM/refs/upper_back \
    -H "X-Api-Key: $AUROUS_API_KEY"
  ```

  ```typescript Node.js theme={null}
  const character = await fetch(
    `https://api.aurous-labs.com/v1/characters/${id}/refs/upper_back`,
    { method: "DELETE", headers: { "X-Api-Key": process.env.AUROUS_API_KEY! } },
  ).then((r) => r.json());

  console.log(character.views.find((v) => v.view === "upper_back").status); // "missing"
  console.log(character.build.missing_views.includes("upper_back"));        // true
  ```

  ```python Python theme={null}
  import os, requests

  r = requests.delete(
      f"https://api.aurous-labs.com/v1/characters/{character_id}/refs/upper_back",
      headers={"X-Api-Key": os.environ["AUROUS_API_KEY"]},
  ).json()

  print(next(v for v in r["views"] if v["view"] == "upper_back")["status"])  # missing
  ```
</CodeGroup>

## Path parameters

| Parameter | Description                                                                                                                                                                                                                                                                    |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `id`      | Opaque character id (`char_…`).                                                                                                                                                                                                                                                |
| `view`    | One of `head_front`, `upper_front`, `lower_front`, `upper_back`, `lower_back`, `full_left`, `full_front`, `full_right`. Anything else is `400 invalid_format` (`param: "view"`) — and the same 400 fires whether or not the character exists, so it is not an existence probe. |

There is no request body.

## Removal is `draft`-only

| Character `status`                            | `DELETE /refs/{view}`                                            |
| --------------------------------------------- | ---------------------------------------------------------------- |
| `draft`                                       | Allowed.                                                         |
| `synthesizing`                                | `409 character_busy` with `Retry-After` — a render is in flight. |
| `failed`, `reviewing`, `ready`, anything else | `400 character_status_invalid`, `param: character_id`.           |

<Note>
  So a character whose build **failed** can have a view **replaced** (`PUT`) but not **removed**, until the next successful build. Nothing was lost: the references you uploaded are stored on the character, not as expiring upload tickets, and [`POST /v1/characters/{id}/build`](/api-reference/characters/build-character) accepts `failed` precisely so a retry needs no re-upload.
</Note>

## Limits

* **Cost**: free. Removing a view renders nothing and charges nothing; it raises what the next build will cost, because there is one more view to render.
* **Rate limit**: bucket `characters_post` — 30 requests/min sustained, 60 burst per team. Shared with the other cheap character writes (draft create, uploads init/classify, `PATCH`, `DELETE /v1/characters/{id}`, save).
* **Idempotency**: no `Idempotency-Key` is needed. The operation is naturally idempotent — removing an already-empty view is a `200` with the character unchanged.

## Errors

| Code                       | HTTP | When                                                                                                                                     |
| -------------------------- | ---- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `invalid_format`           | 400  | `view` is not one of the eight names. `param` is `view`.                                                                                 |
| `character_status_invalid` | 400  | The character is not a `draft`. `param` is `character_id`; the message names the current status and the statuses this operation accepts. |
| `invalid_api_key`          | 401  | Missing, malformed, or revoked `X-Api-Key`.                                                                                              |
| `insufficient_scope`       | 403  | The key does not carry the `write` scope.                                                                                                |
| `resource_not_found`       | 404  | Unknown character id, soft-deleted, or cross-team. The 404 is intentional — cross-team existence is never leaked.                        |
| `character_busy`           | 409  | A render is in flight; retry after `Retry-After` seconds.                                                                                |
| `too_many_requests`        | 429  | Burst > 60 or sustained > 30/min.                                                                                                        |

<Note>
  These changes ship on the existing `2026-08-26` contract. No `Aurous-Version` pin isolates them: the version catalogue carries image and video pricing pointers only, not character pricing or the size of the reference set. Pinning an earlier `Aurous-Version` restores neither the smaller reference set nor the previous price. A character created before 2026-09-14 keeps the references it already has — add either of the two newer views on demand with [`POST /v1/characters/{id}/refs/{view}/regenerate`](/api-reference/characters/regenerate-view); every character created on or after that date carries eight.
</Note>

## Common pitfalls

* This removes **a view**, not the character. To delete the character itself use [`DELETE /v1/characters/{id}`](/api-reference/characters/delete-character), which hard-deletes a `draft`.
* Removing a view **raises** `build.cost_credits` — you have given the platform one more view to render. Re-read `build` after every change rather than caching a quote.
* The `200` on an already-empty view is deliberate, so a retry after a dropped connection is safe. Don't treat it as "the view existed".
* Removing the view your cover pointed at clears the cover; the head view is the default cover when none is set.


## OpenAPI

````yaml DELETE /v1/characters/{id}/refs/{view}
openapi: 3.0.0
info:
  title: Aurous Labs API
  description: >-
    Generate AI images with custom LoRA styles.


    ## Authentication

    All requests require an API key passed in the `X-Api-Key` header.

    Create API keys in your
    [dashboard](https://app.aurous-labs.com/dashboard/api-keys).


    ## Closed-beta access gate

    API keys are scoped to a user. If that user's account is not approved for
    the closed beta, every request returns `403` with one of these `error.code`
    values:


    - `account_pending` — awaiting review

    - `account_rejected` — declined post-signup

    - `account_suspended` — was approved, then suspended


    There is no retry — contact support to be approved. The same codes are
    emitted by the WebSocket gateway via 4001 close.


    ## Common headers

    Every response carries `Aurous-Request-Id` (a server-minted `req_<ULID>` for
    support tracing) and `Aurous-Version` (the API version applied to the
    response). Optionally pin a version on the request with `Aurous-Version:
    YYYY-MM-DD` — omit it and the platform default applies (currently
    `2026-08-26`).


    ## Quick Start

    ```bash

    curl -X POST https://api.aurous-labs.com/v1/images \
      -H "X-Api-Key: al_live_your_key" \
      -H "Content-Type: application/json" \
      -d '{"prompt": "A golden sunset over mountains", "lora_id": "your-lora-id", "size": "1_5k_1_1"}'
    ```
  version: 1.0.0
  contact: {}
servers:
  - url: https://api.aurous-labs.com
    description: Production
  - url: https://api.preprod.aurous-labs.com
    description: Preprod (staging)
security: []
tags:
  - name: Seedance (raw)
    description: >-
      Drop-in raw passthrough for Seedance video generation. Point the official
      Seedance provider SDK at this API's base URL and authenticate with your
      Aurous API key in the `X-Api-Key` header — request bodies are forwarded to
      the provider verbatim and responses come back shape-identical, so you keep
      the provider's exact request/response shapes. Task ids are Aurous-native
      `vid_…` ids. Billing rides response headers, not the body:
      `Aurous-Credits-Held` on the create response and `Aurous-Credits-Charged`
      on a settled, succeeded task read — the body itself stays provider-shaped.
paths:
  /v1/characters/{id}/refs/{view}:
    delete:
      tags:
        - Public API (v1) — Characters
      summary: Remove a view from a draft
      description: >-
        Empties ONE of the eight views on a `draft`, so the next POST
        /v1/characters/{id}/build renders it instead of keeping your photo. Any
        other status returns 400 `character_status_invalid` (param
        `character_id`) — replace the view with a new upload instead.
        Idempotent: a view that holds no reference returns 200 with the
        character unchanged. Never charges. Rate limit: `characters_post`.
      operationId: V1CharactersController_deleteReference
      parameters:
        - name: id
          required: true
          in: path
          description: Opaque character ID
          schema:
            example: char_01HXMQ7Z3K8Y2NABCDEFGHJKMR
            type: string
        - name: view
          required: true
          in: path
          description: The view to empty
          schema:
            type: string
            enum:
              - head_front
              - upper_front
              - lower_front
              - upper_back
              - lower_back
              - full_left
              - full_front
              - full_right
        - name: Aurous-Version
          in: header
          required: false
          description: >-
            Optional API version pin (YYYY-MM-DD). Omit the header to receive
            the platform default, currently `2026-08-26`.
          schema:
            type: string
            example: '2026-08-26'
            pattern: ^\d{4}-\d{2}-\d{2}$
      responses:
        '200':
          description: View emptied (or already empty); updated character returned
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CharacterResponse'
          headers:
            Aurous-Request-Id:
              description: Server-minted request id. Quote this in support tickets.
              schema:
                type: string
                example: req_01HXMQ7Z3K8Y2NABCDEFGHJKMP
            Aurous-Version:
              description: API version pin applied to this response (YYYY-MM-DD).
              schema:
                type: string
                example: '2026-08-26'
            X-RateLimit-Limit:
              description: Bucket capacity (max tokens) for this endpoint class.
              schema:
                type: integer
                example: 120
            X-RateLimit-Remaining:
              description: Tokens remaining after this request.
              schema:
                type: integer
                example: 119
            X-RateLimit-Reset:
              description: >-
                Epoch seconds when the bucket would be full again, assuming no
                further requests.
              schema:
                type: integer
                example: 1700000060
        '400':
          description: >-
            Unknown view (`invalid_format`, param `view`) or the character is
            not a `draft` (`character_status_invalid`, param `character_id`)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          headers:
            Aurous-Request-Id:
              description: Server-minted request id. Quote this in support tickets.
              schema:
                type: string
                example: req_01HXMQ7Z3K8Y2NABCDEFGHJKMP
            Aurous-Version:
              description: API version pin applied to this response (YYYY-MM-DD).
              schema:
                type: string
                example: '2026-08-26'
            X-RateLimit-Limit:
              description: Bucket capacity (max tokens) for this endpoint class.
              schema:
                type: integer
                example: 120
            X-RateLimit-Remaining:
              description: Tokens remaining after this request.
              schema:
                type: integer
                example: 119
            X-RateLimit-Reset:
              description: >-
                Epoch seconds when the bucket would be full again, assuming no
                further requests.
              schema:
                type: integer
                example: 1700000060
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          headers:
            Aurous-Request-Id:
              description: Server-minted request id. Quote this in support tickets.
              schema:
                type: string
                example: req_01HXMQ7Z3K8Y2NABCDEFGHJKMP
            Aurous-Version:
              description: API version pin applied to this response (YYYY-MM-DD).
              schema:
                type: string
                example: '2026-08-26'
            X-RateLimit-Limit:
              description: Bucket capacity (max tokens) for this endpoint class.
              schema:
                type: integer
                example: 120
            X-RateLimit-Remaining:
              description: Tokens remaining after this request.
              schema:
                type: integer
                example: 119
            X-RateLimit-Reset:
              description: >-
                Epoch seconds when the bucket would be full again, assuming no
                further requests.
              schema:
                type: integer
                example: 1700000060
        '403':
          description: >-
            Account not approved for closed beta. error.code is one of
            `account_pending`, `account_rejected`, `account_suspended`. There is
            no retry — contact support to be approved.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          headers:
            Aurous-Request-Id:
              description: Server-minted request id. Quote this in support tickets.
              schema:
                type: string
                example: req_01HXMQ7Z3K8Y2NABCDEFGHJKMP
            Aurous-Version:
              description: API version pin applied to this response (YYYY-MM-DD).
              schema:
                type: string
                example: '2026-08-26'
            X-RateLimit-Limit:
              description: Bucket capacity (max tokens) for this endpoint class.
              schema:
                type: integer
                example: 120
            X-RateLimit-Remaining:
              description: Tokens remaining after this request.
              schema:
                type: integer
                example: 119
            X-RateLimit-Reset:
              description: >-
                Epoch seconds when the bucket would be full again, assuming no
                further requests.
              schema:
                type: integer
                example: 1700000060
        '404':
          description: Character not found / cross-team
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          headers:
            Aurous-Request-Id:
              description: Server-minted request id. Quote this in support tickets.
              schema:
                type: string
                example: req_01HXMQ7Z3K8Y2NABCDEFGHJKMP
            Aurous-Version:
              description: API version pin applied to this response (YYYY-MM-DD).
              schema:
                type: string
                example: '2026-08-26'
            X-RateLimit-Limit:
              description: Bucket capacity (max tokens) for this endpoint class.
              schema:
                type: integer
                example: 120
            X-RateLimit-Remaining:
              description: Tokens remaining after this request.
              schema:
                type: integer
                example: 119
            X-RateLimit-Reset:
              description: >-
                Epoch seconds when the bucket would be full again, assuming no
                further requests.
              schema:
                type: integer
                example: 1700000060
        '409':
          description: >-
            A render is in flight (`character_busy`, retry after `Retry-After`
            seconds)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          headers:
            Aurous-Request-Id:
              description: Server-minted request id. Quote this in support tickets.
              schema:
                type: string
                example: req_01HXMQ7Z3K8Y2NABCDEFGHJKMP
            Aurous-Version:
              description: API version pin applied to this response (YYYY-MM-DD).
              schema:
                type: string
                example: '2026-08-26'
            X-RateLimit-Limit:
              description: Bucket capacity (max tokens) for this endpoint class.
              schema:
                type: integer
                example: 120
            X-RateLimit-Remaining:
              description: Tokens remaining after this request.
              schema:
                type: integer
                example: 119
            X-RateLimit-Reset:
              description: >-
                Epoch seconds when the bucket would be full again, assuming no
                further requests.
              schema:
                type: integer
                example: 1700000060
            Retry-After:
              description: >-
                Seconds to wait before retrying. Present on 429 (rate limit), on
                503 provider_unavailable, and on 409 character_busy. Prefer this
                over computing X-RateLimit-Reset − now.
              schema:
                type: integer
                example: 12
        '429':
          description: Rate limit exceeded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          headers:
            Aurous-Request-Id:
              description: Server-minted request id. Quote this in support tickets.
              schema:
                type: string
                example: req_01HXMQ7Z3K8Y2NABCDEFGHJKMP
            Aurous-Version:
              description: API version pin applied to this response (YYYY-MM-DD).
              schema:
                type: string
                example: '2026-08-26'
            X-RateLimit-Limit:
              description: Bucket capacity (max tokens) for this endpoint class.
              schema:
                type: integer
                example: 120
            X-RateLimit-Remaining:
              description: Tokens remaining after this request.
              schema:
                type: integer
                example: 119
            X-RateLimit-Reset:
              description: >-
                Epoch seconds when the bucket would be full again, assuming no
                further requests.
              schema:
                type: integer
                example: 1700000060
            Retry-After:
              description: >-
                Seconds to wait before retrying. Present on 429 (rate limit), on
                503 provider_unavailable, and on 409 character_busy. Prefer this
                over computing X-RateLimit-Reset − now.
              schema:
                type: integer
                example: 12
        '503':
          description: >-
            Character generation is temporarily unavailable, or the platform
            could not verify your account/billing state or prepare the request
            (for example, reference images) before dispatch — error.code is
            `provider_unavailable` in every case. Retry after the number of
            seconds in the `Retry-After` header.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          headers:
            Aurous-Request-Id:
              description: Server-minted request id. Quote this in support tickets.
              schema:
                type: string
                example: req_01HXMQ7Z3K8Y2NABCDEFGHJKMP
            Aurous-Version:
              description: API version pin applied to this response (YYYY-MM-DD).
              schema:
                type: string
                example: '2026-08-26'
            X-RateLimit-Limit:
              description: Bucket capacity (max tokens) for this endpoint class.
              schema:
                type: integer
                example: 120
            X-RateLimit-Remaining:
              description: Tokens remaining after this request.
              schema:
                type: integer
                example: 119
            X-RateLimit-Reset:
              description: >-
                Epoch seconds when the bucket would be full again, assuming no
                further requests.
              schema:
                type: integer
                example: 1700000060
            Retry-After:
              description: >-
                Seconds to wait before retrying. Present on 429 (rate limit), on
                503 provider_unavailable, and on 409 character_busy. Prefer this
                over computing X-RateLimit-Reset − now.
              schema:
                type: integer
                example: 12
      security:
        - api-key: []
components:
  schemas:
    CharacterResponse:
      type: object
      properties:
        id:
          type: string
          description: Opaque character ID.
          example: char_01HXMQ7Z3K8Y2NABCDEFGHJKMR
        object:
          type: string
          description: Discriminator
          example: character
          enum:
            - character
        name:
          type: string
          description: Display name.
          example: Aurora the Adventurer
        client_reference_id:
          type: string
          description: >-
            Caller-supplied reference echoed back (the value sent on create).
            Null if unset.
          nullable: true
          example: bot_8472
        status:
          type: string
          description: >-
            Lifecycle state. `draft`: references are being assembled; nothing
            has been charged and the character cannot be used for generation.
            New lifecycle states may be added in future — treat any status other
            than `ready` as "not yet usable". `synthesizing`: references are
            being built. `ready`: usable on POST /v1/images — both create flows
            advance here on their own. `reviewing`: reached only after POST
            /:id/resynthesize or POST /:id/build; call POST /:id/save to return
            to `ready`. `failed`: the build failed; `error_message` carries the
            reason and POST /:id/build (builder characters) or POST
            /:id/resynthesize retries. `deleted`: soft-deleted (filtered out of
            the list endpoint).
          example: ready
          enum:
            - draft
            - synthesizing
            - reviewing
            - ready
            - failed
            - deleted
        nudity:
          type: string
          description: >-
            What the reference set is rendered as — `nude` unless you chose
            `clothed`, or — when you omitted `nudity` — your team's default is
            `clothed`. An explicit value always wins. Fixed once the references
            are built.
          enum:
            - nude
            - clothed
          example: clothed
        attributes:
          description: Character attributes. Null when unset.
          nullable: true
          allOf:
            - $ref: '#/components/schemas/CharacterAttributesResponse'
        refs:
          description: >-
            Reference images, one per view the character has. A character built
            today has eight; an older one can have fewer than eight (typically
            six, some of the oldest four). Do not assume a count — read
            `views[]`, the canonical read model for new integrations, or
            `build.missing_views`. `refs[]` lists only the references that
            exist.
          type: array
          items:
            $ref: '#/components/schemas/CharacterRefEntry'
        views:
          description: >-
            One entry per named view, in canonical order — every reference that
            maps to a named view, keyed by view, plus what is missing or was
            rejected. A reference from before named views existed (`refs[].view`
            is `other`) appears only in `refs[]`.
          type: array
          items:
            $ref: '#/components/schemas/CharacterViewEntry'
        build:
          description: What a build would render and cost right now. Always present.
          allOf:
            - $ref: '#/components/schemas/CharacterBuildSummary'
        error_message:
          type: string
          description: >-
            Machine-readable failure code from the most recent
            synthesize/resynthesize attempt. One of `synthesis_failed`,
            `synthesis_timeout`, `provider_unavailable` — a closed set to switch
            on, not customer-facing prose. Null when the most recent attempt
            succeeded (or none has run yet). Set on `failed`, but NOT
            failed-exclusive: a failed *resynthesize* restores the character to
            its prior working status (`reviewing`) rather than overwriting a
            good generation, so a `reviewing` row can carry a non-null code here
            — check this field for failure, not `status`. Cleared on the next
            resynthesize attempt and on success.
          nullable: true
          example: null
        aurous_version:
          type: string
          description: >-
            API contract version applied at the time this row was minted (D25 —
            frozen for replay across future version bumps).
          example: '2026-08-26'
        created_at:
          type: string
          description: Creation timestamp (ISO 8601).
          example: '2026-05-08T10:00:00Z'
        updated_at:
          type: string
          description: Last-update timestamp (ISO 8601).
          example: '2026-05-08T10:00:00Z'
      required:
        - id
        - object
        - name
        - status
        - nudity
        - refs
        - views
        - build
        - created_at
        - updated_at
    ErrorResponse:
      type: object
      properties:
        error:
          description: Error payload
          allOf:
            - $ref: '#/components/schemas/ErrorPayload'
      required:
        - error
    CharacterAttributesResponse:
      type: object
      properties:
        gender:
          type: string
          nullable: true
          example: female
        age:
          type: number
          nullable: true
          example: 28
        ethnicity:
          type: string
          nullable: true
          example: east-asian
        hair_color:
          type: string
          nullable: true
          example: black
        hair_style:
          type: string
          nullable: true
          example: shoulder-length straight
        eye_color:
          type: string
          nullable: true
          example: brown
        body_type:
          type: string
          nullable: true
          example: athletic
        additional_details:
          type: string
          nullable: true
          description: Free-text catch-all for attributes outside the typed fields.
          example: small scar above right eyebrow; warm smile
    CharacterRefEntry:
      type: object
      properties:
        pose:
          type: string
          description: Pose label for this reference image.
          enum:
            - portrait
            - front
            - side
            - back
            - other
          example: front
        view:
          type: string
          description: >-
            One of the eight named views, or `other` for rows created before
            named views existed. Prefer `view` over `pose` — `pose` is the
            original five-value label kept for compatibility.
          enum:
            - head_front
            - upper_front
            - lower_front
            - upper_back
            - lower_back
            - full_left
            - full_front
            - full_right
            - other
          example: full_front
        source:
          type: string
          description: >-
            `uploaded` — a photo you supplied for this view with PUT
            /v1/characters/{id}/refs/{view}, used as-is and never re-rendered (a
            build skips it, and a per-view regenerate refuses it with 400
            `reference_uploaded`). `generated` — rendered by the platform,
            whether by a create, a build or a regenerate. Both values occur
            today.
          enum:
            - uploaded
            - generated
          example: generated
        url:
          type: string
          description: >-
            Time-limited signed URL for the ref image, on the platform's storage
            host. TTL is 24h — re-fetch the character (GET /v1/characters/{id})
            to mint a fresh URL set when one expires. Treat the host as opaque
            and do not allowlist by hostname: it is not the API host and it is
            not part of the contract. Download the bytes, or re-read the
            character for a fresh URL.
          example: >-
            https://storage-host.example/storage/v1/object/sign/characters/full_front.jpg?token=eyJhbGciOi...
      required:
        - pose
        - view
        - source
        - url
    CharacterViewEntry:
      type: object
      properties:
        view:
          type: string
          description: >-
            The view this slot represents. Always one of the eight; never
            `other`.
          enum:
            - head_front
            - upper_front
            - lower_front
            - upper_back
            - lower_back
            - full_left
            - full_front
            - full_right
          example: full_front
        status:
          type: string
          description: >-
            Slot state. `generated` — holds a platform render. `uploaded` —
            holds a photo you supplied with PUT /v1/characters/{id}/refs/{view}.
            `rejected` — your most recent photo for this slot was refused (see
            `reason`) and no accepted reference took its place; it is surfaced
            while the character is a `draft` and expires 24 h after the attempt,
            at which point the slot reads `missing` again. `missing` — empty; it
            is what a build renders. This is an OPEN set: new states may be
            added, so treat an unrecognized value as `missing`.
          enum:
            - uploaded
            - generated
            - rejected
            - missing
          example: generated
        url:
          type: string
          description: >-
            Time-limited signed URL (24 h TTL) on the platform's storage host
            when `status` is `uploaded` or `generated`; `null` otherwise. Treat
            the host as opaque and do not allowlist by hostname — it is not the
            API host and it is not part of the contract.
          nullable: true
          example: null
        nudity:
          type: string
          description: >-
            Whether this specific reference shows nudity. On a `clothed`
            character EVERY view reads `clothed`, uploaded or generated — the
            read model reports the set's rendering intent there. On a `nude`
            character a generated view reads `nude` and an UPLOADED view reports
            what the photo itself shows, which is how a mixed set arises: a
            clothed body photo filed onto a `nude` character is accepted
            deliberately and reads `clothed` while the character's own `nudity`
            stays `nude`. Compare the two to detect a mixed set. (The reverse is
            refused at intake: a nude photo on a `clothed` character is 422
            `reference_unfit` with `reason: "nudity_mismatch"` — except on
            `head_front`, which carries no nudity rule.) `null` when the slot
            has no reference.
          enum:
            - nude
            - clothed
          nullable: true
          example: clothed
        reason:
          type: string
          description: >-
            Why the most recent upload for this slot was refused. Present only
            when `status` is `rejected`. The same set as the `reason` on a 422
            `reference_unfit`, plus the two byte-level codes (`invalid_format`,
            `value_out_of_range`) a photo can be refused for before the fit
            rules run — those two are error codes rather than fit reasons, so
            the 422 itself carries no `reason` for them. Branch on the value and
            treat anything unrecognized as a generic refusal.
          enum:
            - too_small
            - extreme_aspect
            - no_person
            - multiple_people
            - no_face
            - wrong_view
            - nudity_mismatch
            - invalid_format
            - value_out_of_range
          nullable: true
          example: null
        detected_view:
          type: string
          description: >-
            Which view the refused photo actually looked like. Present only when
            `reason` is `wrong_view` — offer the customer that slot instead of
            asking for a new photo: the same upload ticket can be re-sent to
            that view without re-uploading. `null` on every other slot.
          enum:
            - head_front
            - upper_front
            - lower_front
            - upper_back
            - lower_back
            - full_left
            - full_front
            - full_right
            - other
          nullable: true
          example: null
        made_from:
          description: >-
            Which of your references this view was rendered from, by view name.
            `null` for a view you uploaded (it was not rendered from anything)
            and for a `missing` or `rejected` slot; `[]` for a generated view
            whose provenance was not recorded (rows predating provenance).
            Otherwise the view names it was conditioned on.
          nullable: true
          example:
            - head_front
            - full_front
          type: array
          items:
            type: string
      required:
        - view
        - status
    CharacterBuildSummary:
      type: object
      properties:
        missing_views:
          type: array
          description: >-
            Views with no reference, in canonical view order — what a build (or
            the equivalent per-view regenerates) would render right now.
          example:
            - full_front
            - full_right
          items:
            type: string
            enum:
              - head_front
              - upper_front
              - lower_front
              - upper_back
              - lower_back
              - full_left
              - full_front
              - full_right
        cost_credits:
          type: number
          description: >-
            Credits the next build (or the equivalent per-view regenerates) will
            charge: `per_view_credits` × `missing_views.length`.
            Server-computed, and derived from the references that exist RIGHT
            NOW — so it is meaningful once the character is `ready` or
            `reviewing`. While it is `synthesizing` no view has been persisted
            yet, so this quotes every view still to come, not the remaining
            work.
        per_view_credits:
          type: number
          description: >-
            Current price of one generated view, in credits (also the per-view
            regenerate price). Read it; never hard-code it — it is
            configuration, not a constant. On a `character.completed` webhook
            payload a `0` here means the price could not be read at the moment
            the event was emitted, not that views are free — re-read `GET
            /v1/characters/{id}` for the live value.
      required:
        - missing_views
        - cost_credits
        - per_view_credits
    ErrorPayload:
      type: object
      properties:
        type:
          type: string
          description: Broad error category
          example: invalid_request
          enum:
            - invalid_request
            - authentication
            - not_found
            - rate_limit
            - server_error
        code:
          type: string
          description: >-
            Stable error code (programmatic discriminator). Closed-beta gate
            emits one of `account_pending`, `account_rejected`,
            `account_suspended` on 403.
          example: balance_too_low
          enum:
            - invalid_request
            - missing_field
            - invalid_format
            - value_out_of_range
            - unsupported_lora_for_mode
            - generation_not_cancellable
            - prompt_blocked
            - reference_blocked
            - output_moderation_rejected
            - unknown_version
            - mutually_exclusive_input
            - character_not_ready
            - parameter_invalid_combination
            - character_status_invalid
            - character_busy
            - nudity_not_allowed
            - reference_unfit
            - reference_uploaded
            - build_requires_identity
            - style_retired
            - parameter_invalid
            - too_many_reference_images
            - action_not_available
            - upload_invalid
            - balance_too_low
            - idempotency_key_in_use
            - api_key_not_found
            - payload_too_large
            - missing_api_key
            - invalid_api_key
            - revoked_api_key
            - resource_not_found
            - forbidden_resource
            - account_pending
            - account_rejected
            - account_suspended
            - already_approved
            - already_rejected
            - already_suspended
            - invalid_reinstate_target
            - invalid_suspend_target
            - cannot_moderate_admin
            - too_many_requests
            - concurrency_limit_exceeded
            - tpm_rate_limit_exceeded
            - internal_error
            - provider_unavailable
            - reference_check_unavailable
            - provider_timeout
            - provider_not_configured
            - invalid_time_range
            - invalid_bucket_width
            - too_many_buckets
            - too_many_group_by
            - invalid_filter
            - invalid_page_token
            - export_too_large
            - user_already_exists
            - self_invite_forbidden
            - invite_link_failed
            - invite_rate_limited
            - model_not_found
            - model_disabled
            - model_wrong_kind
            - max_tokens_exceeds_hard_cap
            - chat_model_misconfigured
            - embeddings_input_too_large
            - embeddings_unsupported_dimensions
            - pricing_frozen
            - provider_rate_limited
            - chat_provider_request_invalid
            - chat_provider_auth_failed
            - chat_provider_unavailable
            - max_input_tokens_exceeded
            - chat_provider_unknown_error
            - embeddings_provider_unknown_error
            - embeddings_batch_not_supported
            - embeddings_input_too_many_items
            - embeddings_video_unsupported
            - encoding_format_unsupported
            - missing_max_tokens_no_model_default
            - chat_cancel_target_not_found
            - chat_completion_not_found
            - chat_cancel_target_already_terminal
            - chat_cancel_target_not_cancellable
            - tool_choice_required_unsupported
            - response_format_too_large
            - response_format_too_deep
            - invalid_cursor
            - invalid_cursor_for_endpoint
            - model_slug_exists
            - output_expired
            - output_not_available
            - content_filtered
            - image_generation_failed
            - reference_media_invalid
            - reference_media_cap_reached
            - reference_fetch_failed
            - unsupported_auth_method
            - insufficient_scope
            - uploads_expired
            - character_resynthesize_in_progress
            - provider_unknown_error
            - first_frame_too_small
        message:
          type: string
          description: Human-readable message
          example: Team available balance is 1.5 credits, generation requires 2.0.
        param:
          type: object
          description: Field name when the error is parameter-scoped
          example: prompt
          nullable: true
        reason:
          type: string
          description: >-
            Sub-code refining `code`, for codes that document one. Present today
            only on `reference_unfit`; `null` otherwise. Branch on `code` first
            and treat an unrecognized `reason` as a generic failure of that
            code.
          enum:
            - too_small
            - extreme_aspect
            - no_person
            - multiple_people
            - no_face
            - wrong_view
            - nudity_mismatch
          nullable: true
          example: wrong_view
        detected_view:
          type: string
          description: >-
            Present only on `reference_unfit` with `reason: "wrong_view"`: the
            view the rejected image actually depicts. Offer the customer that
            view instead of asking for a new photo — the same upload can be
            re-sent to it.
          enum:
            - head_front
            - upper_front
            - lower_front
            - upper_back
            - lower_back
            - full_left
            - full_front
            - full_right
            - other
          nullable: true
          example: full_left
        doc_url:
          type: string
          description: Documentation link for this error code
          example: https://docs.aurous-labs.com/errors#balance_too_low
        request_id:
          type: string
          description: Echoes Aurous-Request-Id — quote in support tickets
          example: req_01HXMQ7Z3K8Y2VNABCDEFGHJKM
      required:
        - type
        - code
        - message
        - doc_url
        - request_id
  securitySchemes:
    api-key:
      type: apiKey
      in: header
      name: X-Api-Key
      description: Your team API key (starts with `al_live_`).

````