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

# Estimate the credit cost of a video generation

> For a fixed duration, `estimated_cost.amount` is the exact charge. For adaptive (`duration: -1`, the default), `estimated_cost.adaptive` is `true` and the price is a range: `amount_min`–`amount_max`, where `amount` equals `amount_max` (the credits held up front). You are charged for the delivered length and refunded the difference. Same validation as POST /v1/videos, but without side effects — no character synthesis, no reference materialization. A cast (`subjects[]`) is validated identically to POST /v1/videos — cast characters are existence/readiness-checked — and does not change the price.

`reference_video_url`/`reference_audio_url` (a `file_<ulid>` from POST /v1/files or an HTTPS URL) are validated for shape and parameter-combination compatibility, identically to `POST /v1/videos`. A `file_<ulid>` additionally gets the same read-only checks the create call performs — it must exist, belong to your team (404 otherwise), and have been uploaded with the matching purpose (400 `reference_media_invalid` otherwise). The media **bytes** are never fetched at estimate time — the estimate never touches the network — so byte-level validation (format, duration, resolution) and HTTPS-URL fetching only happen on the actual create call. A reference-to-video request never charges the `enhance_prompt` multiplier, even when `enhance_prompt: true` — the system composes the prompt around the reference and never invokes the enhancer.

Because the reference clip is never fetched, its real duration is unknown at estimate time, so a reference (`video_task: reference`) or extend request is priced at the 15-second input ceiling — an **upper bound**. The actual charge is typically lower: the create hold prices against the real clip length. As with the image estimate, this is a deliberate, conservative divergence — you are never charged more than this estimate.

**Video rates are DB-driven.** Video is priced from the live per-model rate table — see `GET /v1/models` for the current per-model credit rates — NOT frozen in the `Aurous-Version` rate card. Unlike image pricing (which is version-frozen), per-model video rates MAY change without an `Aurous-Version` bump; this is the same pricing asymmetry the LLM chat/embeddings surfaces use (spec §6.4). Pin an `Aurous-Version` for stable request/response **shapes**; call this estimate endpoint for an authoritative current-price quote immediately before you generate.



## OpenAPI

