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

# Generate

> Start a video, image or motion-control generation with any model and every input it takes, priced live and charged when it's queued.

One endpoint for every model in [List models](https://tryunsora.com/docs/api-reference/catalog/list.md). Send the model key and its inputs under their own names; the request is validated against the model, priced live, charged and queued.

Poll [Poll video status](https://tryunsora.com/docs/api-reference/video/poll-status.md) (video and motion control) or [Poll image status](https://tryunsora.com/docs/api-reference/image/poll-status.md) (image) with `generation.id`.

* **Price guard:** send `expectedCredits` (for example the quote's `credits`). If the live price is higher, nothing is charged and the response is `409` with code `PRICE_CHANGED` and the new price in `credits`.
* **Outside media:** URLs hosted outside Unsora are copied into your library first, up to 12 per request.
* **Retries:** send an `Idempotency-Key` header so a retried request isn't charged twice.

```bash theme={null}
curl -X POST "https://mvp.tryunsora.com/api/v1/catalog/generate" \
  -H "Authorization: Bearer uns_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "seedance-2.5",
    "inputs": {
      "prompt": "A red fox running through fresh snow at sunrise",
      "aspect_ratio": "9:16",
      "duration": 8,
      "generate_audio": true
    },
    "expectedCredits": 64
  }'
```


## OpenAPI

````yaml POST /catalog/generate
openapi: 3.1.0
info:
  title: Unsora API
  version: 1.4.0
  description: >-
    Public API for Unsora integrations. Authenticate with an Unsora API key
    (`uns_…`, created under Developers → API keys in the app) as a Bearer token
    in the Authorization header. Limit: 60 requests per minute per key; over it,
    429 with code RATE_LIMIT_EXCEEDED.
servers:
  - url: https://mvp.tryunsora.com/api/v1
    description: Production
  - url: /api/v1
    description: This server
security: []
tags:
  - name: User
  - name: Models
    description: >-
      Every video, image and motion-control model, with each model's inputs
      taken from the provider's own request schema and prices quoted live. One
      generate endpoint covers all of them.
  - name: Video
  - name: Image
  - name: Influencer
  - name: Thumbnail
  - name: Clipping
  - name: Music
  - name: Voiceover
  - name: Upscaler
  - name: Subtitle removal
  - name: Motion control
  - name: Avatar
  - name: Movie materials
  - name: Voice clones
  - name: Voice changer
  - name: Uploads
  - name: Scheduler
paths:
  /catalog/generate:
    post:
      tags:
        - Models
      summary: Start a video, image or motion-control generation
      description: >-
        Validates the inputs against the model, prices the run live, charges the
        credits and queues it. Poll GET /video/status/{id} (video and motion
        control) or GET /image/status/{id} (image). Media URLs hosted outside
        Unsora are imported into your library first (at most 12 per request).
      parameters:
        - name: Idempotency-Key
          in: header
          required: false
          schema:
            type: string
            maxLength: 128
          description: >-
            API key requests only. Retrying with the same key within 24 hours
            replays the first response (with the `Idempotent-Replayed: true`
            header) instead of charging again. The body isn't compared; reusing
            the key on a different endpoint returns 409 IDEMPOTENCY_CONFLICT.
            Keys over 128 characters are ignored.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CatalogGenerateRequest'
      responses:
        '200':
          description: Generation queued
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CatalogGenerateResponse'
        '400':
          description: >-
            Invalid model, mode or inputs; a media file couldn't be read or
            imported; or more than 12 media URLs hosted outside Unsora (upload
            them first)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '402':
          description: Insufficient credits
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: User not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '409':
          description: >-
            Idempotency-Key already used on a different endpoint (code
            IDEMPOTENCY_CONFLICT); or the live price is above `expectedCredits`,
            nothing charged (code PRICE_CHANGED, `credits` holds the new price)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          description: The pricing service couldn't be reached; try again
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '503':
          description: >-
            Generation is temporarily unavailable (code PROVIDER_UNAVAILABLE),
            or the job couldn't be started; nothing was charged
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
        - bearerAuth: []
components:
  schemas:
    CatalogGenerateRequest:
      allOf:
        - $ref: '#/components/schemas/CatalogRequest'
        - type: object
          properties:
            expectedCredits:
              type: integer
              description: >-
                The most credits you agree to spend (e.g. the quote's
                `credits`). If the live price is higher, nothing is charged and
                the API answers 409 PRICE_CHANGED.
    CatalogGenerateResponse:
      type: object
      properties:
        success:
          type: boolean
        model:
          type: string
        generation:
          type: object
          properties:
            id:
              type: string
            status:
              type: string
            model:
              type: string
            mode:
              type: string
            modelId:
              type: string
          required:
            - id
            - status
        creditsDeducted:
          type: integer
        creditsRemaining:
          type: integer
      required:
        - success
        - generation
    ErrorResponse:
      type: object
      properties:
        success:
          type: boolean
        error:
          type: string
        code:
          type: string
        message:
          type: string
      required:
        - error
    CatalogRequest:
      type: object
      required:
        - model
      properties:
        model:
          type: string
          description: >-
            Model key from GET /catalog. Older names listed in the model's
            `legacyDbModels` (e.g. `veo`, `kling-pro`, `seedance_2.0`) also
            work. Retired names such as `wan`, `wan_2.6`, `gpt-image-1.5` and
            `seedream-v5-lite` are rejected here; only POST /videos/create and
            POST /image-generations/create translate them.
          example: seedance-2.5
        category:
          type: string
          enum:
            - video
            - image
            - motion-control
          description: >-
            Optional guard: reject the request if the model is from another
            category.
        mode:
          type: string
          description: Mode key from GET /catalog. Omit to pick it from the attached media.
          example: omni
        inputs:
          type: object
          additionalProperties: true
          description: >-
            Inputs in the provider's field names, as listed by GET /catalog.
            Media fields take URLs; files hosted outside Unsora are imported
            into your library first. Omitted fields use the model's defaults.
          example:
            prompt: A red fox running through fresh snow at sunrise
            aspect_ratio: '9:16'
            resolution: 720p
            duration: 8
            generate_audio: true
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: An Unsora API key (`uns_…`). A Clerk session token also works.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.