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

# Regenerate a view

> Re-render one named view of a character, or add a view the character does not have yet.

`POST /v1/characters/{id}/refs/{view}/regenerate` re-renders **one** of the eight named views and returns the updated character. A view the character does not have yet is **added**.

**Every character created on or after 2026-09-14 carries all eight views**, so on a new character this route only re-renders. Characters created before that date carry six — `head_front`, `upper_front`, `lower_front`, `upper_back`, `lower_back`, `full_left` — and this route is the only way to add **`full_right`** to one while it is `ready`. ([Resynthesize](/api-reference/characters/resynthesize-character), available while `reviewing` or `failed`, also brings an older character to eight.) `full_front` can also be reached through the deprecated body form (`{ "pose": "front" }`), which aliases onto it.

The call is **synchronous**: it blocks until the view is rendered. A render takes **60–180 seconds** — set a client timeout of **at least 300 seconds**.

<Warning>
  **A view holding a photo you uploaded cannot be regenerated.** Your photo is the ground truth the character is rendered from, so re-rolling it would discard the identity and charge you for the privilege: the call returns [`400 reference_uploaded`](/errors#reference_uploaded) with `param: view`, and nothing is charged. Replace it with [`PUT /v1/characters/{id}/refs/{view}`](/api-reference/characters/put-ref) instead, or remove it from a `draft` with [`DELETE /v1/characters/{id}/refs/{view}`](/api-reference/characters/delete-ref) and let a build render it. Check `views[].status` — `uploaded` means this route will refuse.
</Warning>

<Warning>
  The request is charged **before** the render is dispatched. Aborting the HTTP request client-side does **not** cancel the render and does **not** refund the credits — you simply stop waiting for a response you already paid for. A credit refund happens only when the render itself fails server-side. If your HTTP client's default timeout is 30 or 60 seconds, raise it before you call this route.
</Warning>

## When to use

* One view came back wrong and the rest are fine.
* An older six-view character needs `full_front` or `full_right` for a video or an edit — this route is the only way to add `full_right` to a `ready` one. A `reviewing` or `failed` character can instead be brought to eight with [Resynthesize](/api-reference/characters/resynthesize-character).

For a whole new set, use [Resynthesize](/api-reference/characters/resynthesize-character).

## 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` (canonical order). Anything else is `400 invalid_format` (`param: "view"`). |

## Examples

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.aurous-labs.com/v1/characters/char_01HXMQ7Z3K8Y2VNABCDEFGHJKM/refs/full_front/regenerate \
    -H "X-Api-Key: $AUROUS_API_KEY" \
    -H "Idempotency-Key: $(uuidgen)"
  ```

  ```typescript Node.js theme={null}
  const character = await fetch(
    `https://api.aurous-labs.com/v1/characters/${id}/refs/full_front/regenerate`,
    { method: "POST", headers: { "X-Api-Key": process.env.AUROUS_API_KEY!, "Idempotency-Key": crypto.randomUUID() } },
  ).then((r) => r.json());
  console.log(character.views.find((v) => v.view === "full_front").status); // "generated"
  ```

  ```python Python theme={null}
  import os, uuid, requests
  r = requests.post(
      f"https://api.aurous-labs.com/v1/characters/{character_id}/refs/full_front/regenerate",
      headers={"X-Api-Key": os.environ["AUROUS_API_KEY"], "Idempotency-Key": str(uuid.uuid4())},
      timeout=300,
  ).json()
  print(next(v for v in r["views"] if v["view"] == "full_front")["status"])
  ```
</CodeGroup>

## Limits

* **Cost**: `build.per_view_credits` (read it from the character; do not hardcode). Charged up front; refunded automatically if the render fails.
* **Rate limit**: bucket `characters_synthesize` — 15 requests/min sustained, 30 burst per team. Shared across `POST /v1/characters`, `POST /v1/characters/{id}/refs/regenerate`, `POST /v1/characters/{id}/refs/{view}/regenerate`, `POST /v1/characters/{id}/resynthesize` and `POST /v1/characters/{id}/build` — five routes, one bucket.
* **Idempotency**: pass `Idempotency-Key`. Because the view is part of the path, use **one key per view** — reusing a key across two views returns `409 idempotency_key_in_use`.

## Errors

| Code                                               | HTTP | When                                                                                                                                       |
| -------------------------------------------------- | ---- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `invalid_format`                                   | 400  | `view` is not one of the eight names.                                                                                                      |
| `character_status_invalid`                         | 400  | The character is not `ready` or `reviewing` (the message names the current status).                                                        |
| [`reference_uploaded`](/errors#reference_uploaded) | 400  | The view holds a photo you uploaded. `param` is `view`. Replace it with `PUT /v1/characters/{id}/refs/{view}` instead. Nothing is charged. |
| `invalid_request`                                  | 400  | The character has no references to condition the render on (zero refs).                                                                    |
| `invalid_api_key`                                  | 401  | Missing, malformed, or revoked `X-Api-Key`.                                                                                                |
| `balance_too_low`                                  | 402  | Team credits below the per-view price.                                                                                                     |
| `insufficient_scope`                               | 403  | The key does not carry the `write` scope.                                                                                                  |
| `resource_not_found`                               | 404  | Unknown id, soft-deleted character, or cross-team.                                                                                         |
| `character_busy`                                   | 409  | A render is in flight; retry after `Retry-After` seconds.                                                                                  |
| `idempotency_key_in_use`                           | 409  | Same `Idempotency-Key` used with a different body or route.                                                                                |
| `too_many_requests`                                | 429  | Bucket exhausted.                                                                                                                          |
| `provider_unavailable`                             | 503  | Synthesis is paused for your team; `Retry-After` is set.                                                                                   |

## Common pitfalls

* The legacy body form `POST /v1/characters/{id}/refs/regenerate` with `{ "pose": ... }` still works but reaches only four views through a fixed alias table — see its page. Its `2xx` responses carry `Deprecation: true` and a `Link` header pointing here. Prefer this route.
* `views[]` and `refs[]` describe the same references; `refs[].pose` keeps the original five-value label for compatibility, `refs[].view` carries the view name. See [Views and lifecycle](/api-reference/characters/views-and-lifecycle).
* Check `views[].status` before offering a regenerate in your UI: `generated` can be re-rolled here, `uploaded` cannot.

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


## OpenAPI

````yaml POST /v1/characters/{id}/refs/{view}/regenerate
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}/regenerate:
    post:
      tags:
        - Public API (v1) — Characters
      summary: Regenerate one named view (synchronous)
      description: >-
        Re-renders ONE of the eight views (`head_front`, `upper_front`,
        `lower_front`, `upper_back`, `lower_back`, `full_left`, `full_front`,
        `full_right` — the canonical order GET /v1/characters/views returns) and
        returns the updated character. A view the character does not have yet
        (characters created before 2026-09-14 carry six) is ADDED. Costs
        `build.per_view_credits`. This route takes no request body. Synchronous:
        the request blocks until the view is rendered. A render takes 60–180 s,
        so set a client timeout of AT LEAST 300 s — a 30 s or 60 s default will
        abort mid-render. The request is charged BEFORE the render is
        dispatched, so a client-side abort neither cancels the render nor
        refunds the credits; credits come back only when the render itself
        fails. Allowed while `ready` or `reviewing`; `synthesizing` answers 409
        `character_busy` with `Retry-After`; other states 400
        `character_status_invalid`.


        **Rate limit:** 15 requests/minute sustained (burst 30) per team —
        **shared** across `POST /v1/characters`, `POST
        /v1/characters/{id}/refs/regenerate`, `POST
        /v1/characters/{id}/refs/{view}/regenerate`, `POST
        /v1/characters/{id}/resynthesize` and `POST /v1/characters/{id}/build` —
        five routes, one bucket. A burst of regenerations, resynthesizes or
        builds draws down the same budget as new creates; they are not
        independently budgeted. The live `X-RateLimit-Limit` /
        `X-RateLimit-Remaining` headers are the authoritative current values
        (limits may change — read them from the response, do not hard-code).
      operationId: V1CharactersController_regenerateView
      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 render
          schema:
            type: string
            enum:
              - head_front
              - upper_front
              - lower_front
              - upper_back
              - lower_back
              - full_left
              - full_front
              - full_right
        - name: Idempotency-Key
          in: header
          description: >-
            Stripe-style idempotency key (1-256 chars). Same key + same
            canonical-JSON body returns the cached response with
            `Aurous-Idempotent-Replayed: true`. Same key against a different
            route (e.g. previously used on /v1/images) returns `409
            invalid_request / idempotency_key_in_use`. Replay window is 24
            hours. Absent header is treated as non-idempotent (each call
            processes anew). One key per view: the view is part of the path, so
            reusing a key across two views returns 409 idempotency_key_in_use.
          required: false
          schema:
            type: string
        - 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 rendered; 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
            Aurous-Idempotent-Replayed:
              description: >-
                Present (literal `true`) when this response was served from a
                stored idempotent replay — the same `Idempotency-Key` +
                canonical body was seen within the 24h window and the original
                response is returned WITHOUT re-executing (no second charge, no
                second task). Absent on the first (fresh) execution and on any
                request sent without an `Idempotency-Key`. Only on the
                idempotency-aware create routes.
              schema:
                type: string
                enum:
                  - 'true'
                example: 'true'
        '400':
          description: >-
            Unknown view (`invalid_format`, param `view`) or character in a
            non-regenerable state (`character_status_invalid`)
          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
        '402':
          description: Insufficient credits (`balance_too_low`)
          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: 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) or Idempotency-Key reuse
          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_`).

````