{
  "openapi": "3.1.0",
  "info": {
    "title": "LLM7 API",
    "description": "Discover models, generate and edit images, and create asynchronous video generation tasks through the LLM7 gateway.",
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "https://api.llm7.io/v1"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/models": {
      "get": {
        "operationId": "listModels",
        "summary": "List models",
        "description": "List the live model catalog, including pricing, modalities, and capability metadata.",
        "security": [],
        "responses": {
          "200": {
            "description": "Model catalog response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ModelListResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          }
        }
      }
    },
    "/videos": {
      "post": {
        "operationId": "createVideoTask",
        "summary": "Create video task",
        "description": "Create an asynchronous text-to-video or image-to-video task. Use JSON when there are no reference images and multipart/form-data when reference images are present.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VideoCreateJsonRequest"
              },
              "examples": {
                "textToVideo": {
                  "summary": "Text to video",
                  "value": {
                    "model": "seedance-2.0-mini",
                    "request_type": "text-to-video",
                    "duration": 8,
                    "resolution": "720p",
                    "prompt": "Waves crashing on rocks, cinematic slow motion",
                    "client_request_id": "video-demo-001"
                  }
                }
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/VideoCreateMultipartRequest"
              },
              "encoding": {
                "input_reference": {
                  "contentType": "image/png, image/jpeg, image/webp"
                }
              },
              "examples": {
                "imageToVideo": {
                  "summary": "Image to video",
                  "value": {
                    "model": "seedance-2.0-mini",
                    "request_type": "image-to-video",
                    "duration": 8,
                    "resolution": "720p",
                    "prompt": "Animate this first frame",
                    "client_request_id": "image-video-demo-001"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Queued video task",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VideoTaskResponse"
                },
                "examples": {
                  "queued": {
                    "summary": "Queued task",
                    "value": {
                      "id": "video_task_id",
                      "status": "queued",
                      "outputs": []
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/InsufficientBalance"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamInvalidResponse"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          }
        }
      }
    },
    "/videos/{id}": {
      "get": {
        "operationId": "retrieveVideoTask",
        "summary": "Retrieve video task",
        "description": "Poll a video generation task until it reaches completed, failed, or timeout.",
        "parameters": [
          {
            "$ref": "#/components/parameters/VideoTaskId"
          }
        ],
        "responses": {
          "200": {
            "description": "Video task status",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VideoTaskResponse"
                },
                "examples": {
                  "inProgress": {
                    "summary": "In progress task",
                    "value": {
                      "id": "video_task_id",
                      "status": "in_progress",
                      "outputs": []
                    }
                  },
                  "completed": {
                    "summary": "Completed task",
                    "value": {
                      "id": "video_task_id",
                      "status": "completed",
                      "outputs": [
                        "https://storage.example/output/video_task_id.mp4"
                      ]
                    }
                  },
                  "failed": {
                    "summary": "Failed task",
                    "value": {
                      "id": "video_task_id",
                      "status": "failed",
                      "outputs": [],
                      "error": {
                        "message": "Upstream generation failed."
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          }
        }
      }
    },
    "/videos/{id}/content": {
      "get": {
        "operationId": "downloadVideoContent",
        "summary": "Download video content",
        "description": "Download completed video content as binary MP4 bytes or follow a redirect to the output URL for Atlas-backed tasks. If the task is not completed yet, the endpoint returns an error.",
        "parameters": [
          {
            "$ref": "#/components/parameters/VideoTaskId"
          }
        ],
        "responses": {
          "200": {
            "description": "Binary MP4 video content",
            "content": {
              "video/mp4": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "302": {
            "description": "Redirect to the completed output URL.",
            "headers": {
              "Location": {
                "description": "Completed video output URL.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              }
            }
          },
          "307": {
            "description": "Temporary redirect to the completed output URL.",
            "headers": {
              "Location": {
                "description": "Completed video output URL.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          }
        }
      }
    },
    "/images/generations": {
      "post": {
        "operationId": "createImageGeneration",
        "summary": "Generate image",
        "description": "Generate a new image from a text prompt. Unsupported fields are rejected.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImageGenerationRequest"
              },
              "examples": {
                "productPhoto": {
                  "summary": "Product photo",
                  "value": {
                    "model": "gpt-image-2",
                    "prompt": "A clean product photo of a matte black desk lamp on a white desk",
                    "size": "1024x1024",
                    "n": 1
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Generated image response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImageResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/InsufficientBalance"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamInvalidResponse"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          }
        }
      }
    },
    "/images/edits": {
      "post": {
        "operationId": "createImageEdit",
        "summary": "Edit image",
        "description": "Edit or inpaint an image from one or more reference images. Unsupported fields and unsupported file field names are rejected.",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/ImageEditRequest"
              },
              "encoding": {
                "image": {
                  "contentType": "image/png, image/jpeg, image/webp"
                }
              },
              "examples": {
                "roomEdit": {
                  "summary": "Room edit",
                  "value": {
                    "model": "gpt-image-2",
                    "prompt": "Replace the empty wall area with a framed abstract painting",
                    "size": "1024x1024"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Edited image response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImageResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/InsufficientBalance"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamInvalidResponse"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer"
      }
    },
    "parameters": {
      "VideoTaskId": {
        "name": "id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "Video task ID returned by POST /videos."
      },
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "schema": {
          "type": "string"
        },
        "description": "Client-generated idempotency key for safe retries of the same logical video task creation request."
      }
    },
    "schemas": {
      "ModelListResponse": {
        "type": "object",
        "required": [
          "object",
          "data"
        ],
        "properties": {
          "object": {
            "type": "string",
            "description": "Response container type.",
            "example": "list"
          },
          "data": {
            "type": "array",
            "description": "Live model records.",
            "items": {
              "$ref": "#/components/schemas/ModelRecord"
            }
          }
        }
      },
      "ModelRecord": {
        "type": "object",
        "additionalProperties": true,
        "required": [
          "id",
          "object"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Model ID to pass as model.",
            "example": "seedance-2.0-mini"
          },
          "object": {
            "type": "string",
            "example": "model"
          },
          "created": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Creation timestamp when available."
          },
          "owned_by": {
            "type": [
              "string",
              "null"
            ]
          },
          "tier": {
            "type": [
              "string",
              "null"
            ],
            "description": "Access tier when applicable."
          },
          "model_type": {
            "type": "string",
            "description": "Broad model family or endpoint type. Video-capable models use video.",
            "example": "video"
          },
          "pricing_mode": {
            "type": "string",
            "description": "Pricing calculation mode. Token-priced models use token; video models use second with route-level prices when available."
          },
          "pricing": {
            "$ref": "#/components/schemas/ModelPricing"
          },
          "modalities": {
            "$ref": "#/components/schemas/ModelModalities"
          },
          "context_window": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": true
          },
          "usage_based_only": {
            "type": "boolean"
          },
          "stream": {
            "type": "boolean"
          },
          "json_mode": {
            "type": "boolean"
          },
          "reasoning": {
            "type": "boolean"
          },
          "tools_calling": {
            "type": "boolean"
          },
          "capabilities": {
            "$ref": "#/components/schemas/ModelCapabilities"
          }
        }
      },
      "ModelPricing": {
        "type": "object",
        "additionalProperties": true,
        "properties": {
          "input": {
            "type": "number",
            "description": "Input-token price for token-priced models."
          },
          "output": {
            "type": "number",
            "description": "Output-token price for token-priced models."
          },
          "price": {
            "type": "number",
            "description": "Compatible, base, or minimum per-unit price for non-token pricing modes. Video models can use route-level prices as the source of truth.",
            "example": 0.01
          },
          "route_prices_usd_per_second": {
            "type": "array",
            "description": "Route-level public USD prices per generated second for video models.",
            "items": {
              "type": "object",
              "additionalProperties": true,
              "properties": {
                "route": {
                  "type": "string",
                  "description": "Route or model route identifier.",
                  "example": "seedance-2.0-mini"
                },
                "request_type": {
                  "type": "string",
                  "description": "Video request type for this route price.",
                  "example": "text-to-video"
                },
                "public_price_usd_per_second": {
                  "type": "number",
                  "description": "Public USD price per generated second for the selected route.",
                  "example": 0.01
                }
              }
            }
          },
          "minimum_request_price_usd": {
            "type": "number"
          },
          "minimum_cache_tokens": {
            "type": "number"
          },
          "currency": {
            "type": "string",
            "example": "USD"
          },
          "unit": {
            "type": "string",
            "example": "second"
          }
        }
      },
      "ModelModalities": {
        "type": "object",
        "properties": {
          "input": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "example": [
              "text",
              "image"
            ]
          },
          "output": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "example": [
              "video"
            ]
          }
        }
      },
      "ModelCapabilities": {
        "type": "object",
        "additionalProperties": true,
        "properties": {
          "video_generation": {
            "type": "boolean",
            "description": "Whether the model can generate video."
          },
          "video_async": {
            "type": "boolean",
            "description": "Whether video generation is asynchronous."
          },
          "supported_seconds": {
            "type": "array",
            "description": "Allowed seconds values for video generation.",
            "items": {
              "type": "integer"
            },
            "example": [
              5,
              8
            ]
          },
          "supported_sizes": {
            "type": "array",
            "description": "Allowed output sizes for video generation.",
            "items": {
              "type": "string"
            },
            "example": [
              "480p",
              "720p",
              "1080p"
            ]
          },
          "max_reference_images": {
            "type": "integer",
            "description": "Maximum number of uploaded reference images."
          },
          "max_reference_image_bytes": {
            "type": "integer",
            "description": "Maximum bytes per uploaded reference image.",
            "example": 8388608
          },
          "requires_reference_image": {
            "type": "boolean",
            "description": "Whether at least one input_reference file is required."
          },
          "atlascloud_video": {
            "type": "boolean",
            "description": "Whether the video model is backed by Atlas routes."
          },
          "atlascloud_routes": {
            "type": "array",
            "description": "Atlas route metadata for video generation.",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          }
        }
      },
      "VideoCreateJsonRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "model",
          "request_type",
          "prompt"
        ],
        "anyOf": [
          {
            "required": [
              "duration"
            ]
          },
          {
            "required": [
              "seconds"
            ]
          }
        ],
        "properties": {
          "model": {
            "type": "string",
            "description": "Video model ID.",
            "example": "seedance-2.0-mini"
          },
          "request_type": {
            "type": "string",
            "description": "Video request type, such as text-to-video or image-to-video.",
            "enum": [
              "text-to-video",
              "image-to-video"
            ],
            "example": "text-to-video"
          },
          "prompt": {
            "type": "string",
            "description": "Text instruction for the video.",
            "example": "Waves crashing on rocks, cinematic slow motion"
          },
          "duration": {
            "type": "number",
            "description": "Requested duration in seconds. Must be listed in the selected model's capabilities.supported_seconds.",
            "example": 8
          },
          "seconds": {
            "type": [
              "number",
              "string"
            ],
            "description": "Compatibility alias for duration.",
            "example": 8
          },
          "resolution": {
            "type": "string",
            "description": "Requested output resolution. Must be listed in the selected model's capabilities.supported_sizes when provided.",
            "example": "720p"
          },
          "size": {
            "type": "string",
            "description": "Compatibility alias for resolution. Legacy models can expose exact sizes such as 1280x720.",
            "example": "1280x720"
          },
          "client_request_id": {
            "type": "string",
            "description": "Client-generated request ID for tracing and retry correlation.",
            "example": "video-demo-001"
          }
        }
      },
      "VideoCreateMultipartRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "model",
          "request_type",
          "prompt",
          "input_reference"
        ],
        "anyOf": [
          {
            "required": [
              "duration"
            ]
          },
          {
            "required": [
              "seconds"
            ]
          }
        ],
        "properties": {
          "model": {
            "type": "string",
            "description": "Video model ID.",
            "example": "seedance-2.0-mini"
          },
          "request_type": {
            "type": "string",
            "description": "Video request type, such as text-to-video or image-to-video.",
            "enum": [
              "text-to-video",
              "image-to-video"
            ],
            "example": "image-to-video"
          },
          "prompt": {
            "type": "string",
            "description": "Text instruction for the video.",
            "example": "Animate this first frame"
          },
          "duration": {
            "type": "number",
            "description": "Requested duration in seconds. Must be listed in the selected model's capabilities.supported_seconds.",
            "example": 8
          },
          "seconds": {
            "type": [
              "number",
              "string"
            ],
            "description": "Compatibility alias for duration.",
            "example": 8
          },
          "resolution": {
            "type": "string",
            "description": "Requested output resolution. Must be listed in the selected model's capabilities.supported_sizes when provided.",
            "example": "720p"
          },
          "size": {
            "type": "string",
            "description": "Compatibility alias for resolution. Legacy models can expose exact sizes such as 1280x720.",
            "example": "1280x720"
          },
          "client_request_id": {
            "type": "string",
            "description": "Client-generated request ID for tracing and retry correlation.",
            "example": "image-video-demo-001"
          },
          "input_reference": {
            "type": "array",
            "description": "Reference images. Send each file with the repeated field name input_reference.",
            "minItems": 1,
            "items": {
              "type": "string",
              "format": "binary"
            }
          }
        }
      },
      "VideoTaskResponse": {
        "type": "object",
        "required": [
          "id",
          "status"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Video task ID.",
            "example": "video_task_id"
          },
          "status": {
            "type": "string",
            "description": "Video task status.",
            "enum": [
              "queued",
              "in_progress",
              "completed",
              "failed",
              "timeout"
            ],
            "example": "queued"
          },
          "outputs": {
            "type": "array",
            "description": "Completed output URLs. Empty or omitted until the task is completed.",
            "items": {
              "type": "string",
              "format": "uri"
            },
            "example": [
              "https://storage.example/output/video_task_id.mp4"
            ]
          },
          "error": {
            "type": "object",
            "description": "Task error details for failed or timed-out tasks.",
            "required": [
              "message"
            ],
            "properties": {
              "message": {
                "type": "string",
                "example": "Upstream generation failed."
              }
            }
          }
        }
      },
      "ImageGenerationRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "model",
          "prompt"
        ],
        "properties": {
          "model": {
            "type": "string",
            "description": "Image model ID.",
            "example": "gpt-image-2"
          },
          "prompt": {
            "type": "string",
            "description": "Text instruction for the image."
          },
          "size": {
            "type": "string",
            "description": "Requested output size. Support depends on the selected model.",
            "example": "1024x1024"
          },
          "n": {
            "type": "integer",
            "description": "Number of images to generate. Only 1 is supported.",
            "enum": [
              1
            ],
            "default": 1
          }
        }
      },
      "ImageEditRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "model",
          "prompt",
          "image"
        ],
        "properties": {
          "model": {
            "type": "string",
            "description": "Image model ID.",
            "example": "gpt-image-2"
          },
          "prompt": {
            "type": "string",
            "description": "Edit or inpaint instruction."
          },
          "size": {
            "type": "string",
            "description": "Requested output size. Support depends on the selected model.",
            "example": "1024x1024"
          },
          "image": {
            "type": "array",
            "description": "Reference images. Send each file with the repeated field name image.",
            "minItems": 1,
            "maxItems": 3,
            "items": {
              "type": "string",
              "format": "binary"
            }
          }
        }
      },
      "ImageResponse": {
        "type": "object",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "type": "array",
            "minItems": 1,
            "maxItems": 1,
            "items": {
              "$ref": "#/components/schemas/ImageData"
            }
          },
          "usage": {
            "$ref": "#/components/schemas/ImageUsage"
          }
        }
      },
      "ImageData": {
        "type": "object",
        "required": [
          "b64_json"
        ],
        "properties": {
          "b64_json": {
            "type": "string",
            "description": "Generated or edited image bytes encoded as base64."
          }
        }
      },
      "ImageUsage": {
        "type": "object",
        "properties": {
          "cost_usd": {
            "type": "string",
            "description": "Decimal USD string for the billed request when cost is available.",
            "example": "0.01200000"
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "$ref": "#/components/schemas/ErrorObject"
          }
        }
      },
      "ErrorObject": {
        "type": "object",
        "required": [
          "message",
          "type",
          "code"
        ],
        "properties": {
          "message": {
            "type": "string"
          },
          "type": {
            "type": "string"
          },
          "param": {
            "type": [
              "string",
              "null"
            ]
          },
          "code": {
            "type": "string"
          }
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Invalid gateway request or upstream rejected the request.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Missing or invalid LLM7 token.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "InsufficientBalance": {
        "description": "No available balance or allowance.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "PayloadTooLarge": {
        "description": "Request body or reference image is too large.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "RateLimited": {
        "description": "Gateway or upstream rate limit.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "UpstreamInvalidResponse": {
        "description": "Upstream success response did not match the endpoint contract.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "UpstreamUnavailable": {
        "description": "Upstream provider is temporarily unavailable.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      }
    }
  }
}