````yaml /api-reference/openapi.json post /v1/videos/estimate
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` — defaults to your team's pinned version.


    ## 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": "2k_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/videos/estimate:
    post:
      tags:
        - Public API (v1)
      summary: Estimate the credit cost of a video generation
      description: >-
        For a fixed duration, `estimated_cost.amount` is the exact charge. For
        adaptive (`duration: -1`, the default), `estimated_cost.adaptive` is
        `true` and the price is a range: `amount_min`–`amount_max`, where
        `amount` equals `amount_max` (the credits held up front). You are
        charged for the delivered length and refunded the difference. Same
        validation as POST /v1/videos, but without side effects — no character
        synthesis, no reference materialization. A cast (`subjects[]`) is
        validated identically to POST /v1/videos — cast characters are
        existence/readiness-checked — and does not change the price.


        `reference_video_url`/`reference_audio_url` (a `file_<ulid>` from POST
        /v1/files or an HTTPS URL) are validated for shape and
        parameter-combination compatibility, identically to `POST /v1/videos`. A
        `file_<ulid>` additionally gets the same read-only checks the create
        call performs — it must exist, belong to your team (404 otherwise), and
        have been uploaded with the matching purpose (400
        `reference_media_invalid` otherwise). The media **bytes** are never
        fetched at estimate time — the estimate never touches the network — so
        byte-level validation (format, duration, resolution) and HTTPS-URL
        fetching only happen on the actual create call. A reference-to-video
        request never charges the `enhance_prompt` multiplier, even when
        `enhance_prompt: true` — the system composes the prompt around the
        reference and never invokes the enhancer.


        Because the reference clip is never fetched, its real duration is
        unknown at estimate time, so a reference (`video_task: reference`) or
        extend request is priced at the 15-second input ceiling — an **upper
        bound**. The actual charge is typically lower: the create hold prices
        against the real clip length. As with the image estimate, this is a
        deliberate, conservative divergence — you are never charged more than
        this estimate.


        **Video rates are DB-driven.** Video is priced from the live per-model
        rate table — see `GET /v1/models` for the current per-model credit rates
        — NOT frozen in the `Aurous-Version` rate card. Unlike image pricing
        (which is version-frozen), per-model video rates MAY change without an
        `Aurous-Version` bump; this is the same pricing asymmetry the LLM
        chat/embeddings surfaces use (spec §6.4). Pin an `Aurous-Version` for
        stable request/response **shapes**; call this estimate endpoint for an
        authoritative current-price quote immediately before you generate.
      operationId: V1EstimateController_estimateVideo
      parameters:
        - name: Aurous-Version
          in: header
          required: false
          description: >-
            Optional API version pin (YYYY-MM-DD). Defaults to your team's
            pinned version, or the system default `2026-07-16` for
            unauthenticated requests.
          schema:
            type: string
            example: '2026-07-16'
            pattern: ^\d{4}-\d{2}-\d{2}$
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateVideoGenerationDto'
      responses:
        '200':
          description: Cost estimate
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EstimateResponse'
          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-07-16'
            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
            Deprecation:
              description: >-
                Present (always the literal string `true`) on a 2xx response to
                POST /v1/images, /v1/images/estimate, /v1/videos or
                /v1/videos/estimate when the request body used the legacy
                `character_id` or `reference_image_urls` field instead of
                `subjects[]`. Absent otherwise. No removal date is set — see the
                linked guide.
              schema:
                type: string
                enum:
                  - 'true'
                example: 'true'
            Link:
              description: >-
                Paired with `Deprecation` — an RFC 8288 link to the subjects[]
                migration guide (`rel="deprecation"`). Same presence rule as
                `Deprecation`.
              schema:
                type: string
                example: >-
                  <https://docs.aurous-labs.com/guides/subjects>;
                  rel="deprecation"; type="text/html"
        '400':
          description: >-
            Validation failed, character_id and reference_image_urls are both
            present (code: mutually_exclusive_input), a cast character is not
            ready (code: character_not_ready), the parameter combination is
            invalid (code: parameter_invalid_combination — e.g. more than 2
            subjects, a subject element carrying both character_id and
            image_urls, a duplicate character across subjects), a malformed id
            was sent (code: invalid_format), or a reference media file id was
            uploaded under a different purpose (code: reference_media_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-07-16'
            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 — missing or invalid API key
          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-07-16'
            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-07-16'
            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: >-
            Video model, character, reference image, or reference media file not
            found / inaccessible
          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-07-16'
            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
        '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-07-16'
            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) and
                on 503 provider_unavailable. 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-07-16'
            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) and
                on 503 provider_unavailable. Prefer this over computing
                X-RateLimit-Reset − now.
              schema:
                type: integer
                example: 12
      security:
        - api-key: []
components:
  schemas:
    CreateVideoGenerationDto:
      type: object
      properties:
        prompt:
          type: string
          description: >-
            Text prompt describing the video. Required unless first_frame_url is
            provided (image-to-video). Subject-driven generation (character_id
            or reference_image_urls) still requires a prompt describing the
            action — a subject alone cannot substitute for one.
          example: A golden sunset over the ocean with gentle waves
        video_lora_id:
          type: string
          description: >-
            Optional. An id (or slug, where one is set) from GET
            /v1/video_loras. Pins a specific video model. If omitted, the
            platform picks a suitable model for your prompt; if none matches,
            your prompt is generated as plain video (or, with a subject
            attached, a subject-driven video). Pin a model only to override that
            choice.
          example: action_01HXMQ7Z3K8Y2VNABCDEFGHJKM
        character_id:
          type: string
          description: >-
            Drive the video from a saved character (reference-to-video). Must be
            `status: ready` — otherwise 400 `character_not_ready`. Cross-team
            ids 404 (existence never leaked). Mutually exclusive with
            `reference_image_urls` (→ 400 `mutually_exclusive_input`) and with
            `first_frame_url`/`last_frame_url` (→ 400
            `parameter_invalid_combination`). Omit both a subject and a frame
            for plain text-to-video. Superseded by `subjects[]` (which also
            supports multi-person casts); fully supported — successful responses
            carry an advisory `Deprecation: true` header when this field is
            used.
          example: char_01HXMQ7Z3K8Y2ABCDEFGHJKM
          deprecated: true
        reference_image_urls:
          description: >-
            Up to 6 subject reference images — each a `file_<ulid>` (POST
            /v1/files) or an `https://` URL (SSRF-pinned server-side fetch).
            Image files only: a `file_<ulid>` uploaded with purpose
            `reference_video`/`reference_audio` is rejected (400
            `invalid_format`). The subject is anchored across the video.
            Mutually exclusive with `character_id` and with
            `first_frame_url`/`last_frame_url`. Superseded by `subjects[]`
            (which also supports multi-person casts); fully supported —
            successful responses carry an advisory `Deprecation: true` header
            when this field is used.
          example:
            - file_01HXMQ7Z3K8Y2NABCDEFGHJKMN
            - https://example.com/ref2.jpg
          minItems: 0
          maxItems: 6
          deprecated: true
          type: array
          items:
            type: string
        subjects:
          maxItems: 2
          description: >-
            Ordered cast for a multi-person video. Up to 2 subjects per
            generation (current engine limit — may increase; exceeding it
            returns 400 parameter_invalid_combination). Each subject is a saved
            character or its own group of 1–4 reference images; character and
            reference subjects can be mixed. Supersedes the single-subject
            `character_id`/`reference_image_urls` fields — sending both shapes
            returns 400 mutually_exclusive_input. A cast may accompany
            `reference_video_url` (the clip supplies motion, the cast supplies
            identity) but not `video_task: "extend"` and not
            `first_frame_url`/`last_frame_url`. Duplicate characters or a
            reference image reused across subjects return 400. Empty array is
            treated as omitted.
          type: array
          items:
            $ref: '#/components/schemas/VideoSubjectDto'
        first_frame_url:
          type: string
          description: >-
            First frame for image-to-video / first+last frame interpolation.
            Either an opaque `file_<ulid>` ID returned by POST /v1/files, or an
            `https://` URL pointing at a public host (max 2048 chars). Image
            files only — a `file_<ulid>` uploaded with purpose
            `reference_video`/`reference_audio` is rejected (400
            `invalid_format`). URLs are server-side fetched through an
            SSRF-pinned client (rejects private IPs / cloud metadata).
          example: file_01HXMQ7Z3K8Y2NABCDEFGHJKMN
          maxLength: 2048
        last_frame_url:
          type: string
          description: >-
            Last frame for first+last frame interpolation. Same rules as
            first_frame_url. Requires `first_frame_url` — sending
            `last_frame_url` alone returns 400 with code
            `parameter_invalid_combination`.
          example: https://example.com/last.jpg
          maxLength: 2048
        resolution:
          type: string
          description: Output video resolution
          enum:
            - 480p
            - 720p
            - 1080p
        ratio:
          type: string
          description: Output video aspect ratio
          enum:
            - '16:9'
            - '4:3'
            - '1:1'
            - '3:4'
            - '9:16'
            - '21:9'
            - adaptive
        duration:
          type: number
          description: >-
            Video length in seconds. Pass -1 for ADAPTIVE (default): the model
            selects the optimal whole-second length within its supported range
            (currently 4–15 s) and you are billed for the delivered length — a
            VARIABLE price. Call POST /v1/videos/estimate to see the min–max
            range before submitting. Pass a whole number 4–15 to pin a fixed
            length (fixed price). Omitting uses the video model's default length
            when your request pins or is matched to one; otherwise adaptive
            (-1). Adaptive holds the 15 s ceiling from your balance until it
            settles.
          enum:
            - -1
            - 4
            - 5
            - 6
            - 7
            - 8
            - 9
            - 10
            - 11
            - 12
            - 13
            - 14
            - 15
          default: -1
          example: 5
        generate_audio:
          type: boolean
          description: >-
            Whether the generated video includes synchronized audio. Defaults to
            the selected video model's audio setting (currently true for all
            models unless noted on the model).
        watermark:
          type: boolean
          description: Whether to add watermark
        enhance_prompt:
          type: boolean
          description: Whether to enhance the prompt with AI
        reference_video_url:
          type: string
          description: >-
            Your reference video — the motion source for a reference-mode
            generation, or the clip to continue when `video_task` is `extend`.
            Either an opaque `file_<ulid>` returned by POST /v1/files (uploaded
            with `purpose: reference_video` — format/duration/resolution were
            already validated at upload), or an HTTPS URL. Requirements: MP4 or
            MOV (H.264/H.265), 2–15 seconds, up to 50 MB, frame area between
            409,600 px (≈640×640) and 2,073,600 px (1920×1080, ≈1080p). URLs
            must be publicly fetchable or pre-signed, serve HTTPS directly
            (redirects are refused — pass the final URL), and respond within the
            fetch budget. Cannot be combined with
            `first_frame_url`/`last_frame_url`. While the reference is prepared
            the generation stays in `processing` — see the endpoint description
            for timing.
          example: https://cdn.example.com/clips/dance-loop.mp4
          maxLength: 2048
        reference_audio_url:
          type: string
          description: >-
            An audio reference (voice, music, or ambience) to guide the
            generated soundtrack — either a `file_<ulid>` from POST /v1/files
            (`purpose: reference_audio`) or an HTTPS URL. WAV or MP3, 2–15
            seconds, up to 15 MB. Needs a companion — a reference video, a
            subject (`subjects[]` or the legacy fields), or a pinned
            `video_lora_id` — and requires audio output (`generate_audio` must
            not be false). Same URL rules as `reference_video_url` (public or
            signed HTTPS, no redirects).
          example: https://cdn.example.com/audio/voiceover.mp3
          maxLength: 2048
        video_task:
          type: string
          description: >-
            What to do with `reference_video_url`. `reference` (default):
            generate a new scene that borrows the clip's motion. `extend`:
            continue the clip itself in `extend_direction`; extend takes the
            clip as-is, so it cannot be combined with `video_lora_id`. Only
            valid when `reference_video_url` is present.
          enum:
            - reference
            - extend
          default: reference
        extend_direction:
          type: string
          description: >-
            Direction to continue the clip when `video_task` is `extend`.
            Defaults to `forward`. Only valid with `video_task: "extend"`.
          enum:
            - forward
            - backward
          default: forward
    EstimateResponse:
      type: object
      properties:
        object:
          type: string
          description: Discriminator
          example: estimate
          enum:
            - estimate
        estimated_cost:
          description: Cost breakdown for this would-be generation.
          allOf:
            - $ref: '#/components/schemas/EstimatedCost'
        currency:
          type: string
          description: Currency unit. All amounts in this response are in `credit`.
          example: credit
          enum:
            - credit
        warnings:
          description: >-
            Non-fatal request adjustments the real create would also report
            (e.g. a retired style pin that generates without a style, or a
            parameter with no effect on this generation path). Same shape and
            codes as the `warnings` on the `POST /v1/images` 201 body — the
            estimate warns exactly when the create would. Omitted when empty.
            Codes are an OPEN set: ignore unknown codes.
          example:
            - code: parameter_ignored
              param: seed
              message: '`seed` has no effect on this generation and was ignored.'
          type: array
          items:
            $ref: '#/components/schemas/WarningEntry'
      required:
        - object
        - estimated_cost
        - currency
    ErrorResponse:
      type: object
      properties:
        error:
          description: Error payload
          allOf:
            - $ref: '#/components/schemas/ErrorPayload'
      required:
        - error
    VideoSubjectDto:
      type: object
      properties:
        type:
          type: string
          enum:
            - character
            - reference
          example: character
          description: Subject kind.
        character_id:
          type: string
          example: char_01HXMQ7Z3K8Y2VNABCDEFGHJKM
          description: >-
            Required for `character` subjects (and must be omitted for
            `reference` subjects — 400 `parameter_invalid_combination`).
            `char_<ulid>` or legacy UUID; must be a ready character your team
            owns.
        image_urls:
          minItems: 1
          maxItems: 4
          example:
            - file_01HXMQ7Z3K8Y2NABCDEFGHJKMN
          description: >-
            Required for `reference` subjects (and must be omitted for
            `character` subjects — 400 `parameter_invalid_combination`). 1–4
            `file_<ulid>` IDs (POST /v1/files) or https URLs. Image files only:
            a `file_<ulid>` uploaded with purpose
            `reference_video`/`reference_audio` is rejected (400
            `invalid_format`). The clearest full-body and portrait views are
            selected automatically to anchor this person across the video.
          type: array
          items:
            type: string
      required:
        - type
    EstimatedCost:
      type: object
      properties:
        amount:
          type: number
          description: >-
            Total credit cost. For images this equals the sum of the `breakdown`
            line items. For videos the price is token-based (per-model rate
            table): `breakdown` carries the token input (`tokens_max`, plus
            optional `enhance_flat_credits`/`discount_factor`), NOT additive
            line items — do not sum it, trust `amount`. For an adaptive video
            (`adaptive: true`) this equals `amount_max` — the ceiling reserved
            up front; you are billed for the delivered length and refunded the
            difference. In all cases trust `amount` as the authoritative figure
            held/charged — it matches the live hold to 4 decimals.
          example: 2
        adaptive:
          type: boolean
          description: >-
            True only for an adaptive (variable-length) video estimate
            (`duration: -1`, the default — see POST /v1/videos). When true the
            price is a range: render `amount_min`–`amount_max`. When false
            (every image estimate, and any video estimate with a fixed
            duration), `amount` is exact.
          example: false
        amount_min:
          type: number
          description: >-
            Adaptive video estimates only: the minimum charge (shortest
            supported length, currently 4 s).
          example: 10
        amount_max:
          type: number
          description: >-
            Adaptive video estimates only: the maximum charge (longest supported
            length, currently 15 s) — equals `amount`.
          example: 37.5
        breakdown:
          type: object
          description: >-
            Cost inputs, keyed by source. Image estimates use `base` (always)
            and `enhance` (only when `enhance_prompt: true`); refs are free and
            do not add line items. When the team has a negotiated discount, an
            additional `discount_factor` line is present — it is a multiplier
            (e.g. `0.9` for 10% off), not a credit amount; `amount` is the
            post-discount total. Video estimates carry token-model inputs:
            `tokens_max` (the ceiling token count used for pricing), plus
            optional `enhance_flat_credits` and `discount_factor` lines. Video
            estimate breakdowns are NOT additive — `amount` is the authoritative
            figure. For adaptive video estimates (`duration: -1`), also check
            the top-level `amount_min`/`amount_max` range. Example image
            breakdown: `{ "base": 1.0, "enhance": 1.0 }`; example video estimate
            breakdown: `{ "tokens_max": 108000, "enhance_flat_credits": 0.5 }`.
            Values are typed `number | string | boolean`: the estimate itself
            returns numeric keys only, but the field set is OPEN and shares its
            contract with the settled generation `cost.breakdown`, which carries
            string/boolean metadata (e.g. `resolution`, `video_input`) — so read
            by name and tolerate non-numeric values on unknown keys.
          example:
            tokens_max: 108000
            enhance_flat_credits: 0.5
      required:
        - amount
        - breakdown
    WarningEntry:
      type: object
      properties:
        code:
          type: string
          description: >-
            Machine-readable warning code. Current values: `parameter_ignored`
            (a parameter you sent has no effect on this generation path and was
            ignored) and `style_retired_plain` (the pinned `lora_id` is retired
            — the generation proceeded without a style). This is an OPEN set:
            new codes may be added without a version bump, so ignore unknown
            codes rather than failing on them.
          example: style_retired_plain
        param:
          type: string
          description: >-
            Machine-readable name of the request field the warning is about
            (e.g. `lora_id`, `seed`).
          example: lora_id
        message:
          type: string
          description: >-
            Human-readable explanation. Wording may change; branch on
            `code`/`param`, not on this text.
          example: >-
            Style lora_06AAAAAAAAAAAAAAAAAAAAAAAA is retired and no longer
            applies a style — this request generates without one.
      required:
        - code
        - param
        - message
    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
            - 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
            - 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
            - provider_unknown_error
        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
        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_01HXMQ7Z3K8Y2ABCDEFGHJKM
      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_`).

````