{
  "openapi": "3.1.0",
  "info": {
    "title": "Revana API",
    "version": "2026-10-19",
    "description": "One API key for image and video models. Prepaid credits, 100 credits = $1; only the route that succeeds is charged. Every model in /data/models.json takes the same request shape: `input` is SeedanceInput for seedance-2.5 and ModelInput for the others, whose allowed values, defaults and prices are listed per model in /data/models.json. An unknown model id answers 422 model_not_available; a model whose routes are all down at the moment, 503 model_unavailable."
  },
  "servers": [
    {
      "url": "https://api.revana.si"
    }
  ],
  "security": [
    {
      "bearer": []
    }
  ],
  "paths": {
    "/v1/generations": {
      "post": {
        "operationId": "createGeneration",
        "summary": "Submit a generation",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "description": "Resending the same key and body returns the same generation instead of starting another. The same key with a different body is 409 idempotency_conflict."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GenerationRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Generation"
                }
              }
            }
          },
          "200": {
            "description": "An Idempotency-Key replay: the generation it created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Generation"
                }
              }
            }
          },
          "400": {
            "description": "Malformed request. Codes: invalid_request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key. Codes: unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "The available balance does not cover reserved_usd. Codes: insufficient_credits.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The account is paused, or the key cannot generate yet. Codes: account_disabled, generation_not_enabled.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Idempotency-Key reused with a different body. Codes: idempotency_conflict.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Body over 1 MB. Codes: body_too_large.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The input cannot run as asked. Nothing is charged. Codes: invalid_input, max_cost_exceeded, model_not_available.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Over the per-second burst guard (honour Retry-After), or too many generations in progress. Codes: rate_limited, concurrency_limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Busy, or no route up. Retry after Retry-After with the same Idempotency-Key. Codes: busy, model_unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Server error. Safe to retry with the same Idempotency-Key. Codes: server_error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/generations/{id}": {
      "get": {
        "operationId": "getGeneration",
        "summary": "Get a generation",
        "parameters": [
          {
            "$ref": "#/components/parameters/id"
          }
        ],
        "responses": {
          "200": {
            "description": "The generation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Generation"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key. Codes: unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No generation with this id on your account. Codes: not_found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Over the per-second burst guard. Codes: rate_limited.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/generations/{id}/content": {
      "get": {
        "operationId": "getGenerationContent",
        "summary": "Download the result (the first file)",
        "parameters": [
          {
            "$ref": "#/components/parameters/id"
          }
        ],
        "responses": {
          "302": {
            "description": "A redirect to a short-lived file URL."
          },
          "200": {
            "description": "The file: a video for video models, a picture for picture models.",
            "content": {
              "video/mp4": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/jpeg": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/webp": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "404": {
            "description": "No generation with this id on your account. Codes: not_found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Not succeeded yet. Codes: not_ready.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/generations/{id}/content/{n}": {
      "get": {
        "operationId": "getGenerationContentN",
        "summary": "Download file n of a result with several files",
        "parameters": [
          {
            "$ref": "#/components/parameters/id"
          },
          {
            "name": "n",
            "in": "path",
            "required": true,
            "description": "2 or more: the position of the file in output.urls.",
            "schema": {
              "type": "integer",
              "minimum": 2,
              "maximum": 99
            }
          }
        ],
        "responses": {
          "302": {
            "description": "A redirect to a short-lived file URL."
          },
          "200": {
            "description": "The file: a video for video models, a picture for picture models.",
            "content": {
              "video/mp4": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/jpeg": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/webp": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "404": {
            "description": "No generation with this id on your account, or it has fewer files. Codes: not_found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Not succeeded yet. Codes: not_ready.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/models": {
      "get": {
        "operationId": "listModels",
        "summary": "List the models you can generate with now",
        "security": [],
        "description": "No key needed. Every model /v1/generations accepts at this moment, with its tasks, options and price (the same fields as /data/models.json). A model missing here answers 422 model_not_available.",
        "responses": {
          "200": {
            "description": "The models.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "const": "list"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "required": [
                          "id",
                          "object"
                        ],
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "object": {
                            "const": "model"
                          },
                          "name": {
                            "type": "string"
                          },
                          "maker": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "kind": {
                            "type": "string",
                            "enum": [
                              "image",
                              "video",
                              "audio"
                            ]
                          },
                          "tasks": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "options": {
                            "type": "object"
                          },
                          "price": {
                            "type": "object"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/balance": {
      "get": {
        "operationId": "getBalance",
        "summary": "What the key's account can spend",
        "description": "available is what a new generation can reserve; held is reserved by generations still running; balance is both. Credits are 100 to the dollar, rounded so available never reads higher than it is.",
        "responses": {
          "200": {
            "description": "The balance.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "object",
                    "currency",
                    "available_usd",
                    "held_usd",
                    "balance_usd",
                    "available_credits",
                    "held_credits",
                    "balance_credits"
                  ],
                  "properties": {
                    "object": {
                      "const": "balance"
                    },
                    "currency": {
                      "const": "usd"
                    },
                    "available_usd": {
                      "type": "number"
                    },
                    "held_usd": {
                      "type": "number"
                    },
                    "balance_usd": {
                      "type": "number"
                    },
                    "spent_usd": {
                      "type": "number"
                    },
                    "available_credits": {
                      "type": "integer"
                    },
                    "held_credits": {
                      "type": "integer"
                    },
                    "balance_credits": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/uploads": {
      "post": {
        "operationId": "createUpload",
        "summary": "A link for a local reference file",
        "description": "Answers a presigned upload_url: PUT the file's bytes there within an hour with exactly upload_headers (its content type and length are signed). Then pass url, an api.revana.si link good for 14 days that redirects to the file, as a reference to /v1/generations. image/* up to 30 MB, video/* up to 50 MB, audio/* up to 15 MB. Free.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "content_type",
                  "bytes"
                ],
                "properties": {
                  "content_type": {
                    "type": "string",
                    "examples": [
                      "image/png"
                    ]
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": 1
                  },
                  "filename": {
                    "type": "string",
                    "maxLength": 200
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The upload.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "id",
                    "object",
                    "url",
                    "expires_at",
                    "upload_url",
                    "upload_method",
                    "upload_headers",
                    "upload_expires_at",
                    "content_type",
                    "bytes",
                    "filename"
                  ],
                  "properties": {
                    "id": {
                      "type": "string",
                      "pattern": "^upl_"
                    },
                    "object": {
                      "const": "upload"
                    },
                    "url": {
                      "type": "string",
                      "format": "uri",
                      "description": "https://api.revana.si/v1/uploads/…: no key needed, answers a redirect to the file until expires_at (14 days)."
                    },
                    "expires_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "upload_url": {
                      "type": "string",
                      "format": "uri"
                    },
                    "upload_method": {
                      "const": "PUT"
                    },
                    "upload_headers": {
                      "type": "object",
                      "additionalProperties": {
                        "type": "string"
                      }
                    },
                    "upload_expires_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "content_type": {
                      "type": "string"
                    },
                    "bytes": {
                      "type": "integer"
                    },
                    "filename": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Not an image, video or audio type, or a bad body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Larger than the reference limit for its kind (too_large).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Uploads are not available (uploads_unavailable).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/queue/revana/{model_id}": {
      "post": {
        "operationId": "submitQueueRequest",
        "summary": "Submit model input directly to the asynchronous queue",
        "description": "Same billing and admission as generations. See https://revana.si/queue.md for fal aliases and compatibility limits. Callback URLs are public HTTPS on port 443; callback notifications are unsigned, so verify by authenticated result retrieval.",
        "security": [
          {
            "bearer": []
          },
          {
            "queueKey": []
          }
        ],
        "parameters": [
          {
            "name": "model_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An id returned by GET /v1/models."
          },
          {
            "name": "fal_webhook",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "schema": {
              "type": "string",
              "maxLength": 200
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Raw model input fields, plus optional max_cost_usd and max_wait_s. See the model catalog."
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "request_id",
                    "status",
                    "status_url",
                    "response_url"
                  ],
                  "properties": {
                    "request_id": {
                      "type": "string"
                    },
                    "gateway_request_id": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "IN_QUEUE",
                        "IN_PROGRESS",
                        "COMPLETED"
                      ]
                    },
                    "status_url": {
                      "type": "string"
                    },
                    "response_url": {
                      "type": "string"
                    },
                    "cancel_url": {
                      "type": "string",
                      "description": "Cancellation is unsupported (405)."
                    },
                    "error": {
                      "type": "string"
                    },
                    "error_type": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "200": {
            "description": "Idempotent replay",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "request_id",
                    "status",
                    "status_url",
                    "response_url"
                  ],
                  "properties": {
                    "request_id": {
                      "type": "string"
                    },
                    "gateway_request_id": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "IN_QUEUE",
                        "IN_PROGRESS",
                        "COMPLETED"
                      ]
                    },
                    "status_url": {
                      "type": "string"
                    },
                    "response_url": {
                      "type": "string"
                    },
                    "cancel_url": {
                      "type": "string",
                      "description": "Cancellation is unsupported (405)."
                    },
                    "error": {
                      "type": "string"
                    },
                    "error_type": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Key reused for different input, endpoint or webhook"
          },
          "422": {
            "description": "Unsupported input or unsafe callback URL"
          },
          "503": {
            "description": "Service or callback worker unavailable"
          }
        }
      }
    },
    "/v1/queue/revana/{model_id}/requests/{request_id}/status": {
      "get": {
        "operationId": "getQueueStatus",
        "summary": "Get queue status",
        "security": [
          {
            "bearer": []
          },
          {
            "queueKey": []
          }
        ],
        "parameters": [
          {
            "name": "model_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An id returned by GET /v1/models."
          },
          {
            "name": "request_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Queue state; failures are COMPLETED with error",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "request_id",
                    "status",
                    "status_url",
                    "response_url"
                  ],
                  "properties": {
                    "request_id": {
                      "type": "string"
                    },
                    "gateway_request_id": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "IN_QUEUE",
                        "IN_PROGRESS",
                        "COMPLETED"
                      ]
                    },
                    "status_url": {
                      "type": "string"
                    },
                    "response_url": {
                      "type": "string"
                    },
                    "cancel_url": {
                      "type": "string",
                      "description": "Cancellation is unsupported (405)."
                    },
                    "error": {
                      "type": "string"
                    },
                    "error_type": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No request owned by this account at this endpoint"
          }
        }
      }
    },
    "/v1/queue/revana/{model_id}/requests/{request_id}": {
      "get": {
        "operationId": "getQueueResult",
        "summary": "Get final model output",
        "security": [
          {
            "bearer": []
          },
          {
            "queueKey": []
          }
        ],
        "parameters": [
          {
            "name": "model_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An id returned by GET /v1/models."
          },
          {
            "name": "request_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Image images[], video video{}, or audio audio{} and audios[]; file URLs require this account API key",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "409": {
            "description": "Still processing"
          },
          "422": {
            "description": "Generation failed"
          },
          "404": {
            "description": "No request owned by this account at this endpoint"
          }
        }
      }
    },
    "/v1/queue/revana/{model_id}/requests/{request_id}/content": {
      "get": {
        "operationId": "getQueueContent",
        "summary": "Download the first output",
        "security": [
          {
            "bearer": []
          },
          {
            "queueKey": []
          }
        ],
        "parameters": [
          {
            "name": "model_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An id returned by GET /v1/models."
          },
          {
            "name": "request_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Media bytes"
          },
          "302": {
            "description": "Short-lived storage redirect after authentication"
          },
          "409": {
            "description": "Not ready"
          },
          "404": {
            "description": "No request owned by this account at this endpoint"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearer": {
        "type": "http",
        "scheme": "bearer",
        "description": "An API key from https://revana.si/dashboard."
      },
      "queueKey": {
        "type": "apiKey",
        "in": "header",
        "name": "Authorization",
        "description": "Queue paths accept Key sr_live_\u2026 or Bearer sr_live_\u2026."
      }
    },
    "parameters": {
      "id": {
        "name": "id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "pattern": "^[\\w-]{1,80}$"
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            }
          }
        }
      },
      "GenerationRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "model",
          "input"
        ],
        "properties": {
          "model": {
            "type": "string",
            "description": "A model id from /data/models.json.",
            "examples": [
              "seedance-2.5"
            ]
          },
          "input": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/SeedanceInput"
              },
              {
                "$ref": "#/components/schemas/NemesisInput"
              },
              {
                "$ref": "#/components/schemas/ModelInput"
              }
            ],
            "description": "SeedanceInput for seedance-2.5; NemesisInput for nemesis and nemesis-lite (a 2-15 s clip, rendered on Wan 3.0 at its rate plus $0.02 a second, per second of clip in plus video out); ModelInput for every other model. Unknown fields, and values the model does not offer, are refused with 422 invalid_input before anything is charged."
          },
          "max_cost_usd": {
            "type": "number",
            "exclusiveMinimum": 0,
            "maximum": 100,
            "default": 100,
            "description": "The most this generation may cost. Routes above it are skipped."
          },
          "max_wait_s": {
            "type": "integer",
            "minimum": 1,
            "maximum": 86400,
            "description": "Routes expected to take longer than this many seconds are skipped, and once it has passed no new route is tried. A route already running may finish (up to 40 minutes) and is charged if it delivers."
          }
        }
      },
      "SeedanceInput": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "prompt"
        ],
        "description": "Input for seedance-2.5.",
        "properties": {
          "prompt": {
            "type": "string",
            "minLength": 1,
            "maxLength": 30000
          },
          "resolution": {
            "enum": [
              "480p",
              "720p",
              "1080p"
            ],
            "default": "720p"
          },
          "duration": {
            "type": "integer",
            "minimum": 4,
            "maximum": 30,
            "default": 5,
            "description": "Seconds. Not with video_url."
          },
          "aspect_ratio": {
            "enum": [
              "16:9",
              "9:16",
              "1:1",
              "4:3",
              "3:4",
              "21:9",
              "adaptive"
            ],
            "default": "16:9"
          },
          "audio": {
            "type": "boolean",
            "default": false
          },
          "image_url": {
            "type": "string",
            "format": "uri",
            "maxLength": 4096,
            "description": "Exact first frame. Not with reference media."
          },
          "end_image_url": {
            "type": "string",
            "format": "uri",
            "maxLength": 4096,
            "description": "Last frame. Needs image_url."
          },
          "image_urls": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uri",
              "maxLength": 4096,
              "description": "A public https URL that downloads directly."
            },
            "minItems": 1,
            "maxItems": 30,
            "description": "Reference images."
          },
          "video_url": {
            "type": "string",
            "format": "uri",
            "maxLength": 4096,
            "description": "A 4-30 s clip to edit; the result keeps its length."
          },
          "video_urls": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uri",
              "maxLength": 4096,
              "description": "A public https URL that downloads directly."
            },
            "minItems": 1,
            "maxItems": 10,
            "description": "Reference clips, 30 s in all."
          },
          "audio_urls": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uri",
              "maxLength": 4096,
              "description": "A public https URL that downloads directly."
            },
            "minItems": 1,
            "maxItems": 10,
            "description": "Reference sound, 30 s in all."
          }
        }
      },
      "NemesisInput": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "video_url",
          "image_urls"
        ],
        "description": "Input for nemesis: restages a clip with your people, products and places (its movement, timing and camera, played by the references). Priced at a Seedance 2.5 edit's rate plus $0.02 a second, per second of the clip in plus the video out. The result keeps the clip's length and shape.",
        "properties": {
          "video_url": {
            "type": "string",
            "format": "uri",
            "maxLength": 4096,
            "description": "The 4-30 s clip to restage."
          },
          "image_urls": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uri",
              "maxLength": 4096
            },
            "minItems": 1,
            "maxItems": 8,
            "description": "Reference pictures."
          },
          "roles": {
            "type": "array",
            "items": {
              "enum": [
                "person",
                "product",
                "location",
                "look"
              ]
            },
            "minItems": 1,
            "maxItems": 8,
            "description": "One per picture, in order. Default: every picture is a person."
          },
          "target_frame": {
            "type": "boolean",
            "description": "Before the render, the clip's first frame is redrawn with the change already made, in the same pose, size and light, and sent as the first reference, so hair, face and clothes stay true to the pictures. Default: true for nemesis, false for nemesis-lite. Free."
          },
          "guide": {
            "enum": [
              "people",
              "scene",
              "clip"
            ],
            "description": "nemesis-lite only (nemesis always edits the clip itself). clip (default with a target frame): follows the clip's own picture. people (default without one): the people are replaced and the background kept (a clip with nobody in it is refused, not charged). scene: everything seen comes from the references and prompt."
          },
          "sound": {
            "enum": [
              "none",
              "original"
            ],
            "description": "original (default on nemesis): the clip's own sound is put back on the result. none (default on nemesis-lite): a silent result."
          },
          "face_mesh": {
            "type": "boolean",
            "description": "Traces every face in the clip so the new face keeps its expressions, eyes and lips; never shown in the result. nemesis-lite only. Default: true with guide people, false with scene and clip."
          },
          "resolution": {
            "enum": [
              "480p",
              "720p",
              "1080p"
            ],
            "default": "720p"
          },
          "prompt": {
            "type": "string",
            "maxLength": 5000,
            "description": "Optional direction."
          }
        }
      },
      "Generation": {
        "type": "object",
        "required": [
          "id",
          "object",
          "model",
          "status",
          "output",
          "quoted_usd",
          "cost_usd",
          "attempts",
          "error",
          "created_at",
          "completed_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "examples": [
              "gen_3f9a1c0d2b7e4a5f6c81"
            ]
          },
          "object": {
            "const": "generation"
          },
          "model": {
            "type": "string"
          },
          "status": {
            "enum": [
              "queued",
              "running",
              "succeeded",
              "failed"
            ]
          },
          "message": {
            "type": "string",
            "description": "Only while a result is being confirmed with a provider."
          },
          "output": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "urls": {
                "type": "array",
                "items": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "duration_s": {
                "type": "number"
              },
              "width": {
                "type": "integer"
              },
              "height": {
                "type": "integer"
              },
              "has_audio": {
                "type": "boolean"
              }
            },
            "description": "Null until succeeded. urls lists every file (a picture model can return several: /content, /content/2, ...). Pictures carry width and height; videos also duration_s and has_audio."
          },
          "quoted_usd": {
            "type": "number",
            "description": "The price on the route tried first. If a dearer backup route makes it instead, the charge is that route's price, up to reserved_usd."
          },
          "reserved_usd": {
            "type": [
              "number",
              "null"
            ],
            "description": "Held from the balance while it runs: the dearest route that may run, so the most it can cost. Set max_cost_usd to quoted_usd to skip dearer backups."
          },
          "cost_usd": {
            "type": [
              "number",
              "null"
            ],
            "description": "The charge once succeeded, 0 once failed, else null."
          },
          "attempts": {
            "type": "integer"
          },
          "error": {
            "type": [
              "object",
              "null"
            ],
            "description": "When failed. message is written to show the person who asked; retryable says whether the same request can work later.",
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "content_policy",
                  "invalid_input",
                  "model_declined",
                  "reference_changed",
                  "max_cost_exceeded",
                  "model_busy",
                  "model_unavailable",
                  "timeout",
                  "all_routes_failed",
                  "review_required",
                  "processing_failed"
                ]
              },
              "message": {
                "type": "string"
              },
              "retryable": {
                "type": "boolean",
                "description": "true: send the same request again later. false: the request has to change."
              },
              "reason": {
                "type": "string",
                "enum": [
                  "sexual",
                  "minors",
                  "copyright",
                  "real_person",
                  "other"
                ],
                "description": "Only on content_policy: the rule the model cited."
              }
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "completed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "ModelInput": {
        "type": "object",
        "additionalProperties": false,
        "description": "The input of every model other than seedance-2.5. Which fields and values a model takes, and its defaults, are in /data/models.json (options, tasks, price).",
        "properties": {
          "prompt": {
            "type": "string",
            "minLength": 1,
            "maxLength": 30000,
            "description": "What to generate. Required unless the model only transforms media (an upscaler)."
          },
          "negative_prompt": {
            "type": "string",
            "maxLength": 5000,
            "description": "What to avoid, on models that take it."
          },
          "image_url": {
            "type": "string",
            "format": "uri",
            "maxLength": 4096,
            "description": "The start frame (image to video) or the picture to edit (image to image)."
          },
          "end_image_url": {
            "type": "string",
            "format": "uri",
            "maxLength": 4096,
            "description": "The last frame, on models with first and last frame. Needs image_url."
          },
          "image_urls": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uri",
              "maxLength": 4096
            },
            "minItems": 1,
            "maxItems": 30,
            "description": "Reference pictures, up to the model's max_input_images."
          },
          "video_url": {
            "type": "string",
            "format": "uri",
            "maxLength": 4096,
            "description": "A clip to transform or extend, on models that take one. Its length is measured and may be billed."
          },
          "audio_url": {
            "type": "string",
            "format": "uri",
            "maxLength": 4096,
            "description": "A sound to drive the video (talking avatars, lip sync)."
          },
          "resolution": {
            "type": "string",
            "description": "One of the model's resolutions, e.g. 720p, 1080p, 1K, 2K, 4K."
          },
          "aspect_ratio": {
            "type": "string",
            "description": "One of the model's aspect ratios, e.g. 16:9, 9:16, 1:1."
          },
          "duration": {
            "type": "integer",
            "minimum": 1,
            "maximum": 300,
            "description": "Video length in seconds: one of the model's durations. Per-second models are billed for it."
          },
          "audio": {
            "type": "boolean",
            "description": "Generate sound, on models that offer it. Changes the price on some models."
          },
          "quality": {
            "type": "string",
            "description": "A quality tier, on models that price by one (e.g. low, medium, high)."
          },
          "seed": {
            "type": "integer",
            "minimum": 0,
            "maximum": 4294967295,
            "description": "A seed, on models that take one."
          }
        }
      }
    }
  }
}
