openapi: 3.1.0
info:
  title: PixAI API - OpenAPI 2.0
  description: |
    Users own the copyrights to images generated through the API. PixAI does not claim any copyright over user-generated works. However, users must ensure that generated content does not infringe any third-party rights and complies with applicable local laws and regulations.

    PixAI's official models (e.g. Haruka, Tsubaki) are copyrighted by PixAI. We grant approved users the right to use these models for commercial activities, but reselling or redistributing the model files themselves is prohibited.

    For details, please refer to:
  termsOfService: https://pixai.art/terms
  license:
    name: Apache 2.0
    url: http://www.apache.org/licenses/LICENSE-2.0.html
  version: 2.0.0
servers:
  - url: https://api.pixai.art/v2
tags:
  - name: image
    description: Image generation and editing endpoints
  - name: video
    description: Video generation endpoints
  - name: task
    description: Read a task and its results
  - name: media
    description: Upload input files and resolve media IDs to URLs
  - name: model
    description: Find models, LoRAs, sizes and color palettes
paths:
  /image/create:
    post:
      tags:
        - image
      summary: Create an image generation task
      description: |
        Start an asynchronous image generation task with the simplified v2 API. The response returns the new task's ID.

        The v2 API provides a streamlined interface with user-friendly parameters such as `aspectRatio`, `mode`, and named `style` presets, replacing the raw pixel dimensions and internal parameter names of v1.
      operationId: createImage
      x-codeSamples:
        - id: curl
          lang: bash
          label: cURL
          source: |
            curl -X POST https://api.pixai.art/v2/image/create \
              -H "Authorization: Bearer $PIXAI_API_KEY" \
              -H "Content-Type: application/json" \
              -d '{
                "modelVersionId": "1983308862240288769",
                "prompt": "1girl, green hair, solo, standing",
                "aspectRatio": "9:16",
                "mode": "standard",
                "batchSize": 4,
                "seed": 12345
              }'
        - id: js
          lang: javascript
          label: JavaScript (fetch)
          source: |
            const response = await fetch("https://api.pixai.art/v2/image/create", {
              method: "POST",
              headers: {
                "Authorization": `Bearer ${PIXAI_API_KEY}`,
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                modelVersionId: "1983308862240288769",
                prompt: "1girl, green hair, solo, standing",
                aspectRatio: "9:16",
                mode: "standard",
                batchSize: 4,
                seed: 12345,
              }),
            });
            const task = await response.json();
            console.log(task);
        - id: python
          lang: python
          label: Python (requests)
          source: |
            import requests

            response = requests.post(
                "https://api.pixai.art/v2/image/create",
                headers={
                    "Authorization": f"Bearer {PIXAI_API_KEY}",
                    "Content-Type": "application/json",
                },
                json={
                    "modelVersionId": "1983308862240288769",
                    "prompt": "1girl, green hair, solo, standing",
                    "aspectRatio": "9:16",
                    "mode": "standard",
                    "batchSize": 4,
                    "seed": 12345,
                },
            )
            task = response.json()
            print(task)
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateImageRequest"
            example:
              modelVersionId: "1983308862240288769"
              prompt: "1girl, green hair, solo, standing"
              aspectRatio: "9:16"
              mode: "standard"
              batchSize: 4
              seed: 12345
      responses:
        "201":
          description: |
            Image generation task created successfully.

            Example Response:
            ```json
            {
              "id": "1943547603237249965",
              "status": "waiting",
              "createdAt": "2025-11-07T14:54:35.000Z",
              "updatedAt": "2025-11-07T14:54:35.000Z",
              "outputs": { "mediaIds": [], "mediaUrls": [] }
            }
            ```
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Task"
        "400":
          description: |
            The request was rejected before a task was created. `code` says why:
            - `BAD_REQUEST` with `data.issues`: the body failed validation (each issue names the field in `path`), or a field is not supported by this model (`message` says which).
            - `INVALID_ARGUMENT`: a field is not allowed for this model family, e.g. `mode` on an SDXL model or `sampling` on Tsubaki. Only `mode` and `sampling` are checked: `mode` works only on Tsubaki models, `sampling` only on SDXL and SD v1. Remove whichever the model does not accept.
            - `IMAGE_SIZE_NOT_ALLOWED`: `width`/`height` fall outside the model's size ranges (`data.reason`). Pick a size from `GET /v2/generation-model/{modelVersionId}/size-config`, or send `aspectRatio`/`size` instead.
            - `INPUT_IMAGE_TOO_LARGE`: a `contextImages` entry is 4000 px or larger on a side.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              example:
                defined: false
                code: BAD_REQUEST
                status: 400
                message: Input validation failed
                data:
                  issues:
                    - code: custom
                      path: []
                      message: Either modelId or modelVersionId must be provided
        "401":
          description: Authentication required. Ensure a valid Bearer token is provided.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "403":
          description: |
            The account cannot run this task right now. `code` says why:
            - `INSUFFICIENT_BALANCE`: not enough credits for the task.
            - `WAITING_NUM_EXCEEDED`: too many of your tasks are still `waiting`. Wait for some to start before submitting more (see [Limits](/en/docs/quick-start/limits)).
            - `LORA_NUM_EXCEEDED`: more `loras` than your plan allows.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "404":
          description: |
            `NOT_FOUND`: no model version has the given `modelVersionId`. `FILE_NOT_FOUND`: a `contextImages` media ID does not exist.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "422":
          description: |
            - `NSFW_PROMPT_REJECTED`: the prompt was rejected by content moderation. Rephrase it; `data.logId` identifies the decision if you contact support.
            - `INVALID_INPUT`: a value is not available for this model or plan, e.g. a `mode` the model does not offer. `message` names the value.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "500":
          description: Task creation failed due to an internal server error. Retry with exponential backoff.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
      security:
        - bearerAuth: []
  /frame-video/create:
    post:
      tags:
        - video
      summary: Create an image-to-video task
      description: |
        Animates an image into a video with PixAI's Tsubaki video model. The video starts on `firstFrameMediaId` and, when you send `lastFrameMediaId`, ends on it. The output keeps the first frame's aspect ratio.

        Frames are image media IDs: upload your own with `POST /v2/media/image/upload-url`, or reuse an image you generated. Media owned by another user is rejected.

        Image-to-video needs a PixAI membership. Credits are charged when the task is created. Poll `GET /v2/task/{id}` for the result; a finished task's video is `outputs.videoMediaId`.
      operationId: createFrameVideo
      x-codeSamples:
        - id: curl
          lang: bash
          label: cURL
          source: |
            curl -X POST https://api.pixai.art/v2/frame-video/create \
              -H "Authorization: Bearer $PIXAI_API_KEY" \
              -H "Content-Type: application/json" \
              -d '{
                "model": "tbkv1.0.1",
                "firstFrameMediaId": "1943547603237249965",
                "prompt": "she turns around and smiles, hair blowing in the wind",
                "duration": 5
              }'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                model:
                  enum:
                    - tbkv1.0.1
                    - tbkv1.0
                  type: string
                  description: The video model. `tbkv1.0.1` is the latest Tsubaki video model.
                firstFrameMediaId:
                  type: string
                  description: Image media ID of the first frame.
                lastFrameMediaId:
                  type: string
                  description: Image media ID of the last frame. Send the first frame again to make a loop.
                prompt:
                  default: null
                  type:
                    - string
                    - "null"
                  description: What should happen in the video.
                duration:
                  type: integer
                  minimum: 5
                  maximum: 15
                  default: 5
                  description: Length in whole seconds.
                mode:
                  enum:
                    - basic
                    - professional
                  type: string
                  default: basic
                  description: "`professional` adds a 1080p upscale on `tbkv1.0.1` and costs more. It has no effect on `tbkv1.0`."
                generateAudio:
                  type: boolean
                  default: true
                  description: Whether to generate a soundtrack.
                audioLanguage:
                  default: null
                  enum:
                    - none
                    - chinese
                    - english
                    - japanese
                    - korean
                    - null
                  type:
                    - string
                    - "null"
                  description: Language of speech in the soundtrack. `none` for no speech.
              required:
                - model
                - firstFrameMediaId
              additionalProperties: false
            example:
              model: tbkv1.0.1
              firstFrameMediaId: "1943547603237249965"
              prompt: she turns around and smiles, hair blowing in the wind
              duration: 5
      responses:
        "201":
          description: The task was created. Poll `GET /v2/task/{id}` with its `id`.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Task"
        "400":
          description: |
            - `INVALID_REFERENCE_MEDIA`: a frame is missing, is not an image, or belongs to another user. `data.code` is `invalid_input` or `media_not_owned`, and `data.mediaId` names the frame.
            - `BAD_REQUEST` with `data.issues`: the body failed validation.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/CannotRun"
        "500":
          $ref: "#/components/responses/CreationFailed"
      security:
        - bearerAuth: []
  /reference-video/create:
    post:
      tags:
        - video
      summary: Create a reference video task
      description: |
        Generates a video guided by reference images, and depending on the model, reference videos and audio.

        Each model accepts different references:

        - `tbkv1.0.1`, `tbkv1.0` (Tsubaki): 1–6 images, no videos, up to 3 audio clips, `duration` 5–15.
        - `v4.0`, `v4.0.1` (Seedance 2, Seedance 2 Fast): up to 9 images, up to 3 videos, up to 3 audio clips, `duration` 4–15.
        - `v4.0.3` (Seedance 2.5): up to 30 images, up to 10 videos, up to 10 audio clips, `duration` 4–30.
        - `v3.3` (Vidu): 1–7 images, no videos or audio, `duration` 3–16.

        Every model needs at least one image or video, except `v4.0.3`, which also accepts audio alone.

        Reference files must meet these limits:

        - Video: MP4 or MOV, H.264 or HEVC, 24–60 fps, 2–15 s per clip and 15 s in total (30 s on `v4.0.3`), up to 50 MB (200 MB on `v4.0.3`).
        - Audio: WAV or MP3, 2–15 s per clip and 15 s in total (30 s on `v4.0.3`), under 15 MiB.

        Check a file with `GET /v2/media/{mediaId}/info` before sending it. On `v4.0` and `v4.0.1`, counts and clip lengths are checked after the task is charged: a task that breaks them fails instead of being refused.

        Credits are charged when the task is created. Poll `GET /v2/task/{id}` for the result; a finished task's video is `outputs.videoMediaId`.
      operationId: createReferenceVideo
      x-codeSamples:
        - id: curl
          lang: bash
          label: cURL
          source: |
            curl -X POST https://api.pixai.art/v2/reference-video/create \
              -H "Authorization: Bearer $PIXAI_API_KEY" \
              -H "Content-Type: application/json" \
              -d '{
                "model": "tbkv1.0.1",
                "prompt": "the girl walks through the city at night",
                "referenceImageMediaIds": ["1943547603237249965"],
                "ratio": "9:16",
                "duration": 5
              }'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                model:
                  type: string
                  minLength: 1
                  enum:
                    - tbkv1.0.1
                    - tbkv1.0
                    - v4.0
                    - v4.0.1
                    - v4.0.3
                    - v3.3
                  description: The video model. See the table above for what each accepts. An unknown value answers `403 MODEL_VERSION_NOT_EXISTS`.
                prompt:
                  default: null
                  type:
                    - string
                    - "null"
                  description: What should happen in the video. Describe how to use the references.
                referenceImageMediaIds:
                  type: array
                  items:
                    type: string
                  default: []
                  description: Image media IDs.
                referenceVideoMediaIds:
                  type: array
                  items:
                    type: string
                  default: []
                  description: Video media IDs. Not accepted by Tsubaki or Vidu.
                referenceAudioMediaIds:
                  type: array
                  items:
                    type: string
                  default: []
                  description: Audio media IDs, uploaded with `POST /v2/media/audio/upload-url`. Not accepted by Vidu.
                duration:
                  type: integer
                  default: 5
                  description: Length in whole seconds. The allowed range depends on `model`.
                ratio:
                  enum:
                    - adaptive
                    - 1:1
                    - 2:3
                    - 3:2
                    - 3:4
                    - 4:3
                    - 9:16
                    - 16:9
                    - 21:9
                  type: string
                  description: |
                    Output aspect ratio. Omitted or `adaptive` follows the references. Seedance models do not take `2:3` or `3:2`, and Vidu ignores this field.
                mode:
                  enum:
                    - basic
                    - professional
                  type: string
                  default: basic
                  description: "`professional` adds an upscale (1080p on `v4.0`, 720p on `v4.0.1`) and costs more. Not accepted by `v4.0.3`."
                generateAudio:
                  type: boolean
                  default: true
                  description: Whether to generate a soundtrack.
                audioLanguage:
                  default: null
                  enum:
                    - none
                    - chinese
                    - english
                    - japanese
                    - korean
                    - null
                  type:
                    - string
                    - "null"
                  description: Language of speech in the soundtrack. `none` for no speech.
              required:
                - model
            example:
              model: tbkv1.0.1
              prompt: the girl walks through the city at night
              referenceImageMediaIds:
                - "1943547603237249965"
              ratio: 9:16
              duration: 5
      responses:
        "201":
          description: The task was created. Poll `GET /v2/task/{id}` with its `id`.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Task"
        "400":
          description: |
            - `BAD_REQUEST` with `data.issues`: the body failed validation, e.g. too many references for `v4.0.3`.
            - `VALIDATION_ERROR`: the combination is not valid for this model, e.g. `mode: professional` on `v4.0.3`, or a video or audio reference for Vidu. `message` says which.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/CannotRun"
        "422":
          description: |
            `INVALID_INPUT`: a reference file was refused before the task was charged. `message` reads `Invalid reference media: <reason>`, sometimes followed by the media ID in parentheses. Reasons include `too_many_reference_images`, `reference_video_not_supported` and `unsupported_reference_video_format`.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "500":
          $ref: "#/components/responses/CreationFailed"
      security:
        - bearerAuth: []
  /gen-task/inpaint:
    post:
      tags:
        - image
      summary: Create an inpaint, outpaint or redraw task
      description: |
        Edits an existing image:

        - **Inpaint** (`fillType: inpaint`): redraws the masked area.
        - **Outpaint** (`fillType: outpaint`): extends the image beyond its edges. Place the original on a larger white canvas and send that as `baseImageMediaId`; the mask marks the new area.
        - **Redraw** (`fillType: inpaint`, no mask): redraws the whole image, keeping it closer to the original as `strength` goes down.

        A masked edit takes two extra images, always sent together:

        - `maskMediaId`: same size as the base image, white where to redraw and black where to keep.
        - `maskedImageMediaId`: the base image with the white area of the mask painted gray (`#808080`).

        The output has the size of the masked image when a mask is sent, otherwise of the base image. Images are media IDs; see `POST /v2/media/image/upload-url`.

        Use `modelPreset: "v1"`. `GET /v2/gen-task/inpaint/constraints` lists the size limits and `sdeditPreset` names of a preset. Credits are charged when the task is created; the result is `outputs.mediaIds[0]` of `GET /v2/task/{id}`.
      operationId: createInpaint
      x-codeSamples:
        - id: curl
          lang: bash
          label: cURL
          source: |
            curl -X POST https://api.pixai.art/v2/gen-task/inpaint \
              -H "Authorization: Bearer $PIXAI_API_KEY" \
              -H "Content-Type: application/json" \
              -d '{
                "modelPreset": "v1",
                "fillType": "inpaint",
                "baseImageMediaId": "1943547603237249965",
                "maskMediaId": "1943547603237249966",
                "prompt": "red scarf"
              }'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                modelPreset:
                  type: string
                  minLength: 1
                  description: The inpaint model. Use `v1`.
                  example: v1
                fillType:
                  enum:
                    - inpaint
                    - outpaint
                  type: string
                baseImageMediaId:
                  type: string
                  description: Image media ID of the image to edit.
                maskMediaId:
                  type: string
                  description: Image media ID of the mask, white where to redraw and black where to keep. Send it with `maskedImageMediaId`, or omit both to redraw the whole image.
                maskedImageMediaId:
                  type: string
                  description: Image media ID of the base image with the mask's white area painted `#808080`. Send it with `maskMediaId`.
                prompt:
                  type: string
                  maxLength: 10000
                  default: ""
                  description: What to draw in the edited area.
                strength:
                  type: number
                  minimum: 0
                  maximum: 1
                  multipleOf: 0.01
                  description: How far the result may depart from the original. Lower keeps it closer.
                seed:
                  type: integer
                  description: Random seed. Omit for a random one.
                promptHelper:
                  enum:
                    - enable
                    - disable
                    - low
                    - medium
                  type: string
                  default: enable
                  description: How much PixAI may expand the prompt.
                sdeditPreset:
                  type: string
                  minLength: 1
                  maxLength: 64
                  description: A redraw preset name from `GET /v2/gen-task/inpaint/constraints`. Sending one to a preset without any answers `SDEDIT_NOT_AVAILABLE`.
                sdedit:
                  type: object
                  properties:
                    spectralScale:
                      type: number
                      minimum: 0
                      maximum: 1
                    hfsBlurSigma:
                      type: number
                      minimum: 0
                      maximum: 32
                    hfsEnd:
                      type: number
                      minimum: 0
                      maximum: 1
                    colorCorrection:
                      type: boolean
                      description: Match the colors of the original.
                  description: Fine-tuning for redraws. With `sdeditPreset`, only `colorCorrection` is taken from here.
              required:
                - baseImageMediaId
                - fillType
                - modelPreset
            example:
              modelPreset: v1
              fillType: inpaint
              baseImageMediaId: "1943547603237249965"
              maskMediaId: "1943547603237249966"
              prompt: red scarf
      responses:
        "201":
          description: The task was created. Poll `GET /v2/task/{id}` with its `id`.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Task"
        "400":
          description: |
            - `INVALID_MODEL_PRESET`: unknown `modelPreset`.
            - `INVALID_MEDIA`: an image media ID does not exist or is not an image.
            - `INVALID_SDEDIT_PRESET`: unknown `sdeditPreset`.
            - `SDEDIT_NOT_AVAILABLE`: this `modelPreset` takes no `sdeditPreset` or `sdedit`.
            - `BAD_REQUEST` with `data.issues`: the body failed validation.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/CannotRun"
        "500":
          $ref: "#/components/responses/CreationFailed"
      security:
        - bearerAuth: []
  /gen-task/inpaint/constraints:
    get:
      tags:
        - image
      summary: Get the limits of an inpaint preset
      description: Returns the size limits and redraw presets of an inpaint `modelPreset`. An unknown preset answers `null` fields rather than an error. No authentication is needed.
      operationId: getInpaintConstraints
      parameters:
        - name: modelPreset
          in: query
          required: true
          schema:
            type: string
            minLength: 1
          example: v1
      responses:
        "200":
          description: The preset's limits.
          content:
            application/json:
              schema:
                type: object
                properties:
                  modelPreset:
                    type: string
                  constraints:
                    type:
                      - object
                      - "null"
                    description: Size limits for the image, or `null` if the preset sets none.
                    properties:
                      minWidth:
                        type: integer
                      maxWidth:
                        type: integer
                      minHeight:
                        type: integer
                      maxHeight:
                        type: integer
                      maxPixels:
                        type: integer
                        description: Maximum width × height.
                      dimensionStep:
                        type: integer
                        description: Width and height must be multiples of this.
                  sdeditPresets:
                    type:
                      - object
                      - "null"
                    description: Redraw presets by name, for `sdeditPreset`.
                    additionalProperties:
                      type: object
                  defaultSdeditPreset:
                    type:
                      - string
                      - "null"
      security:
        - {}
        - bearerAuth: []
  /task/{id}:
    get:
      tags:
        - task
      summary: Get a task
      description: |
        Reads a task created by any v2 endpoint. Poll it every few seconds until `status` is `completed`, `failed` or `cancelled`.

        Where the result is:

        - Images (`taskKind` `t2i`, `i2i`, `inpaint`): `outputs.mediaIds` and `outputs.mediaUrls`.
        - Videos (`taskKind` `i2v-inhouse`, `reference-video`): `outputs.videoMediaId`. Resolve it with `GET /v2/media/batch?ids=<videoMediaId>` and download `fileUrl`. `outputs.mediaIds` then holds only the poster image.

        Generated media is not kept forever. Download results soon after they finish.
      operationId: getTask
      x-codeSamples:
        - id: curl
          lang: bash
          label: cURL
          source: |
            curl https://api.pixai.art/v2/task/1943547603237249965 \
              -H "Authorization: Bearer $PIXAI_API_KEY"
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
          description: The task ID.
        - name: with_parameters
          in: query
          schema:
            type: string
            enum:
              - "true"
          description: Send `true` to include the stored task parameters in `parameters`.
      responses:
        "200":
          description: The task.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Task"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          description: "`NOT_FOUND`: no task with this ID is visible to you. A request without an API key gets this for every task."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
      security:
        - bearerAuth: []
  /media/image/upload-url:
    post:
      tags:
        - media
      summary: Get an upload URL for an image
      description: |
        Step 1 of uploading an image you want to use as an input, for example a `contextImages` entry, a video frame or an inpaint base image.

        1. Call this endpoint to get `uploadUrl` and `externalId`.
        2. Send the raw image bytes to `uploadUrl` with an HTTP `PUT` and the file's real `Content-Type` (for example `image/png`). Do not use a multipart form.
        3. Call `POST /v2/media/image/register` with the `externalId`. Its `id` is the media ID you pass to other endpoints.
      operationId: getImageUploadUrl
      x-codeSamples:
        - id: curl
          lang: bash
          label: cURL
          source: |
            # 1. Get an upload URL
            UPLOAD=$(curl -s -X POST https://api.pixai.art/v2/media/image/upload-url \
              -H "Authorization: Bearer $PIXAI_API_KEY" \
              -H "Content-Type: application/json" -d '{}')
            URL=$(echo "$UPLOAD" | jq -r .uploadUrl)
            EXTERNAL_ID=$(echo "$UPLOAD" | jq -r .externalId)

            # 2. Upload the bytes
            curl -X PUT "$URL" -H "Content-Type: image/png" --data-binary @input.png

            # 3. Register it and read the media ID
            curl -s -X POST https://api.pixai.art/v2/media/image/register \
              -H "Authorization: Bearer $PIXAI_API_KEY" \
              -H "Content-Type: application/json" \
              -d "{\"externalId\": \"$EXTERNAL_ID\"}" | jq -r .id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                isEphemeral:
                  type: boolean
                  default: false
                  description: Mark the file as a short-lived generation input. Ephemeral files are private, and their URLs are signed and expire.
            example: {}
      responses:
        "200":
          description: The upload target.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UploadUrl"
        "401":
          $ref: "#/components/responses/Unauthorized"
      security:
        - bearerAuth: []
  /media/image/register:
    post:
      tags:
        - media
      summary: Register an uploaded image
      description: |
        Step 3 of uploading an image: turns the uploaded file into a media item. Call it after the `PUT` to `uploadUrl` has succeeded. The returned `id` is the media ID to pass to other endpoints.
      operationId: registerImage
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                externalId:
                  type: string
                  format: uuid
                  description: The `externalId` returned by `POST /v2/media/image/upload-url`.
                isEphemeral:
                  type: boolean
                  description: Send the same value you sent to `upload-url`.
              required:
                - externalId
            example:
              externalId: 3f2b8c1e-6a4d-4f6e-9b1a-2c7d5e8f9a01
      responses:
        "200":
          description: The registered image. `width` and `height` can be `0` until processing finishes a few seconds later; read them from `GET /v2/media/batch` if you need them.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Media"
        "401":
          $ref: "#/components/responses/Unauthorized"
      security:
        - bearerAuth: []
  /media/audio/upload-url:
    post:
      tags:
        - media
      summary: Get an upload URL for an audio file
      description: |
        Step 1 of uploading an audio clip for `referenceAudioMediaIds` of `POST /v2/reference-video/create`. The flow is the same as for images: `PUT` the bytes to `uploadUrl` with the file's `Content-Type` (`audio/mpeg` or `audio/wav`), then call `POST /v2/media/audio/register`.

        Only WAV and MP3 are accepted, under 15 MiB per clip. Duration limits depend on the video model; they are checked when the video task is created, not at upload.
      operationId: getAudioUploadUrl
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                isEphemeral:
                  type: boolean
                  default: false
                  description: Mark the file as a short-lived generation input. Ephemeral files are private, and their URLs are signed and expire.
            example: {}
      responses:
        "200":
          description: The upload target.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UploadUrl"
        "401":
          $ref: "#/components/responses/Unauthorized"
      security:
        - bearerAuth: []
  /media/audio/register:
    post:
      tags:
        - media
      summary: Register an uploaded audio file
      description: Step 3 of uploading an audio clip. The returned `id` is the media ID to pass in `referenceAudioMediaIds`.
      operationId: registerAudio
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                externalId:
                  type: string
                  minLength: 1
                  description: The `externalId` returned by `POST /v2/media/audio/upload-url`.
              required:
                - externalId
            example:
              externalId: 3f2b8c1e-6a4d-4f6e-9b1a-2c7d5e8f9a01
      responses:
        "200":
          description: The registered audio file.
          content:
            application/json:
              schema:
                type: object
                required:
                  - id
                properties:
                  id:
                    type: string
                    description: The media ID.
                  fileUrl:
                    type:
                      - string
                      - "null"
                    description: URL of the file.
                  duration:
                    type:
                      - number
                      - "null"
                    description: Length in seconds.
                  size:
                    type:
                      - number
                      - "null"
                    description: Size in bytes.
                  codec:
                    type:
                      - string
                      - "null"
        "401":
          $ref: "#/components/responses/Unauthorized"
      security:
        - bearerAuth: []
  /media/{mediaId}/info:
    get:
      tags:
        - media
      summary: Inspect a video or audio file
      description: |
        Returns the duration, size, containers and codecs of a video or audio media item, so you can check a reference file against the model's limits before creating a reference video task.
      operationId: getMediaInfo
      parameters:
        - name: mediaId
          in: path
          required: true
          schema:
            type: string
          description: A video or audio media ID.
      responses:
        "200":
          description: The media metadata.
          content:
            application/json:
              schema:
                type: object
                properties:
                  mediaId:
                    type: string
                  durationSeconds:
                    type:
                      - number
                      - "null"
                    description: Length in seconds.
                  sizeBytes:
                    type:
                      - string
                      - "null"
                    description: Size in bytes, as a decimal string.
                  containers:
                    type: array
                    items:
                      type: string
                    description: Container formats, lowercase, e.g. `mp3` or `mov`.
                  videoStreams:
                    type: array
                    description: One entry per video stream.
                    items:
                      type: object
                      properties:
                        codec:
                          type: string
                        width:
                          type: integer
                        height:
                          type: integer
                        averageFrameRate:
                          type: number
                  audioStreams:
                    type: array
                    description: One entry per audio stream.
                    items:
                      type: object
                      properties:
                        codec:
                          type: string
        "400":
          description: "`NOT_VIDEO_OR_AUDIO`: the media is an image."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          description: "`MEDIA_NOT_FOUND`: no media has this ID."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
      security:
        - bearerAuth: []
  /media/batch:
    get:
      tags:
        - media
      summary: Get media URLs by ID
      description: |
        Resolves up to 100 media IDs to their URLs, for example the `outputs.mediaIds` or `outputs.videoMediaId` of a finished task. No authentication is needed for public media.

        IDs that do not exist are left out, and the order of the result is not guaranteed, so match items by `id`.
      operationId: batchGetMedia
      parameters:
        - name: ids
          in: query
          required: true
          schema:
            anyOf:
              - type: string
              - type: array
                items:
                  type: string
            description: Media IDs to resolve (1–100). Accepts comma-separated (`?ids=1,2,3`), bracket notation (`?ids[]=1&ids[]=2`), or repeated (`?ids=1&ids=2`).
            type: string
          description: Comma-separated media IDs, 1 to 100, e.g. `?ids=1,2,3`. Repeating the parameter (`?ids=1&ids=2`) also works.
      responses:
        "200":
          description: The media items found.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Media"
      security:
        - {}
        - bearerAuth: []
  /generation-model/search:
    get:
      tags:
        - model
      summary: Search models and LoRAs
      description: |
        Searches the [PixAI Model Market](https://pixai.art/model). Use it to find a base model for `modelVersionId`, or LoRAs for `loras` of `POST /v2/image/create`.

        To use a result, pass its `latestAvailableVersionId`, not its `id`: generation endpoints take **version** IDs. A LoRA's default trigger words are in `latestAvailableVersion.extra.triggerWords`.

        To find LoRAs that work with a base model, send `usageType=LORA` and the base model's type in `loraBaseModelTypes` (the `type` of a model item, e.g. `SDXL_MODEL`).

        Results depend on who is asking: send your API key to get the same content rating as your account. Anonymous requests get stricter filtering.
      operationId: searchGenerationModels
      parameters:
        - name: usageType
          in: query
          required: true
          schema:
            anyOf:
              - const: ALL
              - const: MODEL
              - const: LORA
            type: string
            enum:
              - ALL
              - MODEL
              - LORA
          description: "`MODEL` for base models, `LORA` for LoRAs, `ALL` for both."
        - name: keyword
          in: query
          schema:
            type: string
            minLength: 1
            maxLength: 256
          description: Free-text query. Results rank by relevance and popularity; without a keyword, by popularity.
        - name: loraBaseModelTypes
          in: query
          schema:
            type: string
          description: "With `usageType=LORA`: comma-separated base model types the LoRA must work with, e.g. `SDXL_MODEL`."
        - name: baseModelIds
          in: query
          schema:
            type: string
          description: "With `usageType=LORA`: comma-separated base model IDs the LoRA must work with."
        - name: source
          in: query
          schema:
            enum:
              - ANY
              - PIXAI
              - EXTERNAL
            type: string
            default: ANY
          description: "With `usageType=LORA`: `PIXAI` for LoRAs trained on PixAI, `EXTERNAL` for imported ones."
        - name: baseModelType
          in: query
          schema:
            type: string
          description: "With `usageType=MODEL`: comma-separated model types, e.g. `SDXL_MODEL,MMDIT26B_MODEL`."
        - name: permittedUse
          in: query
          schema:
            enum:
              - COMMERCIAL
              - PERSONAL
            type: string
          description: Only models whose license allows this use.
        - name: postedWithin
          in: query
          schema:
            enum:
              - today
              - this-week
              - this-month
            type: string
        - name: authorId
          in: query
          schema:
            type: string
          description: Only models by this user.
        - name: size
          in: query
          schema:
            type: integer
            maximum: 50
            exclusiveMinimum: 0
            default: 24
            minimum: 1
          description: Page size.
        - name: offset
          in: query
          schema:
            type: integer
            minimum: 0
            maximum: 10000
            default: 0
          description: Number of results to skip. Pages can overlap slightly; de-duplicate by `id`.
      responses:
        "200":
          description: One page of results.
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - hasMore
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/ModelListItem"
                  hasMore:
                    type: boolean
                    description: Whether another page may follow.
      security:
        - {}
        - bearerAuth: []
  /generation-model/{id}:
    get:
      tags:
        - model
      summary: Get a model or LoRA
      description: Reads one model by its **model** ID (the `id` of a search result).
      operationId: getGenerationModel
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
          description: The model ID.
      responses:
        "200":
          description: The model.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/ModelListItem"
                  - type: object
                    properties:
                      triggerWords:
                        type:
                          - string
                          - "null"
                        description: Default trigger words of the latest version.
        "404":
          $ref: "#/components/responses/ModelNotFound"
      security:
        - {}
        - bearerAuth: []
  /generation-model/{modelId}/versions:
    get:
      tags:
        - model
      summary: List the versions of a model
      description: Lists a model's versions, newest first. Pass a version's `id` as `modelVersionId` or `loras[].modelId` to pin an older version.
      operationId: listGenerationModelVersions
      parameters:
        - name: modelId
          in: path
          required: true
          schema:
            type: string
          description: The model ID.
        - name: baseModelType
          in: query
          schema:
            enum:
              - ANY_LORA
              - ANY_MODEL
              - ANY_NON_SDXL_LORA
              - ANY_NON_USER_LORA
              - ANY_SDXL_LORA
              - ANY_USER_LORA
              - ANY_VAE
              - CHAT
              - DIT5A_MODEL_INTERNAL
              - DIT7A_LORA
              - DIT7A_MODEL
              - DIT7A_VAE
              - DIT7B_LORA
              - DIT7B_MODEL
              - DIT7B_VAE
              - DIT7C_LORA
              - DIT7C_MODEL
              - DIT7C_VAE
              - DIT7D_LORA
              - DIT7D_MODEL
              - DIT7D_VAE
              - DIT7_LORA
              - DIT7_MODEL
              - DIT7_VAE
              - DIT9_LORA
              - DIT9_MODEL
              - DIT9_VAE
              - LORA
              - MMDIT26A_MODEL
              - MMDIT26B_MODEL
              - MULTI_LORA
              - SD3_MEDIUM_MODEL
              - SDXL_LORA
              - SDXL_MODEL
              - SDXL_VAE
              - SD_V1_MODEL
              - UNKNOWN_LORA
              - UNKNOWN_MODEL
              - USER_DIT26A_MODEL
              - USER_DIT26B_MODEL
              - USER_LORA
              - USER_MULTI_LORA
              - USER_SDXL_LORA
              - VAE
              - VIDEO_MODEL
              - VIDEO_MODEL_LORA
              - Z_IMAGE_V1_MODEL
            type: string
          description: Only versions for this base model type.
      responses:
        "200":
          description: The versions.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/ModelVersion"
        "404":
          $ref: "#/components/responses/ModelNotFound"
      security:
        - {}
        - bearerAuth: []
  /generation-model-version/{id}:
    get:
      tags:
        - model
      summary: Get a model version
      description: Reads one model version by its **version** ID, the ID that generation endpoints take. Use it to look up a LoRA's trigger words and base model before generating.
      operationId: getGenerationModelVersion
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
          description: The model version ID.
      responses:
        "200":
          description: The version.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ModelVersion"
        "404":
          $ref: "#/components/responses/ModelNotFound"
      security:
        - {}
        - bearerAuth: []
  /generation-model/{modelVersionId}/size-config:
    get:
      tags:
        - model
      summary: Get the sizes a model version accepts
      description: |
        Lists the sizes a model version accepts for `width`/`height` of `POST /v2/image/create`. Despite the path, the parameter is a **version** ID.

        A custom `width`/`height` must fall inside one range's `minWidth`–`maxWidth` and `minHeight`–`maxHeight` and be a multiple of its `step`. Presets are ready-made sizes and may lie outside those bounds. Entries whose `accessStatus` is `membership_required` need a higher membership tier than your account has.
      operationId: getModelSizeConfig
      parameters:
        - name: modelVersionId
          in: path
          required: true
          schema:
            type: string
          description: The model version ID.
      responses:
        "200":
          description: The size ranges.
          content:
            application/json:
              schema:
                type: object
                properties:
                  ranges:
                    type: array
                    items:
                      type: object
                      properties:
                        name:
                          type: string
                        minWidth:
                          type: integer
                        maxWidth:
                          type: integer
                        minHeight:
                          type: integer
                        maxHeight:
                          type: integer
                        step:
                          type: integer
                          description: Width and height must be multiples of this.
                        accessStatus:
                          type: string
                          enum:
                            - available
                            - membership_required
                        presets:
                          type: array
                          items:
                            type: object
                            properties:
                              id:
                                type: string
                              width:
                                type: integer
                              height:
                                type: integer
                              ratioLabel:
                                type: string
                                description: e.g. `9:16`.
                              accessStatus:
                                type: string
                                enum:
                                  - available
                                  - membership_required
        "404":
          $ref: "#/components/responses/ModelNotFound"
      security:
        - {}
        - bearerAuth: []
  /color-palettes/presets:
    get:
      tags:
        - model
      summary: List color palette presets
      description: |
        Lists PixAI's official color palettes for `colorPalette` of `POST /v2/image/create`. To use one, send the whole preset object with `"source": "preset"` added.

        `name` is localized: pass `?lang=ja` (or `ko`, `en`), or an `Accept-Language` header.
      operationId: listColorPalettePresets
      responses:
        "200":
          description: The presets.
          content:
            application/json:
              schema:
                type: object
                properties:
                  palettes:
                    type: array
                    items:
                      allOf:
                        - $ref: "#/components/schemas/ColorPalette"
                        - type: object
                          properties:
                            coverUrl:
                              type:
                                - string
                                - "null"
                              description: Preview image.
      security:
        - {}
        - bearerAuth: []

components:
  schemas:
    CreateImageRequest:
      type: object
      required:
        - modelVersionId
        - prompt
      additionalProperties: false
      properties:
        modelVersionId:
          type: string
          minLength: 1
          description: |
            The unique identifier for the model version to use for generation. Preferred replacement for the deprecated `modelId` field.

            How to find modelVersionId:
            1. Open the model page on PixAI.
            2. Click the model version you'd like to use.
            3. Copy the last path segment of the URL — that's the modelVersionId.

            Example URL: `https://pixai.art/model/<id>-<slug>/<modelVersionId>` → modelVersionId is `<modelVersionId>`.

            <img src="/images/find-modelid.png" alt="Find modelVersionId" />
          example: "1983308862240288769"
        modelId:
          type: string
          minLength: 1
          x-fold: true
          x-badge:
            - type: deprecated
              info: |
                Please use `modelVersionId` instead. `modelId` is ambiguous: it actually expects a model **version** ID instead of a model ID.
          description: |
            The unique identifier for the model version to use for generation. Taken from the model version's URL on PixAI.

            How to find modelId:
            1. Open the model page on PixAI.
            2. Click the model version you'd like to use.
            3. Copy the last path segment of the URL — that's the modelId.

            Example URL: `https://pixai.art/model/<id>-<slug>/<modelVersionId>` → modelId is `<modelVersionId>`.

            <img src="/images/find-modelid.png" alt="Find modelId" />
          example: "1983308862240288769"
        prompt:
          type: string
          minLength: 1
          maxLength: 10000
          description: |
            The main prompt describing the content you want to generate. Up to 10,000 characters on Tsubaki.2 and Tsubaki.3, 4,096 on other models.
          example: "1girl, green hair, solo, standing"
        negativePrompt:
          type: string
          maxLength: 4096
          description: |
            Text describing elements to avoid in the generated image.
          example: "nsfw, lowres, bad anatomy"
        aspectRatio:
          type: string
          enum:
            - "1:1"
            - "2:3"
            - "3:2"
            - "3:4"
            - "4:3"
            - "3:5"
            - "5:3"
            - "9:16"
            - "16:9"
            - "1:3"
            - "3:1"
          description: |
            The aspect ratio of the generated image. Defaults to `1:1` when neither `aspectRatio`/`size` nor `width`/`height` is sent. Cannot be combined with `width` and `height`.

            Available ratios: `1:1`, `2:3`, `3:2`, `3:4`, `4:3`, `3:5`, `5:3`, `9:16`, `16:9`, `1:3`, `3:1`

            All ratios are supported across all model types (SDXL, DiT, Tsubaki.2).

            See [Supported Resolutions](/en/docs/references/supported-resolutions) for the full resolution mapping per size tier.
          example: "1:1"
        size:
          type: string
          enum:
            - "1k"
            - "1.5k"
          description: |
            The output resolution tier. Defaults to `1k` when neither `aspectRatio`/`size` nor `width`/`height` is sent. Cannot be combined with `width` and `height`. The longest edge is capped at 1536 px for `1.5k`.
            - `1k`: ~1 megapixel (e.g. 1024×1024 at 1:1).
            - `1.5k`: ~2.36 megapixels (e.g. 1536×1536 at 1:1).

            See [Supported Resolutions](/en/docs/references/supported-resolutions) for the full mapping table.
          example: "1k"
        width:
          type: integer
          minimum: 1
          maximum: 10240
          description: |
            Exact output width in pixels, for sizes the `aspectRatio`/`size` presets do not cover (e.g. Tsubaki.3's larger outputs). Send together with `height` and without `aspectRatio` and `size`.

            The size must fall within one of the model's size ranges and be a multiple of its `step`. Read them from `GET https://api.pixai.art/v2/generation-model/{modelVersionId}/size-config` (no authentication needed): each entry of `ranges` gives `minWidth`/`maxWidth`, `minHeight`/`maxHeight` and `step`, plus ready-made `presets`. A size outside every range returns `400 IMAGE_SIZE_NOT_ALLOWED`.
          example: 1024
        height:
          type: integer
          minimum: 1
          maximum: 10240
          description: |
            Exact output height in pixels. Send together with `width`; see `width` for the allowed sizes.
          example: 1024
        mode:
          type: string
          x-badge:
            - type: tsubaki2
              info: |
                Only available for the **Tsubaki.2** and **Tsubaki.3** model families. Rejected with `400 INVALID_ARGUMENT` on other model types.
          enum:
            - lite
            - standard
            - pro
            - ultra
          description: |
            The inference profile controlling generation quality and speed.
            - `lite`: Fastest, basic quality.
            - `standard`: Balanced speed and quality.
            - `pro`: Higher quality, slower.
            - `ultra`: Highest quality, slowest.

            Not every mode is offered on every model or plan; an unavailable mode returns `422 INVALID_INPUT` naming the mode.
          example: standard
        style:
          x-badge:
            - type: tsubaki2
              info: |
                Only available for the **Tsubaki.2** and **Tsubaki.3** model families. Silently ignored for other model types.
          description: |
            The style to apply during image generation. Can be a named preset or a custom style string.
          oneOf:
            - type: object
              additionalProperties: false
              required:
                - type
                - key
              properties:
                type:
                  type: string
                  enum:
                    - preset
                key:
                  type: string
                  enum:
                    - anime-watercolor-impasto
                    - art-crayon
                    - bold-line-soft-color
                    - chibi
                    - classic-japanese
                    - clean-flat-illustration
                    - colored-pencil-grain
                    - cool-warm-oil-contrast
                    - desaturated-cool
                    - flat-anime-pastel
                    - glossy-glass-anime
                    - grey-blocks-lineless
                    - hard-line-monochrome-accent
                    - high-contrast-retro-vivid
                    - holographic
                    - korean-style
                    - lineart-watercolor-airy
                    - low-saturation-expressive-eyes
                    - lucid-dreamy
                    - luminous-retro-impasto
                    - minimal-flat-color
                    - modern-oil-glamour
                    - moe-pastel
                    - oil-watercolor-blend
                    - painterly-doodle
                    - paper-watercolor
                    - pencil-sketch
                    - poster-graffiti
                    - retro-comic-fusion
                    - retro-oil-glamour
                    - retro-tv-anime
                    - semi-realistic
                    - stable-vaporwave
                    - tinted-sketch
                    - vintage-collage
                  description: |
                    A named preset style key. Available presets:
                    - `anime-watercolor-impasto` — Watercolor Glow
                    - `art-crayon` — Art Crayon
                    - `bold-line-soft-color` — Glint & Gloom
                    - `chibi` — Chibi
                    - `classic-japanese` — Classic Anime
                    - `clean-flat-illustration` — Clean Flat-Illustration
                    - `colored-pencil-grain` — Chromatic Pencil
                    - `cool-warm-oil-contrast` — Seasonal Glow
                    - `desaturated-cool` — Cool Softlight
                    - `flat-anime-pastel` — Pastel Flat
                    - `glossy-glass-anime` — Glassy Anime
                    - `grey-blocks-lineless` — Grey Wash
                    - `hard-line-monochrome-accent` — Sharp Ink
                    - `high-contrast-retro-vivid` — Neon Vivid
                    - `holographic` — Hyper Pop
                    - `korean-style` — Polished Manhwa
                    - `lineart-watercolor-airy` — Luminous Wash
                    - `low-saturation-expressive-eyes` — Muted & Transparent
                    - `lucid-dreamy` — Lucid Dreamy
                    - `luminous-retro-impasto` — Luminous Impasto
                    - `minimal-flat-color` — Minimal Flat
                    - `modern-oil-glamour` — Modern Glam Anime
                    - `moe-pastel` — Moe Pastel
                    - `oil-watercolor-blend` — Water-Infused Oil
                    - `painterly-doodle` — Tender Brushstroke
                    - `paper-watercolor` — Soft Aqueous
                    - `pencil-sketch` — Pencil Sketch
                    - `poster-graffiti` — Neon Poster
                    - `retro-comic-fusion` — Retro Fusion
                    - `retro-oil-glamour` — Retro Glam Anime
                    - `retro-tv-anime` — 90s Retro-Cell
                    - `semi-realistic` — Semi-Real
                    - `stable-vaporwave` — Neon Vaporwave
                    - `tinted-sketch` — Tinted Sketch
                    - `vintage-collage` — Vintage Collage
            - type: object
              additionalProperties: false
              required:
                - type
                - custom
              properties:
                type:
                  type: string
                  enum:
                    - custom
                custom:
                  type: string
                  description: |
                    A raw style prompt string injected as a prefix to the generation prompt. This is an advanced option — incorrect values may degrade output quality.
          discriminator:
            propertyName: type
        loras:
          type: array
          maxItems: 15
          description: |
            Apply one or more LoRA adapters to fine-tune output style or content. How many can be combined depends on your plan (3 without a membership, up to 15); more returns `403 LORA_NUM_EXCEEDED`.

            Use a LoRA made for the same base model as the generation model: a LoRA's page on PixAI shows its base model.

            How to find LoRA modelId:
            1. Open the LoRA model page on PixAI.
            2. Click the LoRA version you'd like to use.
            3. Copy the last path segment of the URL — that's the LoRA version ID.

            Example URL: `https://pixai.art/model/<loraModelId>/<loraVersionId>` → LoRA version ID is `<loraVersionId>`.
          items:
            $ref: "#/components/schemas/LoraItem"
        contextImages:
          type: array
          maxItems: 3
          x-badge:
            - type: tsubaki3
              info: |
                Only available for **Tsubaki.3** (`modelVersionId` `2024383379556065549`). Other models return `400 BAD_REQUEST` ("This feature is not yet supported for this model").
          description: |
            Reference images for in-context generation, e.g. keeping a character consistent or taking a pose from another image.

            Each item is a media ID: an ID from a finished task's `outputs.mediaIds`, or one returned by [Upload an image or video](/en/docs/api/media/uploadMedia). Each image must be under 4000 px on both sides.
          items:
            type: string
            description: A media ID.
          example: [ "1943547603237249965" ]
        seed:
          type: integer
          description: |
            Random seed for reproducible generation. Omit to use a randomly generated seed.
          example: 42
        batchSize:
          type: integer
          enum:
            - 1
            - 4
          default: 1
          description: |
            Number of images to generate in one task. Supported values are `1` and `4`. Defaults to `1`.
          example: 4
        sampling:
          type: object
          x-badge:
            - type: sdxl-sdv1
              info: |
                Only available for **SDXL** and **SD v1** model families.
          description: |
            Advanced sampling parameters for fine-tuning the diffusion process. All fields are optional — omitting a field uses the model's default.

            Refer to the [Models](/en/docs/references/models) page for allowed sampling methods per model.
          additionalProperties: false
          properties:
            method:
              type: string
              description: |
                Sampler algorithm used during generation. Supported methods vary by model — see the [Models](/en/docs/references/models) page.
              example: "DPM++ 2M Karras"
            steps:
              type: integer
              minimum: 1
              maximum: 100
              description: |
                Number of diffusion steps. Higher values can improve detail but increase generation time and cost.
              example: 25
            cfgScale:
              type: number
              description: |
                Classifier-Free Guidance (CFG) scale. Controls the balance between prompt adherence and creative freedom. Higher values follow the prompt more strictly.
              example: 7
        promptHelper:
          type: string
          enum:
            - enable
            - disable
            - low
            - medium
          default: enable
          description: |
            Whether to use the built-in prompt helper to enhance the prompt before generation.
            - `enable`: Automatically enhance the prompt (default).
            - `disable`: Use the prompt as-is.
            - `low` / `medium`: How freely the helper rewrites the prompt, on Tsubaki.2 and Tsubaki.3. Other models treat both as `enable`.
          x-callout: "Enabling this field will incur additional charges."
        callbackUrl:
          type: string
          format: uri
          description: |
            A publicly accessible URL to receive task status updates via POST request (webhook).

            We will send a POST request to the callback URL when the task status changes.
          example: "https://your-server.example.com/webhook"
        colorPalette:
          x-badge:
            - type: tsubaki3
              info: |
                Only available for **Tsubaki.3** (`modelVersionId` `2024383379556065549`). Other models return `400 BAD_REQUEST` ("This feature is not yet supported for this model").
          description: |
            Steer the colors of the image. Take a preset from `GET /v2/color-palettes/presets` and send it whole, with `"source": "preset"` added.
          allOf:
            - $ref: "#/components/schemas/ColorPalette"
            - type: object
              required:
                - source
              properties:
                source:
                  type: string
                  enum:
                    - preset
                    - user
    LoraItem:
      type: object
      required:
        - modelId
      additionalProperties: false
      properties:
        modelId:
          type: string
          description: The LoRA model version ID from the PixAI Model Market.
          example: "1744880666293972790"
        weight:
          type: number
          minimum: 0
          maximum: 1
          default: 1
          description: The influence weight of the LoRA adapter. Range 0.0–1.0.
          example: 0.7
        triggerWords:
          type: string
          description: |
            Custom trigger words for this LoRA. If omitted, the LoRA's default trigger words are added automatically; an empty string adds none.
    Error:
      type: object
      required:
        - code
        - status
        - message
      properties:
        code:
          type: string
          description: Machine-readable error code, e.g. `BAD_REQUEST` or `INSUFFICIENT_BALANCE`. Branch on this, not on `message`.
        status:
          type: integer
          description: The HTTP status code.
        message:
          type: string
          description: Human-readable detail, often naming the field or value at fault.
        data:
          type: object
          description: Code-specific detail, e.g. `issues` for validation errors or `reason` for `IMAGE_SIZE_NOT_ALLOWED`.
        defined:
          type: boolean
          description: Whether `code` is one this endpoint declares.
    Task:
      type: object
      required:
        - id
        - status
        - createdAt
        - updatedAt
      properties:
        id:
          type: string
          description: "The unique identifier for the task."
        status:
          type: string
          description: "The current status of the task."
          enum:
            - waiting
            - running
            - completed
            - cancelled
            - failed
        createdAt:
          type: string
          description: "The time the task was created."
          format: date-time
        updatedAt:
          type: string
          description: "The time the task was last updated."
          format: date-time
        startedAt:
          type: string
          description: "The time the task started running."
          format: date-time
        endAt:
          type: string
          description: "The time the task finished."
          format: date-time
        taskKind:
          type: string
          description: |
            What the task makes: `t2i` or `i2i` for images, `inpaint` for `POST /v2/gen-task/inpaint`, `i2v-inhouse` for `POST /v2/frame-video/create`, `reference-video` for `POST /v2/reference-video/create`.
        paidQuota:
          type: integer
          description: Credits charged for the task.
        taskStatusMsgI18n:
          type: object
          description: Why a `failed` task failed.
          properties:
            key:
              type: string
              description: A stable message key.
            defaultMessage:
              type: string
              description: The message in English.
        outputs:
          type: object
          description: "The outputs produced by the task."
          properties:
            videoMediaId:
              type: string
              description: |
                For video tasks, the media ID of the video. Resolve it with `GET /v2/media/batch?ids=<videoMediaId>` and download `fileUrl`. `mediaIds` then holds only the poster image.
            seed:
              type: string
              description: The seed used, as a decimal string.
            mediaIds:
              type: array
              description: |
                Media IDs of the generated images. Use these IDs to fetch detailed information about each generated image.

                Generated images are not permanently retained — retrieve them as soon as possible.
              items:
                type: string
                description: The unique identifier for a generated media item.
            mediaUrls:
              type: array
              description: |
                Public URLs of the generated images.

                Generated images are not permanently retained — retrieve them as soon as possible. If an image is unavailable, its entry may be `null`.
              items:
                type:
                  - string
                  - "null"
                description: The URL of the media item, or null if unavailable.
    UploadUrlRequest:
      type: object
      properties:
        isEphemeral:
          type: boolean
          default: false
          description: Mark the file as a short-lived generation input. Ephemeral files are private, and their URLs are signed and expire.
    UploadUrl:
      type: object
      required:
        - uploadUrl
        - externalId
      properties:
        uploadUrl:
          type: string
          description: Presigned URL. `PUT` the raw file bytes to it with the file's `Content-Type`.
        externalId:
          type: string
          description: Pass this to the matching `register` endpoint after the upload.
    Media:
      type: object
      required:
        - id
        - type
      properties:
        id:
          type: string
          description: The media ID.
        type:
          type: string
          enum:
            - IMAGE
            - VIDEO
            - AUDIO
        urls:
          type: array
          description: Image URLs by variant. `PUBLIC` is the full image.
          items:
            type: object
            properties:
              variant:
                type: string
                enum:
                  - PUBLIC
                  - THUMBNAIL
                  - STILL_THUMBNAIL
              url:
                type: string
        width:
          type:
            - number
            - "null"
        height:
          type:
            - number
            - "null"
        fileUrl:
          type:
            - string
            - "null"
          description: URL of the file itself, e.g. the MP4 of a video.
        hlsUrl:
          type:
            - string
            - "null"
          description: HLS stream of a video. Often `null` for generated videos; use `fileUrl`.
        thumbnailUrl:
          type:
            - string
            - "null"
          description: Poster image of a video. Often `null` for generated videos; the task's `outputs.mediaIds` holds the poster.
        duration:
          type:
            - number
            - "null"
          description: Length of a video or audio file in seconds. Can be `0` for generated videos.
    ModelVersion:
      type: object
      required:
        - id
        - modelId
      properties:
        id:
          type: string
          description: The version ID. Pass it as `modelVersionId`, or as `loras[].modelId` for a LoRA.
        modelId:
          type: string
          description: The ID of the model this version belongs to.
        modelTitle:
          type: string
        name:
          type: string
          description: Version name.
        modelType:
          type:
            - string
            - "null"
          description: e.g. `SDXL_MODEL`, `MMDIT26B_MODEL` or `SDXL_LORA`.
        loraBaseModelType:
          type:
            - string
            - "null"
          description: For a LoRA, the base model type it was trained for. Use a base model of this type.
        loraBaseModelId:
          type:
            - string
            - "null"
          description: For a LoRA, the base model it was trained on.
        status:
          type:
            - string
            - "null"
          description: Only `available` versions can be used for generation.
        extra:
          type: object
          description: Version details. `triggerWords` holds the default trigger words of a LoRA.
          properties:
            triggerWords:
              type: string
        mediaId:
          type:
            - string
            - "null"
          description: Cover image media ID.
    ModelListItem:
      type: object
      required:
        - id
        - title
        - type
      properties:
        id:
          type: string
          description: The model ID. Generation endpoints take a version ID instead; use `latestAvailableVersionId`.
        title:
          type: string
        type:
          type: string
          description: e.g. `SDXL_MODEL`, `MMDIT26B_MODEL` or `SDXL_LORA`.
        category:
          type:
            - string
            - "null"
        loraBaseModelTypes:
          type: array
          items:
            type: string
          description: For a LoRA, the base model types it works with.
        permittedUse:
          type: string
          enum:
            - PERSONAL
            - COMMERCIAL
          description: What the license allows.
        mediaId:
          type:
            - string
            - "null"
          description: Cover image media ID.
        latestAvailableVersionId:
          type:
            - string
            - "null"
          description: The newest usable version. Pass it as `modelVersionId`, or as `loras[].modelId` for a LoRA.
        latestAvailableVersion:
          type:
            - object
            - "null"
          description: The newest usable version.
          properties:
            id:
              type: string
              description: Same as `latestAvailableVersionId`.
            name:
              type: string
            modelType:
              type:
                - string
                - "null"
            loraBaseModelType:
              type:
                - string
                - "null"
              description: For a LoRA, the base model type it was trained for.
            extra:
              type: object
              description: "`triggerWords` holds the default trigger words of a LoRA."
              properties:
                triggerWords:
                  type: string
    ColorPalette:
      type: object
      required:
        - id
        - name
        - palette
        - createdAt
        - updatedAt
      properties:
        id:
          type: string
        name:
          type: string
        palette:
          type: object
          description: Colors for the whole image and, optionally, the background and characters. `overall` or `background` is required.
          properties:
            overall:
              $ref: "#/components/schemas/PaletteColors"
            background:
              $ref: "#/components/schemas/PaletteColors"
            character:
              $ref: "#/components/schemas/PaletteColors"
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
    PaletteColors:
      type: object
      required:
        - colors
      properties:
        colors:
          type: array
          minItems: 1
          maxItems: 12
          items:
            type: object
            required:
              - hex
              - ratio
            properties:
              hex:
                type: string
                description: "`#RRGGBB`."
              ratio:
                type: number
                minimum: 0
                maximum: 100
                description: Share of the image, in percent.
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: API-Key
      description: |
        In all requests that require authentication
  headers:
    X-Trace-Id:
      description: "A unique identifier for the request. Useful for debugging and tracing."
      schema:
        type: string
  responses:
    Unauthorized:
      description: '`UNAUTHORIZED`: no API key was sent. An invalid, revoked or expired key answers `{"message": "invalid token", "code": 40100001}` instead, with a numeric `code`.'
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    CannotRun:
      description: |
        The account cannot run this task right now. `code` says why:

        - `INSUFFICIENT_BALANCE`: not enough credits for the task.
        - `WAITING_NUM_EXCEEDED`: too many of your tasks are still `waiting` (`data.currentWaitingTasks`). Wait for some to start before submitting more.
        - `REQUIRE_MEMBERSHIP`: the feature needs a PixAI membership (image-to-video).
        - `NSFW_PROMPTS_DETECTED`: the prompt was refused because the account is in safe mode.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    CreationFailed:
      description: "`CREATION_FAILED`: the task could not be created. Retry with exponential backoff."
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    ModelNotFound:
      description: "`NOT_FOUND`: no such model or version, or it is private. The two cases are not told apart."
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
