# Documentation This file contains the complete documentation in markdown format for LLM consumption. --- ## One API for image, video, audio, 3D, and text - **URL:** https://runware.ai/docs/models-api/introduction - **Description:** Hundreds of models on Runware are addressable by their model identifier and reachable through a single call. ## Introduction Runware exposes a **single endpoint** for image, video, audio, 3D, and text generation. Models are addressed by their **model identifier**, and the same request shape works across every modality. ## One shape, every modality **Image Request**: ```json { "taskType": "imageInference", "taskUUID": "a770f077-f413-47de-9dac-be0b26a35da6", "model": "xai:grok-imagine@image-quality", "positivePrompt": "A golden retriever on a park bench, cinematic lighting", "width": 1024, "height": 1024 } ``` **Video Request**: ```json { "taskType": "videoInference", "taskUUID": "a770f077-f413-47de-9dac-be0b26a35da6", "model": "klingai:kling-video@3-4k", "positivePrompt": "Ocean waves crashing on a beach at sunset", "width": 3840, "height": 2160, "duration": 8 } ``` **Audio Request**: ```json { "taskType": "audioInference", "taskUUID": "a770f077-f413-47de-9dac-be0b26a35da6", "model": "fishaudio:s2.1@pro", "speech": { "text": "Welcome to Runware." } } ``` **3D Request**: ```json { "taskType": "3dInference", "taskUUID": "a770f077-f413-47de-9dac-be0b26a35da6", "model": "tripo:v3.1@0", "positivePrompt": "A vintage Polaroid camera, detailed mesh" } ``` **Text Request**: ```json { "taskType": "textInference", "taskUUID": "a770f077-f413-47de-9dac-be0b26a35da6", "model": "anthropic:claude@opus-4.8", "messages": [ { "role": "user", "content": "Write a haiku about the ocean." } ] } ``` **Image Response**: ```json { "taskType": "imageInference", "taskUUID": "a770f077-f413-47de-9dac-be0b26a35da6", "imageUUID": "77da2d99-a6d3-44d9-b8c0-ae9fb06b6200", "imageURL": "https://im.runware.ai/image/os/a14d18/ws/2/ii/77da2d99-a6d3-44d9-b8c0-ae9fb06b6200.jpg", "cost": 0.05 } ``` **Video Response**: ```json { "taskType": "videoInference", "taskUUID": "a770f077-f413-47de-9dac-be0b26a35da6", "videoUUID": "b7db282d-2943-4f12-992f-77df3ad3ec71", "videoURL": "https://vm.runware.ai/video/os/a14d18/ws/2/vi/b7db282d-2943-4f12-992f-77df3ad3ec71.mp4", "cost": 3.36 } ``` **Audio Response**: ```json { "taskType": "audioInference", "taskUUID": "a770f077-f413-47de-9dac-be0b26a35da6", "audioUUID": "f1e2d3c4-b5a6-7890-1234-567890abcdef", "audioURL": "https://am.runware.ai/audio/os/a14d18/ws/2/ai/f1e2d3c4-b5a6-7890-1234-567890abcdef.mp3", "cost": 0.0003 } ``` **3D Response**: ```json { "taskType": "3dInference", "taskUUID": "a770f077-f413-47de-9dac-be0b26a35da6", "outputs": { "files": [ { "uuid": "8c2e6d99-7404-43e6-a8f0-7a3b8d8d9f0c", "url": "https://im.runware.ai/image/os/a14d18/ws/5/ii/8c2e6d99-7404-43e6-a8f0-7a3b8d8d9f0c.glb" } ] }, "cost": 0.3 } ``` **Text Response**: ```json { "taskType": "textInference", "taskUUID": "a770f077-f413-47de-9dac-be0b26a35da6", "text": "Ocean breathes the dawn\nWaves whisper their endless songs\nMoon hangs silent watch", "finishReason": "stop", "cost": 0.0005 } ``` **445 hosted models**. Plus thousands of community and user-uploaded models that run on any of our supported architectures. [Browse all models](https://runware.ai/docs/models) ## Getting started 1. [Sign up](https://runware.ai/signup) for a Runware account. 2. Generate an API key from your dashboard. 3. Read [Authentication](https://runware.ai/docs/models-api/authentication) to learn how to send the key with your requests. 4. Browse [Models](https://runware.ai/docs/models) to find the right one for your use case. > [!NOTE] > The fastest path is the [TypeScript SDK](https://runware.ai/docs/tools/typescript) or [Python SDK](https://runware.ai/docs/tools/python). Both wrap REST and WebSocket transports and validate requests against the model's JSON Schema before sending. For AI agents, see the [MCP integration](https://runware.ai/docs/tools/mcp) and [Skills](https://runware.ai/docs/tools/skills). ## Your first request The same call in cURL, TypeScript, or Python. **TypeScript**: ```typescript import { createClient } from '@runware/sdk' const client = await createClient({ apiKey: process.env.RUNWARE_API_KEY }) await client.connect() const [result] = await client.run({ model: 'xai:grok-imagine@image-quality', positivePrompt: 'A golden retriever on a park bench, cinematic lighting', width: 1024, height: 1024 }) ``` **Python**: ```python import asyncio import os from runware import Runware async def main(): async with Runware(api_key=os.environ["RUNWARE_API_KEY"]) as client: results = await client.run({ "model": "xai:grok-imagine@image-quality", "positivePrompt": "A golden retriever on a park bench, cinematic lighting", "width": 1024, "height": 1024 }) asyncio.run(main()) ``` **cURL**: ```bash curl https://api.runware.ai/v1 \ -H "Authorization: Bearer $RUNWARE_API_KEY" \ -H "Content-Type: application/json" \ -d '[ { "taskType": "imageInference", "taskUUID": "a770f077-f413-47de-9dac-be0b26a35da6", "model": "xai:grok-imagine@image-quality", "positivePrompt": "A golden retriever on a park bench, cinematic lighting", "width": 1024, "height": 1024 } ]' ``` **CLI**: ```bash runware run xai:grok-imagine@image-quality \ positivePrompt="A golden retriever on a park bench, cinematic lighting" \ width=1024 \ height=1024 ``` **JSON**: ```json { "taskType": "imageInference", "taskUUID": "a770f077-f413-47de-9dac-be0b26a35da6", "model": "xai:grok-imagine@image-quality", "positivePrompt": "A golden retriever on a park bench, cinematic lighting", "width": 1024, "height": 1024 } ``` ## Core API concepts ### Task-based architecture Every Runware request is a **task**. Each task is processed independently, so you can send one task or batch many in a single call. Long-running tasks (video, large images) run asynchronously and deliver results as they complete. ### Anatomy of a request Hover any field below to see what it does. The same shape applies to every task type on Runware. ```json [ { "taskType": "imageInference", "taskUUID": "a770f077-f413-47de-9dac-be0b26a35da6", "model": "xai:grok-imagine@image-quality", "positivePrompt": "A golden retriever on a park bench", "width": 1024, "height": 1024 } ] ``` 1. **Array of tasks** — Every request is an array. Send one task or batch many in a single call. 2. **Task object** — Each item in the array is one task. The same object shape works for image, video, audio, 3D, and text. 3. **Task type** — Picks the operation. `imageInference`, `videoInference`, `audioInference`, `3dInference`, `textInference`, plus utilities. 4. **Task UUID** — A UUID v4 you generate. Used to match the response and to trace the task in your dashboard. 5. **Model** — Address any model on the platform by its model identifier: `creator:family@version`. ### Common response structure Every response echoes `taskType` and `taskUUID` from the request, and adds the modality-specific output: `imageURL`, `videoURL`, `audioURL`, mesh files for 3D, or `text` for LLMs. Set **`includeCost: true`** on the request to get a `cost` field back. When a task produces multiple results, each completes independently and arrives in its own message. Output URLs are retained for **7 days** by default. Set `ttl` on the request to change the retention. ```json { "data": [ { "taskType": "imageInference", "taskUUID": "a770f077-f413-47de-9dac-be0b26a35da6", "imageUUID": "77da2d99-a6d3-44d9-b8c0-ae9fb06b6200", "imageURL": "https://im.runware.ai/image/os/a14d18/ws/2/ii/a770f077-f413-47de-9dac-be0b26a35da6.jpg", "cost": 0.0013 }, { "taskType": "videoInference", "taskUUID": "b880f077-e514-58ef-0ebd-ce1c37b46eb7", "videoUUID": "b7db282d-2943-4f12-992f-77df3ad3ec71", "videoURL": "https://vm.runware.ai/video/os/a14d18/ws/2/vi/b7db282d-2943-4f12-992f-77df3ad3ec71.mp4", "cost": 0.18 } ] } ``` --- ## Connection & Authentication - **URL:** https://runware.ai/docs/models-api/authentication - **Description:** Learn how to connect and authenticate with the Runware API using HTTP REST or WebSockets. ## Introduction Every request to the Runware API authenticates with **an API key unique to your account**. You can create a separate key per project or environment, describe it, and **revoke it at any time**. With the teams feature you can also share a key with your team. Sign up on [Runware](https://runware.ai/signup) and open the **API Keys** page, then click Create Key and fill in the details. ## HTTP (REST) We recommend using [WebSockets](https://runware.ai/docs/models-api/authentication#websockets) for a more efficient and faster connection. However, if you prefer to use a **simpler connection** and don't need to keep it open, you can use HTTP REST API. The URL for the API is **`https://api.runware.ai/v1`**. All requests must be made using the `POST` method and the `Content-Type` header must be set to `application/json`. The payload for each request is a **JSON array with one or more objects**. Each object represents a task to be executed by the API. There are two ways in: **the authentication object as the first element of the array**, or the `Authorization` header with `Bearer `. **Payload Auth**: ```bash curl --location 'https://api.runware.ai/v1' \ --header 'Content-Type: application/json' \ --data-raw '[ { "taskType": "authentication", "apiKey": "" }, { "taskType": "imageInference", "taskUUID": "39d7207a-87ef-4c93-8082-1431f9c1dc97", "positivePrompt": "a cat", "width": 512, "height": 512, "model": "civitai:102438@133677", "numberResults": 1 } ]' ``` **Header Auth**: ```bash curl --location 'https://api.runware.ai/v1' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer ' \ --data-raw '[ { "taskType": "imageInference", "taskUUID": "39d7207a-87ef-4c93-8082-1431f9c1dc97", "positivePrompt": "a cat", "width": 512, "height": 512, "model": "civitai:102438@133677", "numberResults": 1 } ]' ``` The API returns a JSON object with a `data` array holding every response object. **Each one carries the `taskType` and the `taskUUID` of the request it answers**, alongside whatever else the task produced. ```json { "data": [ { "taskType": "imageInference", "taskUUID": "39d7207a-87ef-4c93-8082-1431f9c1dc97", "imageUUID": "b7db282d-2943-4f12-992f-77df3ad3ec71", "imageURL": "https://im.runware.ai/image/os/a14d18/ws/2/ii/b7db282d-2943-4f12-992f-77df3ad3ec71.jpg" } ] } ``` **On an error there is no `data` property at all.** The response carries `error` instead, with the message. ## WebSockets We support WebSocket connections as they are **more efficient, faster, and less resource intensive**. We have made our WebSocket connections easy to work with, as each response contains the request ID. So it's possible to easily match **request → response**. The API uses a bidirectional protocol that encodes all messages as **JSON objects**. You can connect through **one of the SDKs** ([TypeScript](https://runware.ai/docs/tools/typescript), [Python](https://runware.ai/docs/tools/python)) or by hand. If you prefer to connect manually (to use another language/technology), the endpoint URL is **`wss://ws-api.runware.ai/v1`**. ### New connections #### Request WebSocket connections are point-to-point, so **there's no need for each request to contain an authentication header**. Instead, the first request **must always** be an authentication request that includes the API key. This way we can identify which subsequent requests are arriving from the same user. **TypeScript**: ```typescript import { createClient } from '@runware/sdk' const client = await createClient({ apiKey: process.env.RUNWARE_API_KEY }) await client.connect() const [result] = await client.run({ taskType: 'authentication', apiKey: '' }) ``` **Python**: ```python import asyncio import os from runware import Runware async def main(): async with Runware(api_key=os.environ["RUNWARE_API_KEY"]) as client: results = await client.run({ "taskType": "authentication", "apiKey": "" }) asyncio.run(main()) ``` **cURL**: ```bash curl https://api.runware.ai/v1 \ -H "Authorization: Bearer $RUNWARE_API_KEY" \ -H "Content-Type: application/json" \ -d '[ { "taskType": "authentication", "apiKey": "" } ]' ``` **CLI**: ```bash runware run undefined apiKey="" ``` **JSON**: ```json { "taskType": "authentication", "apiKey": "" } ``` #### Response The authentication request returns a `connectionSessionUUID`. It is unique to your connection and **is what resumes it after a drop** (more on this later). ```json { "data": [ { "taskType": "authentication", "connectionSessionUUID": "f40c2aeb-f8a7-4af7-a1ab-7594c9bf778f" } ] } ``` In case of error you will receive an object with the error message. ```json { "errors": [ { "code": "invalidApiKey", "message": "Invalid API key. Get one at https://runware.ai/signup", "parameter": "apiKey", "type": "string", "taskType": "authentication" } ] } ``` ### Keeping connection alive The WebSocket connection is kept open for 120 seconds **from the last message exchanged**. If you **don't send any messages for 120 seconds**, the connection will be closed automatically. To keep the connection going, you can send a `ping` message when needed, to which we will reply with a `pong`. #### Request Send a ping task to signal that the connection is still active: **TypeScript**: ```typescript import { createClient } from '@runware/sdk' const client = await createClient({ apiKey: process.env.RUNWARE_API_KEY }) await client.connect() const [result] = await client.run({ taskType: 'ping', ping: true }) ``` **Python**: ```python import asyncio import os from runware import Runware async def main(): async with Runware(api_key=os.environ["RUNWARE_API_KEY"]) as client: results = await client.run({ "taskType": "ping", "ping": True }) asyncio.run(main()) ``` **cURL**: ```bash curl https://api.runware.ai/v1 \ -H "Authorization: Bearer $RUNWARE_API_KEY" \ -H "Content-Type: application/json" \ -d '[ { "taskType": "ping", "ping": true } ]' ``` **CLI**: ```bash runware run undefined ping=true ``` **JSON**: ```json { "taskType": "ping", "ping": true } ``` #### Response The server will respond confirming the connection is alive: ```json { "data": [ { "taskType": "ping", "pong": true } ] } ``` ### Resuming connections If any service, server or network is unresponsive (for instance due to a restart), all the results that could not be delivered **are kept in a buffer memory for 120 seconds**. You can reconnect and have these messages delivered by including the `connectionSessionUUID` parameter in the initial authentication connection request. ```json [ { "taskType": "authentication", "apiKey": "", "connectionSessionUUID": "f40c2aeb-f8a7-4af7-a1ab-7594c9bf778f" } ] ``` This means there is no need to make the same request again, the initial one will be delivered when reconnecting. SDK libraries reconnect **automatically**. --- ## Model Schemas - **URL:** https://runware.ai/docs/models-api/model-schemas - **Description:** One request shape covers every combination of inputs a model accepts. Learn how to build on a model's schema, and how to map it to separate modes. ## Introduction Models take more kinds of input with every generation. A video model used to do one thing, text to video or image to video. Current ones accept reference images, videos and audio **combined in one request**, and each release adds combinations. A product that lists each mode as a separate item has no place for those requests. A first frame is image to video and reference images are reference to video, and **a request that carries both fits neither item**. It needs an item of its own, and so does every combination a new model adds. Runware describes a request by its inputs instead, which is **the shape models are converging on**. A model is one item, and you send it the inputs you have in any combination it accepts. Every request goes to the same endpoint, and a combination the model gains later is already covered by the integration you wrote. That integration is written against **the schema each model publishes**, one JSON document stating which inputs and parameters the model accepts and how they combine. Parameters keep the same name and role across models, so a first frame is always `inputs.frameImages`, whoever made the model, and code that reads one schema reads all of them. The sections below lay out a request and show how to build on the schema, with [MiniMax H3](https://runware.ai/docs/models/minimax-h3) as the example. If you are migrating from a provider that gives each mode its own endpoint, or your product is organized around separate modes and you are keeping them for now, [Working with separate modes](https://runware.ai/docs/models-api/model-schemas#working-with-separate-modes) maps them onto the same schema. > [!NOTE] > Hand this page to your agent > > This page is written to be given to a coding agent. Pass it the [Markdown version](https://runware.ai/docs/models-api/model-schemas.md) along with the model you want to integrate, and it has what it needs to do the work: every step reads from a public JSON document and ends in a request it can validate. ## Where the schema lives The schemas are served as JSON from **two endpoints**. | Endpoint | What it holds | | --- | --- | | `/docs/models/index.json` | Every public model with its id, AIR, status, capabilities, and the URL of its schema. | | `/docs/models//schema.json` | The OpenAPI document for one model. | Start from the index and follow `schema`. ```bash curl -s https://runware.ai/docs/models/index.json | jq '.[] | select(.id == "minimax-h3")' ``` ```json { "id": "minimax-h3", "air": "minimax:h3@0", "name": "MiniMax H3", "status": "live", "capabilities": ["text-to-video", "image-to-video", "video-to-video", "audio-to-video", "edit", "checkpoint", "audio"], "schema": "https://runware.ai/docs/models/minimax-h3/schema.json" } ``` The document that `schema` points at carries everything else an integration reads. | Location | What it holds | | --- | --- | | `info["x-air-id"]` | The value to send as `model`. | | `info["x-status"]` | `live`, `coming-soon` or `deprecated`. A deprecated model also carries `x-deactivates-at` and `x-replaced-by`. | | `info["x-modes"]` | Every combination of inputs the model accepts. | | `info["x-examples"]` | The URL of the model's published examples, each with the request that produced it. | | `info["x-pricing"]` | Rates and measured runs. [Pricing](https://runware.ai/docs/models-api/pricing) explains the shapes. | | `components.schemas.RequestBody` | The request, an array of tasks. `items` is the JSON Schema of one task, called the task schema on this page. | | `components.schemas.ResponseBody` | The response. `properties.data.items` is the JSON Schema of one result. | ## The layers of a request A task is a flat object with a few nested ones, and nearly every parameter sits in **one of four layers**. The layer tells you how much that parameter varies from one model to the next. ```json [ { "taskType": "videoInference", "taskUUID": "a770f077-f413-47de-9dac-be0b26a35da6", "includeCost": true, "model": "minimax:h3@0", "positivePrompt": "The worker lifts the mature wasabi root smoothly into view.", "resolution": "768p", "duration": 8, "inputs": { "frameImages": ["https://assets.runware.ai/assets/inputs/93bc5eb1-8f3d-4c56-9232-06f3da7dce28.jpg"] }, "settings": { "promptExpansion": "disabled" } } ] ``` 1. **API** — General to the API and the same on every model. They control delivery and output, such as `deliveryMethod`, `webhookURL`, `outputFormat` and `numberResults`. 2. **Core** — The main parameters, shared across models under the same name, such as `model`, `positivePrompt`, `width`, `height`, `duration` and `seed`. Each model has the ones that apply to it, with its own ranges. 3. **Inputs** — Every asset the model works from, inside `inputs`. Models differ in which media they take, alone or combined. 4. **Settings** — Finer tuning options, inside `settings`. They are specific to a model, a family or a provider, with no single set common to the whole catalog. A model declares only the parameters it supports, and **anything it does not declare is rejected**. H3 has no `steps` and no `negativePrompt`, so neither appears in its schema and neither can be sent. ## Inputs Every asset the model works from goes in this object. Each key has **one role across the whole catalog**, so the key alone tells you what the model does with the asset. | Input | Role | | --- | --- | | `referenceImages` | Images that guide the result without fixing any frame, such as a subject or a style. | | `referenceVideos` | Clips the model takes as a reference for the subject or the motion. | | `referenceAudios` | Audio the model takes as a reference, such as a voice. | | `frameImages` | Images pinned to a position on the video timeline. One image is the first frame, two are the first and the last. | | `image`, `video`, `audio` | The single asset the task operates on: the image to upscale, the video to edit, the audio a video follows. | | `images`, `videos`, `audios`, `documents` | Several assets read together, mostly attachments for a text model. | | `seedImage` | The image an image-to-image generation starts from. | | `maskImage` | The area of the source image to repaint. White is edited and black is preserved. | Almost every model in the catalog is **described by these inputs alone**, which is what lets one integration cover them all. That consistency never comes at the cost of the developer experience. When a model needs an input of its own, or a different shape for one of these, **its schema defines it**. Each input **declares its own limits**. H3 takes up to 9 `referenceImages` and up to 2 `frameImages`, both stated as `maxItems` in its schema. ## Building on the schema The direct integration is **one interface per model**. Each input becomes an upload slot, each core and settings parameter becomes a control, and the schema decides which requests are valid. The API layer stays in your backend, set once for every model. Every combination the model accepts is available from that one interface. The user fills the slots they need, and **nothing has to be decided per mode**. ### Rules between parameters Most parameters are valid whatever inputs are sent. H3 has 20 parameters outside `inputs`, and **only three depend on anything else**: `width`, `height` and `resolution`. What ties them to the inputs is a set of rules under `allOf`, at the root of the task schema. The rules are standard JSON Schema, and nearly all of them take **one of five shapes**. | Keyword | Meaning | Example | | --- | --- | --- | | `dependentRequired` | Parameters that travel together. | `width` requires `height`, and `height` requires `width`. | | `not` | Parameters that cannot be sent together. | `resolution` with `width` or `height`. | | `if` / `then` | One parameter being present requires, forbids or narrows another. | With `frameImages`, `width` and `height` are forbidden. | | `if` / `then` / `else` | The same, with a second rule for when the condition is not met. | With `frameImages`, `width` and `height` are forbidden. Without it, both are required. | | `oneOf` | A closed list of alternatives. | The `width` and `height` pairs the model accepts. | This is the H3 rule that removes the size parameters once a frame is sent. ```json { "if": { "properties": { "inputs": { "required": ["frameImages"] } }, "required": ["inputs"] }, "then": { "not": { "anyOf": [{ "required": ["width"] }, { "required": ["height"] }] } } } ``` The condition is **a presence check**. `if` matches when `inputs.frameImages` is sent, and `then` rejects the request if `width` or `height` came with it. With a frame, the output takes its aspect ratio from the image and `resolution` sets its size. ### Dimensions Many models accept **a closed list of width and height pairs** instead of any size. The list is a `oneOf`, and each entry carries a `title` you can show as a label. This is the start of the H3 list. ```json { "oneOf": [ { "title": "768p (~16:9)", "properties": { "width": { "const": 1344 }, "height": { "const": 768 } } }, { "title": "768p (4:3)", "properties": { "width": { "const": 1024 }, "height": { "const": 768 } } }, { "title": "768p (1:1)", "properties": { "width": { "const": 768 }, "height": { "const": 768 } } } ] } ``` A size outside the list is rejected, and on H3 that includes `1920 × 1080`. ### Limits on the media you send JSON Schema can check that `referenceVideos` is a list of URLs. It cannot check how long each clip runs. **Limits that depend on the file itself** are in `x-constraints`, at the root of the schema. ```json [ { "operation": "duration", "parameters": ["inputs.referenceVideos", "inputs.referenceAudios"], "minimum": 2, "maximum": 15, "scope": "each" }, { "operation": "duration", "parameters": ["inputs.referenceVideos", "inputs.referenceAudios"], "maximum": 15 } ] ``` On H3 each reference clip runs between 2 and 15 seconds, and the clips of one request add up to 15 seconds at most. Every entry is built from **the same fields**. | Field | Meaning | | --- | --- | | `operation` | What is measured. One of the operations listed below. | | `parameters` | The parameters the limit applies to, as paths. `inputs.referenceVideos` bounds a file, and `width` with `height` bounds the output size. | | `minimum`, `maximum` | The bounds, in the unit of the operation. | | `allowed` | A closed list of accepted values, used in place of the bounds. | | `scope` | `each` bounds every file on its own. Without it, the entry bounds all the listed files together. | | `when` | Makes the entry conditional. It applies only when every parameter in `present` is sent and every parameter in `absent` is left out. | `operation` takes **one of these values**. | Operation | What it measures | Unit | | --- | --- | --- | | `width` | Width of the output or of an input file | pixels | | `height` | Height of the output or of an input file | pixels | | `area` | Pixel count, width times height | pixels | | `ratio` | Width divided by height | none | | `duration` | Length of a video or audio file | seconds | | `frameRate` | Frame rate of a video | frames per second | | `pageCount` | Pages in a document | count | | `fileCount` | Files across the listed inputs | count | | `fileFormat` | Accepted file types, listed in `allowed` | none | | `fileSize` | Size of a file | bytes | | `archiveUnzippedSize` | Size of an archive once unpacked | bytes | | `archiveFileCount` | Files inside an archive | count | | `archiveImageCount` | Valid images inside an archive | count | A JSON Schema validator skips `x-constraints`, so a request can pass validation and still break one of these limits. **Check them in your own code** before uploading a file. ### Validating a request A JSON Schema validator **applies every rule at once**, so an interface can check a request as the user fills it in and before anything is sent. ```javascript import Ajv from 'ajv/dist/2020.js' const response = await fetch('https://runware.ai/docs/models/minimax-h3/schema.json') const document = await response.json() const task = document.components.schemas.RequestBody.items const compile = (schema) => new Ajv({ strict: false, validateFormats: false }).compile(schema) const validate = compile(task) const base = { taskType: 'videoInference', taskUUID: crypto.randomUUID(), model: 'minimax:h3@0', positivePrompt: 'The worker lifts the mature wasabi root smoothly into view.', } const firstFrame = { frameImages: ['https://assets.runware.ai/assets/inputs/93bc5eb1-8f3d-4c56-9232-06f3da7dce28.jpg'], } validate({ ...base, width: 1344, height: 768 }) // true validate({ ...base, resolution: '768p', inputs: firstFrame }) // true validate({ ...base, width: 1344, height: 768, inputs: firstFrame }) // false ``` One schema accepts the request with a frame and the request without one, and rejects the size parameters that do not fit the inputs sent. The rejected call reports `schemaPath`, **the location of the rule that failed**. Here it is `#/allOf/3/then/not`, the fourth rule of the task. An interface can use it to disable the control, and an agent can read the rule and correct the payload. > [!NOTE] > Use a validator, not a parser of your own > > The rules can be read by hand, but a parser has to be taught every shape a rule can take, and it breaks the day a model uses one it has never seen. A validator already implements the whole standard, so it stays right for every model, including the ones released later. A few models tie one value to another, so validate the final request with every value in place. A model can offer durations of 5, 8 and 10 seconds and sizes up to 1080p, and still take **5 or 8 seconds only** at 1080p. The [TypeScript](https://runware.ai/docs/tools/typescript) and [Python](https://runware.ai/docs/tools/python) SDKs run this validation for you, on every request, before it leaves your machine. ### Published examples Every model also publishes examples, each with **the request that produced it**. `info["x-examples"]` links to them, and they are there when you would rather adapt a request that ran than write one from an empty object. The published requests leave out `taskUUID`, so add one before sending. ## Working with separate modes Some products list text to video and image to video as separate items. That layout comes from models that did one thing each, and it maps onto the same schema: **each item is one combination of inputs** of the same model. This section is for anyone migrating from a provider with one endpoint per mode, and for a product that has that layout and keeps it for now. ### The modes of a model `info["x-modes"]` lists **every valid combination** of inputs. The list is shortened here. ```bash curl -s https://runware.ai/docs/models/minimax-h3/schema.json | jq '.info["x-modes"]' ``` ```json [ { "id": "text", "inputs": [] }, { "id": "reference-images", "inputs": ["referenceImages"] }, { "id": "first-frame", "inputs": ["frameImages"], "frames": ["first"] }, { "id": "first-last-frames", "inputs": ["frameImages"], "frames": ["first", "last"] }, { "id": "reference-videos", "inputs": ["referenceVideos"] }, { "id": "reference-images+reference-videos", "inputs": ["referenceImages", "referenceVideos"] } ] ``` | Field | Meaning | | --- | --- | | `id` | The inputs of the mode in kebab case, joined with `+`. `text` means no inputs at all. | | `inputs` | The keys of `inputs` that the mode sends. | | `frames` | Present on frame modes with fixed positions. The positions `frameImages` fills, so one input yields `first-frame` and `first-last-frames`. | | `frameCount` | Present on `multiple-frames`, the mode for three or more frames at positions you choose. It gives the `minimum` and `maximum` number of images. | | `values` | Present when a field inside an input changes what the input combines with. It names that field and the value the mode needs, and the `id` carries the value after a colon, as in `reference-videos:extend`. | The list already applies the rules between inputs. H3 has no mode that mixes `frameImages` with a reference input, and no `reference-audios` mode on its own, because an audio reference **needs an image or video reference** next to it. A combination missing from the list is one the model rejects. ### Choosing which modes to expose Every entry is a valid request, so the full list is the whole menu. **One item per mode** is the predictable choice: each item maps to one `id` and shows exactly the inputs it sends. For fewer items, keep the modes whose inputs are **not contained in a larger one**, and treat their inputs as optional. ```javascript const modes = document.info['x-modes'] const widest = modes.filter((mode) => ( !modes.some((other) => ( other.inputs.length > mode.inputs.length && mode.inputs.every((input) => (other.inputs.includes(input))) )) )) ``` On H3 that leaves three: `first-frame`, `first-last-frames`, and `reference-images+reference-videos+reference-audios`. > [!WARNING] > A narrower mode can accept parameters the wider one rejects. H3 takes `width` and `height` in `text` mode and forbids them once `frameImages` is present, so an item that folds `text` into `first-frame` has to switch its size controls when the frame is left empty. The list keeps growing as models accept more combinations, and each new one is another item to add. The interface described in [Building on the schema](https://runware.ai/docs/models-api/model-schemas#building-on-the-schema) **takes them all and stays the same**. ### Parameters of a mode Most of the schema is the same in every mode. **A few parameters are ruled out**, and those few are all that separates one mode from the next. | Group | Which parameters | How they behave | | --- | --- | --- | | **Inputs** | The keys listed in `inputs` on the `x-modes` entry. | Exactly those, and no other input. | | **Parameters that change** | The ones named in a rule of the schema. Usually the size parameters. | Allowed, required or forbidden depending on the mode. | | **Everything else** | The rest of the schema. | The same in every mode. | On H3 the three parameters named in a rule are **the only difference between its nine modes**. | Modes of H3 | Size parameters | | --- | --- | | `text` | `width` and `height` | | `first-frame`, `first-last-frames` | `resolution` | | Every mode with a reference input | `resolution`, or `width` and `height` | Many models have no rule at all, and each of their modes takes the full schema. For the rest, collecting the names that appear under `allOf` gives **the short list to resolve**. Not every name on it changes with the mode, and the test in the next section settles which ones do. The snippets in this section reuse `document`, `task`, `compile`, `base` and `firstFrame` from [Validating a request](https://runware.ai/docs/models-api/model-schemas#validating-a-request). ```javascript const ruleNames = (node, names = new Set()) => { if (Array.isArray(node)) { node.forEach((item) => ruleNames(item, names)) } else if (node && typeof node === 'object') { for (const name of node.required ?? []) { names.add(name) } for (const name of Object.keys(node.properties ?? {})) { names.add(name) } Object.values(node).forEach((value) => ruleNames(value, names)) } return names } const changing = [...ruleNames(task.allOf)] .filter((name) => (name !== 'inputs' && name in task.properties)) // ['resolution', 'width', 'height'] ``` ### A schema per mode Adding one constraint to the task schema **narrows it to a single mode**: the inputs of the mode become required and every other input is ruled out. The result is a regular JSON Schema, so a product with one item per mode can store one of these next to each item. ```javascript const modeSchema = (mode) => { const pinned = {} const count = (mode.frames) ? { minimum: mode.frames.length, maximum: mode.frames.length } : mode.frameCount if (count) { pinned.frameImages = { minItems: count.minimum, maxItems: count.maximum } } for (const [path, value] of Object.entries(mode.values ?? {})) { const [input, field] = path.split('.') pinned[input] = { items: { required: [field], properties: { [field]: { const: value } } } } } return { allOf: [task, { required: (mode.inputs.length) ? ['inputs'] : [], properties: { inputs: { required: mode.inputs, maxProperties: mode.inputs.length, properties: pinned }, }, }], } } const firstFrameMode = modes.find((mode) => (mode.id === 'first-frame')) const validateMode = compile(modeSchema(firstFrameMode)) const request = { ...base, inputs: firstFrame } validateMode({ ...request, resolution: '768p' }) // true validateMode({ ...request, width: 1344, height: 768 }) // false validateMode({ ...base, width: 1344, height: 768 }) // false ``` The first two calls **settle the size parameters** of `first-frame`: it takes `resolution` and rejects `width` and `height`. The third is a valid `text` request, and the mode schema rejects it because the frame is missing. **Run the same test for each changing parameter** against each mode and you have the form of every mode, with no rule read by hand. ### A working request per mode The mode schema also picks **the published example that fits the mode**, which gives each item a request that already ran. ```javascript const { examples } = await (await fetch(document.info['x-examples'])).json() const starting = examples.find((example) => ( validateMode({ ...example.request, taskUUID: crypto.randomUUID() }) )) // starting.request: { taskType, model, positivePrompt, resolution, duration, inputs } ``` A mode with no published example starts from the closest one, with its inputs swapped for the inputs of the mode. ## Integrating a new model 1. **Find the model.** Read `/docs/models/index.json`, match on `id` or `air`, and fetch the document at `schema`. 2. **Check its status.** Skip a model that is not `live`. For a `deprecated` one, `x-deactivates-at` is the date it stops working and `x-replaced-by` is the model to move to. 3. **Build the interface from the task schema.** Give each input an upload slot and each core and settings parameter a control. 4. **Write the request.** The examples in `info["x-examples"]` are there if you want one that already ran to start from. 5. **Validate every request** against the task schema, as it is filled in and before sending it. 6. **Send it.** Long-running tasks use `"deliveryMethod": "async"` with [task polling](https://runware.ai/docs/models-api/task-polling) or [webhooks](https://runware.ai/docs/models-api/webhooks). 7. **Read the result** with the shape in `ResponseBody`. Set `includeCost` to get the charge back with it. A product with separate modes adds two steps after the second: pick its items from `info["x-modes"]`, then build a schema per mode and validate against that one. Every step reads from the schema, so the same code path **covers the next model** the day its schema is published. --- ## Task Polling - **URL:** https://runware.ai/docs/models-api/task-polling - **Description:** Retrieve results from async operations using the getResponse task. Learn how to poll for status updates and fetch completed results. ## Introduction Some operations like video generation require extended processing time. Instead of holding the connection open, you can set `"deliveryMethod": "async"` on your request to **queue the task for asynchronous processing**. You receive an acknowledgment immediately, then use the `getResponse` task to poll for status updates and retrieve the final result when ready. [Webhooks](https://runware.ai/docs/models-api/webhooks) are the alternative: results arrive by HTTP POST as soon as they are ready, **with no polling at all**. > [!NOTE] > If you are using the [TypeScript](https://runware.ai/docs/tools/typescript) or [Python](https://runware.ai/docs/tools/python) SDK, async polling is handled automatically. You do not need to call `getResponse` directly. This page is relevant if you are integrating with the raw API. ### How it works When you call `getResponse` with a task UUID from an async operation, the system: 1. **Checks active operations** and finds the running async task and all its generations. 2. **Returns the current status** of each generation: `processing`, `success`, or `error`. 3. **Provides results as they become available.** Completed generations include their final outputs, so you can access partial results without waiting for everything to finish. > [!NOTE] > Polling best practices > > Implement **exponential backoff** when polling to avoid overwhelming the API. Start with 1-2 second intervals and gradually increase the delay between requests. > > For tasks with predictable durations (like video generation), consider adding an **initial delay** before your first poll to reduce unnecessary requests. ## Request The Runware API always accepts an array of objects as input, where each object represents a **specific task to be performed**. The structure varies depending on the workflow and features used. The following example shows the structure of a request object. **TypeScript**: ```typescript import { createClient } from '@runware/sdk' const client = await createClient({ apiKey: process.env.RUNWARE_API_KEY }) await client.connect() const [result] = await client.run({ taskType: 'getResponse', taskUUID: '50836053-a0ee-4cf5-b9d6-ae7c5d140ada' }) ``` **Python**: ```python import asyncio import os from runware import Runware async def main(): async with Runware(api_key=os.environ["RUNWARE_API_KEY"]) as client: results = await client.run({ "taskType": "getResponse", "taskUUID": "50836053-a0ee-4cf5-b9d6-ae7c5d140ada" }) asyncio.run(main()) ``` **cURL**: ```bash curl https://api.runware.ai/v1 \ -H "Authorization: Bearer $RUNWARE_API_KEY" \ -H "Content-Type: application/json" \ -d '[ { "taskType": "getResponse", "taskUUID": "50836053-a0ee-4cf5-b9d6-ae7c5d140ada" } ]' ``` **CLI**: ```bash runware result 50836053-a0ee-4cf5-b9d6-ae7c5d140ada ``` **JSON**: ```json { "taskType": "getResponse", "taskUUID": "50836053-a0ee-4cf5-b9d6-ae7c5d140ada" } ``` --- ### [taskType](https://runware.ai/docs/models-api/task-polling#request-tasktype) - **Type**: `string` - **Required**: true - **Value**: `getResponse` Identifier for the type of task being performed. ### [taskUUID](https://runware.ai/docs/models-api/task-polling#request-taskuuid) - **Type**: `string` - **Required**: true - **Format**: `UUID v4` UUID v4 identifier for tracking tasks and matching async responses. Must be unique per task. ## Response **All requests return the same response format.** Processing and successful generations appear in the `data` array, and failed ones move to the `errors` array. ```json { "data": [ { "taskType": "videoInference", "taskUUID": "24cd5dff-cb81-4db5-8506-b72a9425f9d1", "status": "processing", "progress": 47 }, { "taskType": "videoInference", "taskUUID": "24cd5dff-cb81-4db5-8506-b72a9425f9d1", "status": "success", "videoUUID": "b7db282d-2943-4f12-992f-77df3ad3ec71", "videoURL": "https://vm.runware.ai/video/os/a14d18/ws/2/vi/b7db282d-2943-4f12-992f-77df3ad3ec71.mp4", "cost": 0.18 } ], "errors": [ { "code": "timeoutProvider", "status": "error", "message": "The external provider did not respond within the timeout window. The request was automatically terminated.", "documentation": "https://runware.ai/docs/models-api/errors", "taskUUID": "24cd5dff-cb81-4db5-8506-b72a9425f9d1" } ] } ``` --- ### [taskType](https://runware.ai/docs/models-api/task-polling#response-tasktype) - **Type**: `string` - **Required**: true Identifier for the type of task this response belongs to. **Possible values**: `authentication` `imageInference` `videoInference` `audioInference` `textInference` `3dInference` `modelSearch` `modelUpload` `accountManagement` `imageUpload` `mediaStorage` `getResponse` `caption` `controlNetPreprocess` `imageMasking` `promptEnhance` `removeBackground` `upscale` `vectorize` `training` `ping` ### [taskUUID](https://runware.ai/docs/models-api/task-polling#response-taskuuid) - **Type**: `string` - **Required**: true - **Format**: `UUID v4` UUID v4 identifier echoed from the original request, used to match async responses to their tasks. ### [status](https://runware.ai/docs/models-api/task-polling#response-status) - **Type**: `string` - **Required**: true Current status of the task. **Possible values**: `processing` `success` `error` ### [progress](https://runware.ai/docs/models-api/task-polling#response-progress) - **Type**: `integer` - **Min**: `0` - **Max**: `100` Task progress as a percentage from 0 to 100. Returned while `status` is `processing`, and only for tasks that support progress reporting. ### [error](https://runware.ai/docs/models-api/task-polling#response-error) - **Path**: `error.code` - **Type**: `object (2 properties)` Error details if the task failed. #### [code](https://runware.ai/docs/models-api/task-polling#response-error-code) - **Path**: `error.code` - **Type**: `string` Error code. #### [message](https://runware.ai/docs/models-api/task-polling#response-error-message) - **Path**: `error.message` - **Type**: `string` Error message description. --- ## Streaming (SSE) - **URL:** https://runware.ai/docs/models-api/streaming - **Description:** Stream text inference results token-by-token using Server-Sent Events. Learn how to enable streaming and parse the SSE response format. ## Introduction Streaming lets you receive text inference responses **token-by-token as they are generated**, rather than waiting for the entire response to complete. Results are delivered via [Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events) (SSE), a lightweight HTTP-based protocol designed for real-time, server-to-client data delivery. Reach for it in chat interfaces and anywhere **perceived latency matters**. Instead of a multi-second wait followed by a wall of text, your users see the response appear progressively. Streaming is available for all text inference models and works alongside the existing `sync` and `async` delivery methods. ## Enabling streaming Add `"deliveryMethod": "stream"` to your request. Everything else stays the same: **TypeScript**: ```typescript import { createClient } from '@runware/sdk' const client = await createClient({ apiKey: process.env.RUNWARE_API_KEY }) await client.connect() const [result] = await client.run({ model: 'minimax:m2.7@0', deliveryMethod: 'stream', messages: [ { role: 'user', content: 'Hello' } ], settings: { maxTokens: 4096, temperature: 1 } }) ``` **Python**: ```python import asyncio import os from runware import Runware async def main(): async with Runware(api_key=os.environ["RUNWARE_API_KEY"]) as client: results = await client.run({ "model": "minimax:m2.7@0", "deliveryMethod": "stream", "messages": [ { "role": "user", "content": "Hello" } ], "settings": { "maxTokens": 4096, "temperature": 1 } }) asyncio.run(main()) ``` **cURL**: ```bash curl https://api.runware.ai/v1 \ -H "Authorization: Bearer $RUNWARE_API_KEY" \ -H "Content-Type: application/json" \ -d '[ { "taskType": "textInference", "taskUUID": "a770f077-f413-47de-9dac-be0b26a35da6", "model": "minimax:m2.7@0", "deliveryMethod": "stream", "messages": [ { "role": "user", "content": "Hello" } ], "settings": { "maxTokens": 4096, "temperature": 1 } } ]' ``` **CLI**: ```bash runware run minimax:m2.7@0 \ deliveryMethod=stream \ messages.0.role=user \ messages.0.content=Hello \ settings.maxTokens=4096 \ settings.temperature=1 ``` **JSON**: ```json { "taskType": "textInference", "taskUUID": "a770f077-f413-47de-9dac-be0b26a35da6", "model": "minimax:m2.7@0", "deliveryMethod": "stream", "messages": [ { "role": "user", "content": "Hello" } ], "settings": { "maxTokens": 4096, "temperature": 1 } } ``` The response is **an SSE stream instead of a single JSON object**. Each event carries a chunk of the generated text that you can display immediately. ## Delivery methods compared The `deliveryMethod` parameter controls how results are returned. Streaming is one of three options available for text inference tasks: | Value | Behavior | Best for | | --- | --- | --- | | `sync` | Waits for the full response, returns it as a single JSON object. This is the default. | Simple integrations, short responses | | `stream` | Streams tokens as SSE events as they are generated. | Chat UIs, long-form generation | | `async` | Returns immediately with a task acknowledgment. Poll for results using [Task Polling](https://runware.ai/docs/models-api/task-polling). | Background processing, long-running tasks | ## SSE response format The response is a standard SSE stream. Each event is a line prefixed with `data:`, followed by a JSON object, and terminated by a blank line. **The stream ends with a `data: [DONE]` sentinel.** The server may send `: ping` comments as keepalives, which should be ignored. ```text : ping data: {"taskUUID":"a770f077-f413-47de-9dac-be0b26a35da6","taskType":"textInference","delta":{"text":"Hello"},"finishReason":null} data: {"taskUUID":"a770f077-f413-47de-9dac-be0b26a35da6","taskType":"textInference","delta":{"text":" there"},"finishReason":null} data: {"taskUUID":"a770f077-f413-47de-9dac-be0b26a35da6","taskType":"textInference","delta":{},"finishReason":"stop"} data: [DONE] ``` ### Parsing rules Follow these steps to parse the SSE stream: 1. **Skip blank lines** and comment lines (lines starting with `:`). 2. **Strip the `data:` prefix** from each event line. 3. **Stop when you see `data: [DONE]`**, which signals the end of the stream. 4. **Parse each remaining line as JSON**. 5. **Read the text** from `delta.text`. 6. **Check for errors** by looking for an `errors` array in the parsed object. ### Content chunks During generation, each event carries a piece of the response text in `delta.text`. **Concatenate these chunks to build the full response**: ```text data: {"taskUUID":"a770f077-f413-47de-9dac-be0b26a35da6","taskType":"textInference","delta":{"text":"The"},"finishReason":null} data: {"taskUUID":"a770f077-f413-47de-9dac-be0b26a35da6","taskType":"textInference","delta":{"text":" answer"},"finishReason":null} data: {"taskUUID":"a770f077-f413-47de-9dac-be0b26a35da6","taskType":"textInference","delta":{"text":" is"},"finishReason":null} data: {"taskUUID":"a770f077-f413-47de-9dac-be0b26a35da6","taskType":"textInference","delta":{"text":" 42."},"finishReason":null} ``` ### Reasoning chunks Some models perform internal reasoning before generating the final response. For these models, reasoning tokens arrive **first** in `delta.reasoningContent`, followed by the actual response in `delta.text`. ```text // Reasoning chunks - delta.reasoningContent data: {"taskUUID":"6e879837-4b2a-4c1d-ae5f-8f3c21b07a92","taskType":"textInference","delta":{"reasoningContent":"The user asks: \"What is 2+2? Be brief.\" They want a short answer. It's a simple arithmetic: 4. Provide"}} data: {"taskUUID":"6e879837-4b2a-4c1d-ae5f-8f3c21b07a92","taskType":"textInference","delta":{"reasoningContent":" short answer."}} // Actual response - switches to delta.text data: {"taskUUID":"6e879837-4b2a-4c1d-ae5f-8f3c21b07a92","taskType":"textInference","delta":{"text":"4"},"finishReason":null} ``` **Reasoning content is separate from the answer**, so you can put it behind a collapsible section or a debug panel while the final response streams to the user. ### Multiple results When you set `numberResults` greater than 1, multiple completions stream on the same connection. **Each chunk includes a `resultIndex`**, because all results share the same `taskUUID`: ```text data: {"taskUUID":"a770f077-f413-47de-9dac-be0b26a35da6","taskType":"textInference","resultIndex":0,"delta":{"text":"Paris"},"finishReason":null} data: {"taskUUID":"a770f077-f413-47de-9dac-be0b26a35da6","taskType":"textInference","resultIndex":1,"delta":{"text":"The capital"},"finishReason":null} data: {"taskUUID":"a770f077-f413-47de-9dac-be0b26a35da6","taskType":"textInference","resultIndex":0,"delta":{},"finishReason":"stop"} data: {"taskUUID":"a770f077-f413-47de-9dac-be0b26a35da6","taskType":"textInference","resultIndex":1,"delta":{"text":" is Paris."},"finishReason":null} data: {"taskUUID":"a770f077-f413-47de-9dac-be0b26a35da6","taskType":"textInference","resultIndex":1,"delta":{},"finishReason":"stop"} data: [DONE] ``` Group chunks by `resultIndex` to reconstruct each result independently. Results may finish at different times. ### Final chunk and finish reason The last content-bearing event includes a `finishReason` value that tells you why the model stopped generating: | Finish reason | Meaning | | --- | --- | | `stop` | The model completed its response naturally. | | `length` | The response hit the `maxTokens` limit. | | `content_filter` | Content was filtered by the safety system. | | `tool_calls` | The model is requesting a tool call. | | `tool_use` | The model is requesting a tool use. | | `unknown` | The model stopped for an unrecognized reason. | ```text data: {"taskUUID":"6e879837-4b2a-4c1d-ae5f-8f3c21b07a92","taskType":"textInference","delta":{},"finishReason":"stop"} data: [DONE] ``` ### Cost and usage Cost and token usage are reported in the **final chunk** of the stream, but only when explicitly requested: - Set **`includeCost: true`** to receive the `cost` field with the total price of the request in USD. Useful for tracking spend and billing. - Set **`includeUsage: true`** to receive the `usage` object with detailed token counts and processing metadata. Useful for monitoring context window usage and optimizing prompts. **TypeScript**: ```typescript import { createClient } from '@runware/sdk' const client = await createClient({ apiKey: process.env.RUNWARE_API_KEY }) await client.connect() const [result] = await client.run({ model: 'minimax:m2.7@0', deliveryMethod: 'stream', messages: [ { role: 'user', content: 'What is 2+2? Be brief.' } ], settings: { maxTokens: 4096, temperature: 1 }, includeCost: true, includeUsage: true }) ``` **Python**: ```python import asyncio import os from runware import Runware async def main(): async with Runware(api_key=os.environ["RUNWARE_API_KEY"]) as client: results = await client.run({ "model": "minimax:m2.7@0", "deliveryMethod": "stream", "messages": [ { "role": "user", "content": "What is 2+2? Be brief." } ], "settings": { "maxTokens": 4096, "temperature": 1 }, "includeCost": True, "includeUsage": True }) asyncio.run(main()) ``` **cURL**: ```bash curl https://api.runware.ai/v1 \ -H "Authorization: Bearer $RUNWARE_API_KEY" \ -H "Content-Type: application/json" \ -d '[ { "taskType": "textInference", "taskUUID": "a770f077-f413-47de-9dac-be0b26a35da6", "model": "minimax:m2.7@0", "deliveryMethod": "stream", "messages": [ { "role": "user", "content": "What is 2+2? Be brief." } ], "settings": { "maxTokens": 4096, "temperature": 1 }, "includeCost": true, "includeUsage": true } ]' ``` **CLI**: ```bash runware run minimax:m2.7@0 \ deliveryMethod=stream \ messages.0.role=user \ messages.0.content="What is 2+2? Be brief." \ settings.maxTokens=4096 \ settings.temperature=1 \ includeCost=true \ includeUsage=true ``` **JSON**: ```json { "taskType": "textInference", "taskUUID": "a770f077-f413-47de-9dac-be0b26a35da6", "model": "minimax:m2.7@0", "deliveryMethod": "stream", "messages": [ { "role": "user", "content": "What is 2+2? Be brief." } ], "settings": { "maxTokens": 4096, "temperature": 1 }, "includeCost": true, "includeUsage": true } ``` The final chunk before `[DONE]` will include both fields: ```text data: {"taskUUID":"6e879837-4b2a-4c1d-ae5f-8f3c21b07a92","taskType":"textInference","delta":{},"finishReason":"stop","usage":{"promptTokens":51,"completionTokens":38,"totalTokens":89},"cost":0.000061} data: [DONE] ``` ### Error handling If an error occurs during streaming, the event will contain an `errors` array instead of a `delta` object. ```json { "errors": [ { "code": "timeoutProvider", "message": "The provider timed out while generating the response.", "taskType": "textInference", "taskUUID": "a770f077-f413-47de-9dac-be0b26a35da6" } ] } ``` **Check for `errors` in your parsing logic**, not only for text chunks. The fields follow the same structure as [standard API errors](https://runware.ai/docs/models-api/errors). ## Code examples **cURL**: ```bash # The -N flag disables curl's output buffering so chunks print as they arrive. curl -N -X POST https://api.runware.ai/v1 \ -H "Authorization: Bearer $RUNWARE_API_KEY" \ -H "Content-Type: application/json" \ -d '[ { "taskType": "textInference", "taskUUID": "550e8400-e29b-41d4-a716-446655440000", "model": "minimax:m2.7@0", "deliveryMethod": "stream", "messages": [{"role": "user", "content": "Tell me a joke"}], "settings": {"maxTokens": 512, "temperature": 1.0}, "includeCost": true } ]' ``` **JavaScript**: ```javascript const response = await fetch('https://api.runware.ai/v1', { method: 'POST', headers: { 'Authorization': 'Bearer ' + RUNWARE_API_KEY, 'Content-Type': 'application/json', }, body: JSON.stringify([{ taskType: 'textInference', taskUUID: crypto.randomUUID(), model: 'minimax:m2.7@0', deliveryMethod: 'stream', messages: [{ role: 'user', content: 'Tell me a joke' }], settings: { maxTokens: 512, temperature: 1.0 }, }]), }); const reader = response.body.getReader(); const decoder = new TextDecoder(); let buffer = ''; while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split('\n'); buffer = lines.pop(); for (const line of lines) { if (!line.trim() || line.startsWith(':')) continue; if (line === 'data: [DONE]') return; const json = JSON.parse(line.replace('data: ', '')); if (json.errors) { console.error(json.errors[0].message); return; } const text = json.delta?.text; if (text) process.stdout.write(text); } } ``` **Python**: ```python import json import uuid import httpx response = httpx.post( 'https://api.runware.ai/v1', headers={ 'Authorization': f'Bearer {RUNWARE_API_KEY}', 'Content-Type': 'application/json', }, json=[{ 'taskType': 'textInference', 'taskUUID': str(uuid.uuid4()), 'model': 'minimax:m2.7@0', 'deliveryMethod': 'stream', 'messages': [{'role': 'user', 'content': 'Tell me a joke'}], 'settings': {'maxTokens': 512, 'temperature': 1.0}, }], timeout=None, ) for line in response.iter_lines(): if not line or line.startswith(':'): continue if line == 'data: [DONE]': break data = json.loads(line.removeprefix('data: ')) if 'errors' in data: raise Exception(data['errors'][0]['message']) text = data.get('delta', {}).get('text', '') if text: print(text, end='', flush=True) ``` ## Best practices - **Buffer by line, not by byte**. Network chunks may split a JSON event across multiple reads. Accumulate data in a buffer and process complete lines only. - **Handle `[DONE]` explicitly**. Always check for the `data: [DONE]` sentinel before attempting to parse JSON. Treating it as JSON will cause a parse error. - **Separate reasoning from content**. If you're working with reasoning models, track whether the stream is currently delivering `delta.reasoningContent` or `delta.text` and route them accordingly. - **Implement timeouts**. Set a reasonable timeout for the overall stream connection. If no events arrive within your timeout window, close the connection and retry. - **Use the Fetch API for browser clients**. The browser's native `EventSource` API only supports GET requests. Since text inference uses POST, use the Fetch API with `ReadableStream` instead. --- ## Webhooks - **URL:** https://runware.ai/docs/models-api/webhooks - **Description:** Receive real-time notifications when your tasks complete using webhooks. Learn how to configure, secure, and handle webhook deliveries from Runware. ## Introduction Webhooks deliver an HTTP POST the moment a generation task completes, **so nothing has to poll for the result**. Runware sends the complete response to the URL you name. They earn their place on **long-running work like video generation**, on batches whose items finish at different times, and wherever another system has to react the moment a result exists. For an alternative approach using client-side polling, see [Task Polling](https://runware.ai/docs/models-api/task-polling). ## How it works You provide a webhook URL when submitting a task. Runware processes the request asynchronously and POSTs the complete task response as JSON when it completes. **Your endpoint must answer with a 2xx status code to confirm receipt**, or delivery is retried automatically (see [Retry behavior](https://runware.ai/docs/models-api/webhooks#retry-behavior)). In a batch, **each completed item triggers its own webhook call** as it becomes available. ## Configuration Include the `webhookURL` parameter in your API request: **TypeScript**: ```typescript import { createClient } from '@runware/sdk' const client = await createClient({ apiKey: process.env.RUNWARE_API_KEY }) await client.connect() const [result] = await client.run({ model: 'runware:100@1', positivePrompt: 'a serene landscape', width: 1024, height: 1024, webhookURL: 'https://api.example.com/webhooks/runware' }) ``` **Python**: ```python import asyncio import os from runware import Runware async def main(): async with Runware(api_key=os.environ["RUNWARE_API_KEY"]) as client: results = await client.run({ "model": "runware:100@1", "positivePrompt": "a serene landscape", "width": 1024, "height": 1024, "webhookURL": "https://api.example.com/webhooks/runware" }) asyncio.run(main()) ``` **cURL**: ```bash curl https://api.runware.ai/v1 \ -H "Authorization: Bearer $RUNWARE_API_KEY" \ -H "Content-Type: application/json" \ -d '[ { "taskType": "imageInference", "taskUUID": "a770f077-f413-47de-9dac-be0b26a35da6", "model": "runware:100@1", "positivePrompt": "a serene landscape", "width": 1024, "height": 1024, "webhookURL": "https://api.example.com/webhooks/runware" } ]' ``` **CLI**: ```bash runware run runware:100@1 \ positivePrompt="a serene landscape" \ width=1024 \ height=1024 \ webhookURL=https://api.example.com/webhooks/runware ``` **JSON**: ```json { "taskType": "imageInference", "taskUUID": "a770f077-f413-47de-9dac-be0b26a35da6", "model": "runware:100@1", "positivePrompt": "a serene landscape", "width": 1024, "height": 1024, "webhookURL": "https://api.example.com/webhooks/runware" } ``` ### Authentication **Webhooks authenticate through URL parameters.** Put a token, an API key or your own tracking parameters directly in the webhook URL: **Authentication token**: ```text https://api.example.com/webhooks/runware?token=your_auth_token ``` **API key**: ```text https://api.example.com/webhooks/runware?apiKey=sk_live_abc123 ``` **Custom parameters**: ```text https://api.example.com/webhooks/runware?projectId=proj_789&userId=12345 ``` > [!WARNING] > Always use HTTPS for webhook URLs to ensure data transmission is encrypted. Validate authentication parameters in your endpoint before processing webhook data. ## Receiving notifications The webhook POST body carries the complete JSON response for your task. **The structure matches the standard API response for that task type**: **TypeScript**: ```typescript import { createClient } from '@runware/sdk' const client = await createClient({ apiKey: process.env.RUNWARE_API_KEY }) await client.connect() const [result] = await client.run({ imageUUID: '550e8400-e29b-41d4-a716-446655440000', imageURL: 'https://im.runware.ai/image/os/a14d18/ws/2/ii/550e8400-e29b-41d4-a716-446655440000.jpg', model: 'runware:100@1', width: 1024, height: 1024, cost: 0.004, createdAt: '2026-01-16T10:30:45Z' }) ``` **Python**: ```python import asyncio import os from runware import Runware async def main(): async with Runware(api_key=os.environ["RUNWARE_API_KEY"]) as client: results = await client.run({ "imageUUID": "550e8400-e29b-41d4-a716-446655440000", "imageURL": "https://im.runware.ai/image/os/a14d18/ws/2/ii/550e8400-e29b-41d4-a716-446655440000.jpg", "model": "runware:100@1", "width": 1024, "height": 1024, "cost": 0.004, "createdAt": "2026-01-16T10:30:45Z" }) asyncio.run(main()) ``` **cURL**: ```bash curl https://api.runware.ai/v1 \ -H "Authorization: Bearer $RUNWARE_API_KEY" \ -H "Content-Type: application/json" \ -d '[ { "taskType": "imageInference", "taskUUID": "a770f077-f413-47de-9dac-be0b26a35da6", "imageUUID": "550e8400-e29b-41d4-a716-446655440000", "imageURL": "https://im.runware.ai/image/os/a14d18/ws/2/ii/550e8400-e29b-41d4-a716-446655440000.jpg", "model": "runware:100@1", "width": 1024, "height": 1024, "cost": 0.004, "createdAt": "2026-01-16T10:30:45Z" } ]' ``` **CLI**: ```bash runware run runware:100@1 \ imageUUID=550e8400-e29b-41d4-a716-446655440000 \ imageURL=https://im.runware.ai/image/os/a14d18/ws/2/ii/550e8400-e29b-41d4-a716-446655440000.jpg \ width=1024 \ height=1024 \ cost=0.004 \ createdAt=2026-01-16T10:30:45Z ``` **JSON**: ```json { "taskType": "imageInference", "taskUUID": "a770f077-f413-47de-9dac-be0b26a35da6", "imageUUID": "550e8400-e29b-41d4-a716-446655440000", "imageURL": "https://im.runware.ai/image/os/a14d18/ws/2/ii/550e8400-e29b-41d4-a716-446655440000.jpg", "model": "runware:100@1", "width": 1024, "height": 1024, "cost": 0.004, "createdAt": "2026-01-16T10:30:45Z" } ``` ## Building your endpoint Your endpoint must answer with a status code between 200 and 299 to confirm receipt, **ideally within 5 seconds**. If the work is heavy, return the 200 first and do the work afterwards. **Node.js (Express)**: ```javascript const express = require('express'); const app = express(); app.use(express.json()); app.post('/webhooks/runware', (req, res) => { const webhookData = req.body; // Verify authentication if (req.query.token !== process.env.WEBHOOK_TOKEN) { return res.status(401).send('Unauthorized'); } // Process asynchronously processWebhook(webhookData).catch(console.error); // Respond immediately res.status(200).send('OK'); }); async function processWebhook(data) { console.log('Task completed:', data.taskUUID); // Handle the completed task... } app.listen(3000); ``` **Python (Flask)**: ```python from flask import Flask, request import os app = Flask(__name__) @app.route('/webhooks/runware', methods=['POST']) def webhook(): if request.args.get('token') != os.environ.get('WEBHOOK_TOKEN'): return 'Unauthorized', 401 webhook_data = request.json process_webhook(webhook_data) return 'OK', 200 def process_webhook(data): print(f"Task completed: {data['taskUUID']}") # Handle the completed task... if __name__ == '__main__': app.run(port=3000) ``` **PHP**: ```php { const { taskUUID } = req.body; if (processed.has(taskUUID)) { return res.status(200).send('Already processed'); } processed.add(taskUUID); processWebhook(req.body); res.status(200).send('OK'); }); ``` ## Troubleshooting If nothing arrives, check that **your endpoint is publicly reachable and answering with 2xx**. Look for the incoming requests in your server logs, and confirm the SSL certificate is valid on an HTTPS endpoint. In local development, ngrok gives you a reachable URL. If your endpoint times out, return the 200 first and move the heavy work to a background job. **Delivery counts as successful only when a 2xx arrives inside the timeout window.** --- ## Errors - **URL:** https://runware.ai/docs/models-api/errors - **Description:** Understanding error responses from the Runware API and how to handle them in your integration. ## Introduction When a request fails, the Runware API returns a JSON response containing an `errors` array. This format is consistent across both **HTTP REST** and **WebSocket** connections. **Error Response**: ```json { "errors": [ { "code": "invalidApiKey", "message": "Invalid API key. Get one at https://runware.ai/signup", "parameter": "apiKey", "taskType": "authentication" } ] } ``` Each object in the `errors` array represents a single failed operation. When you send multiple tasks in one request, **errors are scoped to the task that failed** and the rest may still succeed. ### Error fields | Field | Type | Description | | --- | --- | --- | | `code` | string | A short identifier for the error (e.g., `invalidApiKey`, `timeoutProvider`). | | `message` | string | A human-readable explanation with details about what went wrong. | | `parameter` | string | The request parameter related to the error, if applicable. | | `taskType` | string | The task type of the request that failed. | | `taskUUID` | string | The unique identifier of the request that failed, useful for debugging and support. | | `retryAfter` | integer | The number of seconds to wait before retrying, on errors that name a wait. | | `documentation` | string | A link to relevant documentation for the parameter. | > [!NOTE] > We are actively standardizing our error codes and response formats. During this transition, you may encounter error codes or message formats that vary between models and providers. We recommend logging the full `message` and `taskUUID` fields to debug issues effectively. ## HTTP status codes Over the HTTP REST API, the response also carries **a standard HTTP status code alongside the `errors` array**. These codes name the general category of the failure: | Code | Description | | --- | --- | | `400` | **Bad Request** - The request was unacceptable, often due to missing a required parameter. | | `401` | **Unauthorized** - No valid API key provided. | | `402` | **Payment Required** - Your account balance is insufficient. | | `403` | **Forbidden** - The API key doesn't have permissions to perform the request. | | `404` | **Not Found** - The requested resource doesn't exist. | | `429` | **Too Many Requests** - The request was not accepted, because the model's queue is over capacity or your organization passed its rate limit. Retry after the wait in the `Retry-After` header. See [Rate Limits](https://runware.ai/docs/models-api/rate-limits). | | `500` | **Server Error** - Something went wrong on Runware's end. | | `503` | **Service Unavailable** - The service is temporarily unavailable (e.g., maintenance or capacity). | **WebSocket connections have no HTTP status codes.** Read the `code` field in the error object instead to tell the categories apart. ## Handling errors For retry decisions, read the HTTP status code on REST and the error `code` on WebSocket. For debugging, **log the full `message` and `taskUUID`**: the task UUID is the fastest way to get help from support. ### Retries For transient errors, it is often safe to retry the request with **exponential backoff**. These include: - HTTP `429` (Too Many Requests) and `5xx` (Server Error) status codes. - Error codes indicating capacity or provider issues (e.g., `timeoutProvider`, `providerRateLimitExceeded`). When an error carries `retryAfter`, **wait that many seconds** before sending the task again and skip your own backoff delay for that attempt. This is the case for `serviceOverloaded`, which the API returns when a model's queue is over capacity. Over HTTP the wait also arrives in the `Retry-After` header. For client errors such as invalid parameters or authentication failures, you should **not** retry without modifying the request, as it will fail again. See [Rate Limits](https://runware.ai/docs/models-api/rate-limits) for detailed retry implementation patterns. --- ## Rate Limits - **URL:** https://runware.ai/docs/models-api/rate-limits - **Description:** Understanding platform rate limits and best practices for building resilient integrations with Runware. ## Introduction Runware runs on **shared infrastructure with finite processing capacity**. Queue-based systems balance load across users while prioritizing active workloads, and the REST API adds a **per-organization rate limit** that sits far above typical traffic. Under load, **latency rises first**. Once a model's queue is over capacity, new requests for that model are **rejected right away with a retry hint**. **Current approach:** - **High rate limit** - A per-organization limit on the REST API sits far above typical traffic. - **Shared queues** - Requests are processed through model-specific queues with finite capacity. - **Fair allocation** - Processing capacity is distributed fairly across active users. - **Graceful degradation** - Under load, latency increases first. Once a queue is over capacity, new requests are rejected. ## What to expect Under normal conditions, requests are processed quickly. **When platform capacity is reached**, here is what happens: **1\. Queueing** - Requests enter a queue and wait for available processing capacity. **2\. Increased latency** - Generation time increases as queue depth grows. This is normal and expected. **3\. Overload rejection** - When a model's queue is over capacity, new requests for that model are rejected immediately with a retry hint. See [Overload rejections](https://runware.ai/docs/models-api/rate-limits#overload-rejections). **4\. Timeout potential** - Extremely long queues may result in timeout errors after waiting too long. **5\. Transient failures** - During peak demand, some requests may fail with retryable errors. ### HTTP status codes You may encounter these status codes when capacity is constrained: - **`429 Too Many Requests`** - The request was not accepted, because the model's queue is over capacity or your organization passed its rate limit. Retry after the wait in the `Retry-After` header. - **`503 Service Unavailable`** - Temporary capacity constraint, retry recommended. - **`504 Gateway Timeout`** - Request exceeded maximum queue wait time. All of these are transient and should be handled with retry logic. ### Overload rejections When a model's queue is over capacity, the API rejects new requests for that model with the `serviceOverloaded` error code. The task is **rejected before it enters the queue**, so retrying it cannot run it twice. **Error Response**: ```json { "errors": [ { "code": "serviceOverloaded", "message": "The service is temporarily unavailable due to high demand. Please retry your request in a few moments.", "taskType": "imageInference", "retryAfter": 7, "taskUUID": "f4cdf306-e3dc-4a58-ad64-0ad049518e2d" } ] } ``` `retryAfter` is the **number of seconds to wait** before sending the task again. It follows the load on the queue, so the value changes from one rejection to the next. In a request with several tasks, read it on each rejected task. Over HTTP, a response made up only of these rejections is a `429` with a `Retry-After` header. WebSocket messages have no headers, so read the field there. ### Organization rate limit The REST API also applies a **rate limit per organization**, counted in results per second. Each requested result counts once, so a task with `numberResults` set to 4 counts as four. The limit sits far above typical traffic. A request over the limit fails with the `inferenceRateLimitExceeded` error code and a `429`. The `Retry-After` header gives the wait in seconds, and the request **was not processed**, so sending it again cannot run it twice. A single request that asks for more results than the limit allows at once fails with `inferenceRateLimitRequestTooLarge`. Retrying it unchanged fails again, so **split it into smaller requests**. ## Third-party provider limits We integrate with external AI providers like OpenAI, Black Forest Labs, ByteDance, and others. **Their rate limits and capacity constraints affect our service**, even when our infrastructure has available capacity. > [!NOTE] > Models from third-party providers are subject to the provider's own rate limits and capacity constraints. When a provider experiences high demand or enforces their limits, you may see reduced throughput or temporary unavailability for those specific models. **What this means:** - **Provider throttling appears as our errors** - You'll see 429, 503, or increased latency when upstream providers hit their limits. - **We can't control their capacity** - Some providers enforce strict concurrency or rate limits that cascade to our service. - **Model-specific constraints** - Check individual model documentation for provider-specific limitations. This is an inherent part of working with third-party AI services, and why **a retry with backoff belongs in your client**. ## Best practices ### Implement retry logic Retry capacity errors, and **wait for the time the API names** whenever the response carries one. Fall back to exponential backoff when it does not. A little random jitter on top keeps clients that were rejected together from all returning in the same second. **TypeScript**: ```typescript async function sendWithRetry(tasks: object[], maxRetries = 5) { for (let attempt = 0; ; attempt++) { const response = await fetch('https://api.runware.ai/v1', { method: 'POST', headers: { 'Authorization': 'Bearer ' + RUNWARE_API_KEY, 'Content-Type': 'application/json', }, body: JSON.stringify(tasks), }) const overCapacity = response.status === 429 || response.status === 503 if (!overCapacity || attempt === maxRetries) { return response.json() } const hint = Number(response.headers.get('Retry-After')) const seconds = hint > 0 ? hint : 2 ** attempt await new Promise(resolve => setTimeout(resolve, (seconds + Math.random()) * 1000)) } } ``` **Python**: ```python import random import time import httpx def send_with_retry(tasks, max_retries=5): for attempt in range(max_retries + 1): response = httpx.post( 'https://api.runware.ai/v1', headers={ 'Authorization': f'Bearer {RUNWARE_API_KEY}', 'Content-Type': 'application/json', }, json=tasks, timeout=None, ) over_capacity = response.status_code in (429, 503) if not over_capacity or attempt == max_retries: return response.json() hint = response.headers.get('Retry-After', '') seconds = int(hint) if hint.isdigit() else 2 ** attempt time.sleep(seconds + random.random()) ``` ### Manage concurrency While we don't enforce hard concurrency limits, we recommend the following for optimal performance: **Standard usage** - 2-4 concurrent requests provides optimal throughput for most use cases. **High-volume deployments** - Contact our team to discuss capacity planning and dedicated infrastructure options. **Burst workloads** - Implement request throttling on your end to avoid saturating queues during sudden spikes. > [!WARNING] > Sending hundreds of concurrent requests may saturate queues and result in rejections or timeouts. Implement concurrency limits in your application for better reliability. ### Monitor response times Track generation latency as a proxy for platform capacity: - **Consistent sub-30s responses** - Healthy capacity, system operating normally. - **Increasing latency trends** - Approaching capacity limits, consider reducing concurrency. - **Frequent rejections or timeouts** - Queue saturation, implement backoff or reduce request volume. Use latency monitoring to dynamically adjust your request patterns and avoid overwhelming the platform. ## Model-specific capacity Some models have limited infrastructure due to hardware requirements, demand patterns, or provider constraints: **High-demand models** - Popular models may experience longer queues during peak hours. **Resource-intensive models** - Video generation and large models require significant GPU resources, limiting concurrent capacity. Check individual model documentation for specific constraints. **Third-party provider models** - Models from external providers are subject to their capacity constraints and rate limits. > [!NOTE] > For production deployments requiring guaranteed capacity or SLAs on specific models, contact our sales team to discuss dedicated infrastructure options. ## What's coming We're actively developing improvements to provide more predictable performance: **Tiered concurrency limits** - Predictable limits based on usage tier, with clear thresholds and automatic scaling. **Capacity reservations** - Guaranteed throughput for enterprise users with dedicated infrastructure. **Real-time capacity metrics** - API endpoints showing current queue depth and estimated processing times. **Serverless scaling** - Dynamic model loading for improved availability and reduced cold starts. These improvements will provide enterprise-grade reliability while maintaining platform accessibility for all users. ## Summary **Current state:** - Shared infrastructure with finite capacity, and a high per-organization rate limit on the REST API - Queueing under load, then rejection with a retry hint once a queue is over capacity - Third-party provider limits affect service availability **Your responsibilities:** - Retry capacity errors, waiting for `Retry-After` when the response carries it - Manage concurrency (2-4 concurrent requests recommended) - Monitor latency and adjust request patterns **Need guarantees?** - Contact sales for dedicated capacity, SLAs, and custom infrastructure Follow these and your integration **absorbs a capacity constraint instead of failing on it**. --- ## Pricing - **URL:** https://runware.ai/docs/models-api/pricing - **Description:** How Runware charges for a generation, where the price of each model lives, and how to read pricing data as JSON. ## Introduction You pay for what each request uses, in USD, with **no subscription and no minimum spend**. Your balance is deducted as you generate and it never expires. Two things decide what a generation costs: **the model you call** and **what you ask it for**. A 10 second video costs more than a 5 second one, and a 2048 × 2048 image costs more than a 512 × 512 one. ## How a model is priced **Most models charge a rate per unit.** The unit is whatever the model produces or consumes, from a second of video to a million tokens. Multiply the units you asked for by the rate and you know the price before you send the request. **Some models are billed by compute time.** The charge follows the GPU time your request uses, so every setting that gives it more work to do makes it cost more. These models publish measured runs instead of a rate: real generations, each with the settings that produced it and what it was charged. Compute time also works in your favor. **When an optimization cuts the GPU time a model needs, the cost of a generation drops with it**, with no change on your side and no new price to adopt. ## What changes the cost **Anything that gives the model more work to do costs more.** These are the usual ones, and they are examples rather than the whole list. | Factor | Effect | | --- | --- | | **Model** | Sets the rate, or the hardware and optimizations the run uses. | | **Resolution** | More pixels take longer to generate, and some models price each tier separately. | | **Duration** | Video and audio are usually charged per second of output. | | **Steps** | Each step is another pass through the model. | | **Number of outputs** | `numberResults` multiplies the cost of the task. | A model can charge for other things too, such as each reference image past the first few, or the characters of a script it has to read. **The rate card on the model's page names every unit that model bills by.** ## Where the price of a model lives A model with a published price carries a **Cost and speed** panel on its page, with the rates, the measured runs, and example generations with their price and the time they took. When a model is running a temporary offer, a badge shows it there, and **what you are charged while the offer lasts is lower than the listed rate**. Start at the [Models](https://runware.ai/docs/models) section. **A model with a rate tells you what a request costs before you send it.** One billed by compute time tells you after it runs, and its measured runs are there to size it up first. ## Pricing data as JSON The same data is published as JSON, so an agent or a script can read prices without scraping a page. | Endpoint | What it holds | | --- | --- | | `/docs/models/index.json` | Every public model with its id, AIR, capabilities, and the URL of its schema. | | `/docs/models//schema.json` | The OpenAPI document for one model. Pricing is in `info["x-pricing"]`. | | `/docs/models//examples.json` | The runs behind the example prices, each with its request and response. | Ask any model for its pricing block and you get **the shape that fits how it charges**. The example lists are shortened here. **Per second**: ```bash curl -s https://runware.ai/docs/models/alibaba-wan3-0/schema.json | jq '.info["x-pricing"]' ``` ```json { "currency": "USD", "docs": "https://runware.ai/docs/models-api/pricing", "rates": [ { "amount": 0.05, "unit": "durationSecond", "label": "480p", "display": "$0.05 per second" }, { "amount": 0.1, "unit": "durationSecond", "label": "720p", "display": "$0.10 per second" }, { "amount": 0.2, "unit": "durationSecond", "label": "1080p", "display": "$0.20 per second" } ], "examples": [ { "id": "mycelium-packaging-factory-b-roll", "configuration": "first-frame · 720p · 5s", "price": 0.504, "latencyMs": 127753 } ] } ``` **Per run**: ```bash curl -s https://runware.ai/docs/models/prunaai-p-image-ideogram/schema.json | jq '.info["x-pricing"]' ``` ```json { "currency": "USD", "docs": "https://runware.ai/docs/models-api/pricing", "rates": [ { "amount": 0.003, "unit": "output", "label": "1K - very low thinking", "display": "$0.003 per image" }, { "amount": 0.006, "unit": "output", "label": "2K - very low thinking", "display": "$0.006 per image" } ], "examples": [ { "id": "stage-backdrop-conservation-book-cover", "configuration": "text-to-image", "price": 0.0225, "latencyMs": 16427 } ] } ``` **Per token**: ```bash curl -s https://runware.ai/docs/models/minimax-m3/schema.json | jq '.info["x-pricing"]' ``` ```json { "currency": "USD", "docs": "https://runware.ai/docs/models-api/pricing", "basis": "token", "rates": [ { "amount": 3e-07, "unit": "inputToken", "label": "≤ 512K context", "display": "$0.30 per 1M input tokens" }, { "amount": 6e-07, "unit": "inputToken", "label": "> 512K context", "display": "$0.60 per 1M input tokens" }, { "amount": 1.2e-06, "unit": "outputToken", "label": "≤ 512K context", "display": "$1.20 per 1M output tokens" }, { "amount": 2.4e-06, "unit": "outputToken", "label": "> 512K context", "display": "$2.40 per 1M output tokens" }, { "amount": 6e-08, "unit": "cachedInputToken", "label": "≤ 512K context", "display": "$0.06 per 1M cached tokens" }, { "amount": 1.2e-07, "unit": "cachedInputToken", "label": "> 512K context", "display": "$0.12 per 1M cached tokens" } ], "examples": [ { "id": "forced-utc-time-function-call", "configuration": "tool-calling", "price": 0.000136, "latencyMs": 1230 } ] } ``` **Compute time**: ```bash curl -s https://runware.ai/docs/models/alibaba-z-image/schema.json | jq '.info["x-pricing"]' ``` ```json { "currency": "USD", "docs": "https://runware.ai/docs/models-api/pricing", "measured": [ { "configuration": "512×512 · steps 20", "price": 0.0013, "latencyMs": 6175 }, { "configuration": "1024×1024 · steps 20", "price": 0.0045, "latencyMs": 16846 }, { "configuration": "1024×1024 · steps 50", "price": 0.0102, "latencyMs": 20374 } ], "examples": [ { "id": "chicken-embryo-cutaway-workbook-illustration", "configuration": "inpaint · 896×1152", "price": 0.0045, "latencyMs": 19568 } ] } ``` A model billed by compute time has no `rates`. It carries `measured` instead, with the price of each configuration we ran. **Most of both kinds carry `examples`** as well, the runs behind those numbers. ### Reading a rate `amount` and `unit` are the price a program should calculate with. `display` is the same value written out for a person to read. **Token rates are stored per token and displayed per million.** An `amount` of `0.00001` on `inputToken` is `$10.00 per 1M input tokens`, which is what `display` says. `label` names the configuration the rate applies to, such as `720p` or `≤ 272K context`. **`after` means the rate only starts applying beyond that many units**, like the sixth reference image onwards. | Unit | One unit is | | --- | --- | | `output` | One generation, whatever it produced. | | `durationSecond` | One second of the video or audio returned. | | `computeSecond` | One second of GPU time. | | `step` | One inference step. | | `inputImage` | One image handed to the model. | | `inputMegapixel`, `outputMegapixel` | One megapixel in, or one megapixel out. | | `character`, `utf8Byte` | One character, or one byte, of the input text. | | `inputToken`, `outputToken` | One token read, or one token produced. | | `cachedInputToken`, `cacheWriteToken` | One input token served from the cache, or written into it. | **A `basis` field appears when the rates are not exactly what a request costs.** `token` means the bill follows how much the model produced, `passthrough` means the provider prices each job and the rates are typical, `floor` means a request that produces more than the rates cover is billed per token, and `plusTokens` means the prompt and any text answered with are billed on top. ### What the example prices are Examples are **real generations we ran and paid for**, with at least one for every mode the model supports. They are picked to cover the features of the model, from plain text to image up to editing with references, and each one carries the settings that produced it, its price and how long it took. **They are not averages, and they are not a sample of what other customers do.** For a request that matches none of them, take the rate and multiply, or run it once and read the cost it returns. > [!NOTE] > `examples.json` carries the full request body of each example next to its price. Sending that body back to the API runs the same request, so you can check the cost of a workflow before wiring it into your product. ## The cost of a request you send Add `includeCost` to any task and the response carries a `cost` field with the USD amount deducted for it. **TypeScript**: ```typescript import { createClient } from '@runware/sdk' const client = await createClient({ apiKey: process.env.RUNWARE_API_KEY }) await client.connect() const [result] = await client.run({ model: 'runware:z-image@0', positivePrompt: 'a red apple on a wooden table', width: 1024, height: 1024, includeCost: true }) ``` **Python**: ```python import asyncio import os from runware import Runware async def main(): async with Runware(api_key=os.environ["RUNWARE_API_KEY"]) as client: results = await client.run({ "model": "runware:z-image@0", "positivePrompt": "a red apple on a wooden table", "width": 1024, "height": 1024, "includeCost": True }) asyncio.run(main()) ``` **cURL**: ```bash curl https://api.runware.ai/v1 \ -H "Authorization: Bearer $RUNWARE_API_KEY" \ -H "Content-Type: application/json" \ -d '[ { "taskType": "imageInference", "taskUUID": "39d7207a-343e-4198-9c40-ef6d302cadb3", "model": "runware:z-image@0", "positivePrompt": "a red apple on a wooden table", "width": 1024, "height": 1024, "includeCost": true } ]' ``` **CLI**: ```bash runware run runware:z-image@0 \ positivePrompt="a red apple on a wooden table" \ width=1024 \ height=1024 \ includeCost=true ``` **JSON**: ```json { "taskType": "imageInference", "taskUUID": "39d7207a-343e-4198-9c40-ef6d302cadb3", "model": "runware:z-image@0", "positivePrompt": "a red apple on a wooden table", "width": 1024, "height": 1024, "includeCost": true } ``` **Failed generations are not charged.** You only pay for tasks that returned a result. ## Balance and payments All amounts are in USD. The [Dashboard](https://runware.ai/dashboard) is where you top up, turn on **auto-reload** so your balance refills when it falls below a threshold, set low balance alerts, and add a backup payment method. For high volume work, [talk to sales](https://runware.ai/contact) about custom pricing. --- ## Zero Data Retention - **URL:** https://runware.ai/docs/models-api/zero-data-retention - **Description:** What Runware keeps and deletes when Zero Data Retention is enabled on your organization, which models it covers, and how to work with outputs that expire. ## Introduction Zero Data Retention (ZDR) is an **organization-level option for enterprise accounts**. When it is on, Runware processes your prompts and input media to run each request and **keeps none of that content afterwards**. Generated outputs stay available only until their TTL expires. ZDR is enabled per organization by our team and **applies from the moment it is turned on**. Requests processed before that keep the retention they had. ## What is retained **Only the data needed to bill and operate the service is kept.** Everything you send is discarded, and everything a model generates is deleted once its `ttl` expires. | Data | Retention | | --- | --- | | **Prompts and text generations** | Not retained. Processed in memory for the duration of the request. | | **Input media** | Not retained. This covers input and reference images, masks, video frames and audio. | | **Generated media** | Deleted when the `ttl` of the request expires, 60 seconds by default. | | **Technical metadata** | Retained for billing, debugging, reliability monitoring and security auditing. | | **Billing records** | Retained as required by tax and accounting law. | | **Account and authentication data** | Retained for the life of the account plus any statutory retention period. | For language models with prompt caching, part of a prompt and its **KV cache can stay in memory** between requests. That cache is never written to disk, is evicted automatically, and is discarded when the replica restarts. **Runware never uses data sent through the API to train or improve models**, with or without ZDR. ## Covered models For image, video, audio and 3D, ZDR covers three groups of models: - **Runware-hosted models**, marked **Runware Optimized** in the [model catalog](https://runware.ai/models). - **Community and user-uploaded models**, which run on the same infrastructure as the hosted ones. - **All Black Forest Labs models**, both the open-weight FLUX models we host and the ones served through the Black Forest Labs API. For text, ZDR covers these language models: - DeepSeek-V4-Flash-0731 - DeepSeek-V4-Pro-0423 - DeepSeek-V4.1-Flash - [Gemma 4 31B](https://runware.ai/docs/models/google-gemma-4-31b) - GLM-5.2 - GLM-5.3 - GLM-5.3-Flash - gpt-oss-120b - gpt-oss-safeguard-20b - Kimi K3 - Shieldstral 1.0 3B Any other model is **not covered by ZDR today**, even when your organization has it enabled. Coverage for models served by other providers depends on an agreement with each provider, and **more models can be added on request**. If the model you need is not listed, [contact Sales](https://runware.ai/contact-sales) to ask about it. ## Working with outputs Without ZDR, output URLs stay available for 7 days. With ZDR, **the file behind an output URL is deleted when the `ttl` expires**. The default is 60 seconds, and you can set a longer one with the `ttl` parameter of each request. Download the result before it expires. **Asynchronous requests** follow the same clock. `getResponse` keeps returning the finished task after the `ttl` expires, but the URL in it no longer resolves, so poll and download within the window. **Webhooks** deliver the result as soon as it is ready, and the same deadline applies to the URL they carry. To skip the URL entirely, request `base64Data` or `dataURI` as the `outputType`. **The output comes back inside the response and no file is stored**, so there is nothing to fetch or expire. ## What changes in the dashboard The usage log keeps the metadata of each task, such as its UUID, model, date and cost. **Request and response payloads are not stored**, so the log can't show what you sent and **reusing a past request is not available**. The Playground still generates, but past generations are not saved. ## Enabling ZDR ZDR is enabled per organization on request. [Contact Sales](https://runware.ai/contact-sales) to turn it on for yours. --- ## Model Search API - **URL:** https://runware.ai/docs/models-api/model-search - **Description:** Search and discover AI models available in the Runware platform. Filter and find the right model for your generation tasks. ## Introduction The Model Search API enables discovery of available models on the Runware platform, providing search and filtering capabilities across **public models from the community** and **private models within your organization**. Models discovered through this API can be used immediately in generation tasks **by referencing their AIR identifiers**. This enables dynamic model selection in applications and helps discover new models for specific use cases. The search works across model names, versions, tags, and other metadata. Multiple filters can be combined to narrow results by category, type, architecture, and visibility. Results are returned in a **paginated format** with a default of 20 models per page, controlled by the `limit` and `offset` parameters. ## Request The Runware API always accepts an array of objects as input, where each object represents a **specific task to be performed**. The structure of the object varies depending on the type of the task. For this section, we will focus on the parameters related to the **model search task**. The following JSON snippet shows the basic structure of a request object. **TypeScript**: ```typescript import { createClient } from '@runware/sdk' const client = await createClient({ apiKey: process.env.RUNWARE_API_KEY }) await client.connect() const result = await client.modelSearch({ search: 'realistic', tags: 'photorealistic', category: 'checkpoint', type: 'base', architecture: 'sdxl', visibility: 'all', offset: 0, limit: 20 }) ``` **Python**: ```python import asyncio import os from runware import Runware async def main(): async with Runware(api_key=os.environ["RUNWARE_API_KEY"]) as client: result = await client.model_search({ "search": "realistic", "tags": "photorealistic", "category": "checkpoint", "type": "base", "architecture": "sdxl", "visibility": "all", "offset": 0, "limit": 20 }) asyncio.run(main()) ``` **cURL**: ```bash curl https://api.runware.ai/v1 \ -H "Authorization: Bearer $RUNWARE_API_KEY" \ -H "Content-Type: application/json" \ -d '[ { "taskType": "modelSearch", "taskUUID": "50836053-a0ee-4cf5-b9d6-ae7c5d140ada", "search": "realistic", "tags": "photorealistic", "category": "checkpoint", "type": "base", "architecture": "sdxl", "visibility": "all", "offset": 0, "limit": 20 } ]' ``` **CLI**: ```bash runware model search \ -q realistic \ --tags photorealistic \ --category checkpoint \ --type base \ --architecture sdxl \ --visibility all \ --offset 0 \ --limit 20 ``` **JSON**: ```json { "taskType": "modelSearch", "taskUUID": "50836053-a0ee-4cf5-b9d6-ae7c5d140ada", "search": "realistic", "tags": "photorealistic", "category": "checkpoint", "type": "base", "architecture": "sdxl", "visibility": "all", "offset": 0, "limit": 20 } ``` --- ### [taskType](https://runware.ai/docs/models-api/model-search#request-tasktype) - **Type**: `string` - **Required**: true - **Value**: `modelSearch` Identifier for the type of task being performed. ### [taskUUID](https://runware.ai/docs/models-api/model-search#request-taskuuid) - **Type**: `string` - **Required**: true - **Format**: `UUID v4` UUID v4 identifier for tracking tasks and matching async responses. Must be unique per task. ### [search](https://runware.ai/docs/models-api/model-search#request-search) - **Type**: `string` - **Max**: `48` Search query to find models by name, description or AIR ID. ### [source](https://runware.ai/docs/models-api/model-search#request-source) - **Type**: `string` Filter by model source. **Allowed values**: `official` `community` ### [category](https://runware.ai/docs/models-api/model-search#request-category) - **Type**: `string` Filter models by category. **Allowed values**: `checkpoint` `lora` `lycoris` `vae` `embeddings` ### [architecture](https://runware.ai/docs/models-api/model-search#request-architecture) - **Type**: `string` Filter by model architecture. ### [capabilities](https://runware.ai/docs/models-api/model-search#request-capabilities) - **Type**: `array of strings` Filter by model capabilities. ### [visibility](https://runware.ai/docs/models-api/model-search#request-visibility) - **Type**: `string` Filter by visibility status. **Allowed values**: `public` `private` `favorite` `owned` ### [limit](https://runware.ai/docs/models-api/model-search#request-limit) - **Type**: `integer` - **Min**: `1` - **Max**: `100` - **Default**: `20` Maximum number of results to return. ### [offset](https://runware.ai/docs/models-api/model-search#request-offset) - **Type**: `integer` - **Min**: `0` - **Default**: `0` Number of results to skip for pagination. ### [sort](https://runware.ai/docs/models-api/model-search#request-sort) - **Type**: `string` Sort order for results. A bare field name sorts ascending and a `-` prefix sorts descending, except `popularity`, whose bare value is already descending (most popular first). `_score` sorts by search relevance and has no descending form. Defaults to `_score` when `search` is non-empty, and to `popularity` otherwise. **Allowed values**: `_score` `popularity` `-popularity` `name` `-name` `addedUnixTimestamp` `-addedUnixTimestamp` `updatedDateUnixTimestamp` `-updatedDateUnixTimestamp` ## Response Results will be delivered in the format below. ```json { "data": [ { "results": [ { "name": "Promissing_Realistic_XL", "air": "civitai:305149@392545", "tags": [ "photorealistic", "base model", "sci-fi", "photo", "woman", "fantasy", "photorealism", "rpg", "general use", "close up", "close up shot", "promissing_realistic_xl" ], "heroImage": "https://mim.runware.ai/r/66a70a0bb7c38-450x450.jpg", "category": "checkpoint", "private": false, "comment": "", "version": "v22", "architecture": "sdxl", "type": "base", "defaultWidth": 1024, "defaultHeight": 1024, "defaultSteps": 20, "defaultScheduler": "Default", "defaultCFG": 7.5 } ], "taskUUID": "50836053-a0ee-4cf5-b9d6-ae7c5d140ada", "taskType": "modelSearch", "totalResults": 2 } ] } ``` --- ### [taskType](https://runware.ai/docs/models-api/model-search#response-tasktype) - **Type**: `string` - **Required**: true - **Value**: `modelSearch` Identifier for the type of task this response belongs to. ### [taskUUID](https://runware.ai/docs/models-api/model-search#response-taskuuid) - **Type**: `string` - **Required**: true - **Format**: `UUID v4` UUID v4 identifier echoed from the original request, used to match async responses to their tasks. ### [totalResults](https://runware.ai/docs/models-api/model-search#response-totalresults) - **Type**: `integer` - **Required**: true - **Min**: `0` Total number of models matching the search criteria. ### [results](https://runware.ai/docs/models-api/model-search#response-results) - **Path**: `results.air` - **Type**: `array of objects (13 properties)` - **Required**: true List of models found. #### [air](https://runware.ai/docs/models-api/model-search#response-results-air) - **Path**: `results.air` - **Type**: `string` - **Required**: true Artificial Intelligence Resource identifier. #### [name](https://runware.ai/docs/models-api/model-search#response-results-name) - **Path**: `results.name` - **Type**: `string` - **Required**: true Model name. #### [category](https://runware.ai/docs/models-api/model-search#response-results-category) - **Path**: `results.category` - **Type**: `string` - **Required**: true Model category. **Possible values**: `checkpoint` `lora` `lycoris` `vae` `embeddings` #### [architecture](https://runware.ai/docs/models-api/model-search#response-results-architecture) - **Path**: `results.architecture` - **Type**: `string | null` - **Required**: true Model architecture. #### [capabilities](https://runware.ai/docs/models-api/model-search#response-results-capabilities) - **Path**: `results.capabilities` - **Type**: `array of strings` - **Required**: true Model capabilities. #### [source](https://runware.ai/docs/models-api/model-search#response-results-source) - **Path**: `results.source` - **Type**: `string` - **Required**: true Model source. **Possible values**: `official` `community` #### [heroImage](https://runware.ai/docs/models-api/model-search#response-results-heroimage) - **Path**: `results.heroImage` - **Type**: `string | null` - **Required**: true - **Format**: `uri` Representative image URL. #### [private](https://runware.ai/docs/models-api/model-search#response-results-private) - **Path**: `results.private` - **Type**: `boolean` - **Required**: true Whether the model is private. #### [isFavorite](https://runware.ai/docs/models-api/model-search#response-results-isfavorite) - **Path**: `results.isFavorite` - **Type**: `boolean` Whether the model is favorited. #### [provider](https://runware.ai/docs/models-api/model-search#response-results-provider) - **Path**: `results.provider` - **Type**: `string` Model provider. #### [shortDescription](https://runware.ai/docs/models-api/model-search#response-results-shortdescription) - **Path**: `results.shortDescription` - **Type**: `string` Short description. #### [positiveTriggerWords](https://runware.ai/docs/models-api/model-search#response-results-positivetriggerwords) - **Path**: `results.positiveTriggerWords` - **Type**: `string` Positive trigger words. #### [negativeTriggerWords](https://runware.ai/docs/models-api/model-search#response-results-negativetriggerwords) - **Path**: `results.negativeTriggerWords` - **Type**: `string` Negative trigger words. --- ## Model Upload - **URL:** https://runware.ai/docs/models-api/model-upload - **Description:** Upload and manage your custom AI models on the Runware platform. Integrate your own checkpoints, LoRAs, and other model types into your workflow. ## Introduction The Model Upload API lets you integrate **custom models** into the Runware platform. Upload your own checkpoints, LoRAs, or other supported model types and use them in generation tasks just like any other model on the platform. Uploaded models are automatically **optimized for the Sonic Inference Engine®**, enhancing speed and efficiency without compromising output quality. Once processed, models are distributed across our infrastructure and can be referenced by their assigned identifiers in any API request. ### Supported model categories - **Checkpoints**: Base models across multiple architectures including Stable Diffusion (1.x, 2.x, XL, 3.x) and FLUX. - **LoRAs**: Low-Rank Adaptation models for style and concept fine-tuning. - **LyCORIS**: An advanced alternative to LoRA for model fine-tuning. - **VAE**: Variational Autoencoder models for image encoding and decoding. - **Embeddings**: Textual Inversion embeddings for custom concepts and styles. ### Visibility and versioning **You control who can reach each model**: public makes it available to all platform users, private restricts it to your organization. The API also keeps multiple versions of the same model, so you can iterate on weights or configuration without losing the history. ### Storage pricing Model upload is currently in **beta and free of charge**. There are no costs for uploading or storing models during this period. After the beta period, storage will be charged at **$0.05 per GB per month**, rounded up to the nearest GB and calculated daily. We will not retroactively charge for storage used during the beta. A positive account balance is required to upload new models. ## Request The Runware API always accepts an array of objects as input, where each object represents a **specific task to be performed**. The structure of the object varies depending on the type of the task. For this section, we will focus on the parameters related to the **model upload task**. The following JSON snippet shows the basic structure of a request object. **TypeScript**: ```typescript import { createClient } from '@runware/sdk' const client = await createClient({ apiKey: process.env.RUNWARE_API_KEY }) await client.connect() const result = await client.modelUpload({ category: 'checkpoint', architecture: 'flux', format: 'safetensors', air: 'myorg:42@1', uniqueIdentifier: 'abc123def456', name: 'My Custom Model', version: 'v1', downloadURL: 'https://example.com/models/my-model.safetensors', private: true }) ``` **Python**: ```python import asyncio import os from runware import Runware async def main(): async with Runware(api_key=os.environ["RUNWARE_API_KEY"]) as client: result = await client.model_upload({ "category": "checkpoint", "architecture": "flux", "format": "safetensors", "air": "myorg:42@1", "uniqueIdentifier": "abc123def456", "name": "My Custom Model", "version": "v1", "downloadURL": "https://example.com/models/my-model.safetensors", "private": True }) asyncio.run(main()) ``` **cURL**: ```bash curl https://api.runware.ai/v1 \ -H "Authorization: Bearer $RUNWARE_API_KEY" \ -H "Content-Type: application/json" \ -d '[ { "taskType": "modelUpload", "taskUUID": "b92ea202-349f-4560-adae-abb55a8146ee", "category": "checkpoint", "architecture": "flux", "format": "safetensors", "air": "myorg:42@1", "uniqueIdentifier": "abc123def456", "name": "My Custom Model", "version": "v1", "downloadURL": "https://example.com/models/my-model.safetensors", "private": true } ]' ``` **CLI**: ```bash runware model upload \ --category checkpoint \ --architecture flux \ --format safetensors \ --air myorg:42@1 \ --unique-identifier abc123def456 \ --name "My Custom Model" \ --version v1 \ --download-url https://example.com/models/my-model.safetensors \ --private true ``` **JSON**: ```json { "taskType": "modelUpload", "taskUUID": "b92ea202-349f-4560-adae-abb55a8146ee", "category": "checkpoint", "architecture": "flux", "format": "safetensors", "air": "myorg:42@1", "uniqueIdentifier": "abc123def456", "name": "My Custom Model", "version": "v1", "downloadURL": "https://example.com/models/my-model.safetensors", "private": true } ``` --- ### [taskType](https://runware.ai/docs/models-api/model-upload#request-tasktype) - **Type**: `string` - **Required**: true - **Value**: `modelUpload` Identifier for the type of task being performed. ### [taskUUID](https://runware.ai/docs/models-api/model-upload#request-taskuuid) - **Type**: `string` - **Required**: true - **Format**: `UUID v4` UUID v4 identifier for tracking tasks and matching async responses. Must be unique per task. ### [category](https://runware.ai/docs/models-api/model-upload#request-category) - **Type**: `string` - **Required**: true Category of the model. **Allowed values**: `checkpoint` `lora` `lycoris` `vae` `embeddings` ### [format](https://runware.ai/docs/models-api/model-upload#request-format) - **Type**: `string` - **Required**: true Format of the model file. **Allowed values**: `safetensors` ### [air](https://runware.ai/docs/models-api/model-upload#request-air) - **Type**: `string` Artificial Intelligence Resource identifier. Format: `provider:model@version`. ### [uniqueIdentifier](https://runware.ai/docs/models-api/model-upload#request-uniqueidentifier) - **Type**: `string` Unique identifier for the model. ### [name](https://runware.ai/docs/models-api/model-upload#request-name) - **Type**: `string` - **Required**: true Name of the model. ### [version](https://runware.ai/docs/models-api/model-upload#request-version) - **Type**: `string` - **Required**: true Version of the model. ### [downloadURL](https://runware.ai/docs/models-api/model-upload#request-downloadurl) - **Type**: `string` - **Required**: true - **Format**: `uri` URL where the model file is hosted. ### [private](https://runware.ai/docs/models-api/model-upload#request-private) - **Type**: `boolean` - **Default**: `true` Whether the model should be private. ### [heroImageURL](https://runware.ai/docs/models-api/model-upload#request-heroimageurl) - **Type**: `string` - **Format**: `uri` URL of the hero image. ### [tags](https://runware.ai/docs/models-api/model-upload#request-tags) - **Type**: `array of strings` Tags associated with the model. ### [shortDescription](https://runware.ai/docs/models-api/model-upload#request-shortdescription) - **Type**: `string` Short description of the model. ### [comment](https://runware.ai/docs/models-api/model-upload#request-comment) - **Type**: `string` Additional comments or notes. ### Checkpoints When `category` is set to `checkpoint`, the following additional parameters are available: ### [type](https://runware.ai/docs/models-api/model-upload#request-type) - **Type**: `string` Type of the model (specific to category). **Allowed values**: `base` `inpainting` ### [architecture](https://runware.ai/docs/models-api/model-upload#request-architecture) - **Type**: `string` - **Required**: true Architecture of the model. **Allowed values**: `exactlyai_image` `flux1d` `flux1s` `fluxkontextdev` `illustrious` `noobai` `pony` `sd1x` `sdxl` `sdxllightning` `sdxlturbo` `z_image` `z_image_turbo` ### [defaultScheduler](https://runware.ai/docs/models-api/model-upload#request-defaultscheduler) - **Type**: `string` Default scheduler. ### [defaultSteps](https://runware.ai/docs/models-api/model-upload#request-defaultsteps) - **Type**: `integer` - **Min**: `1` Default number of inference steps. ### [defaultCFG](https://runware.ai/docs/models-api/model-upload#request-defaultcfg) - **Type**: `float` - **Min**: `0` Default classifier-free guidance scale. ### [defaultStrength](https://runware.ai/docs/models-api/model-upload#request-defaultstrength) - **Type**: `float` - **Min**: `0` - **Max**: `1` Default strength for img2img. ### LoRAs When `category` is set to `lora`, the following additional parameters are available: ### [type](https://runware.ai/docs/models-api/model-upload#request-type) - **Type**: `string` Type of the model (specific to category). **Allowed values**: `positive` `negative` ### [architecture](https://runware.ai/docs/models-api/model-upload#request-architecture) - **Type**: `string` - **Required**: true Architecture of the model. **Allowed values**: `flux1d` `flux1s` `flux2klein_4b` `flux2klein_9b` `flux2klein_base_4b` `flux2klein_base_9b` `flux_2_dev` `fluxkontextdev` `hidreamdev` `hidreamfast` `hidreamfull` `illustrious` `ltx_2_3_video` `noobai` `pony` `qwen_image` `qwen_image_edit` `qwen_image_edit_plus` `qwen_image_layered` `sd1x` `sd3` `sdxl` `sdxllightning` `sdxlturbo` `z_image` `z_image_turbo` ### [defaultWeight](https://runware.ai/docs/models-api/model-upload#request-defaultweight) - **Type**: `float` Default weight for the model. ### [positiveTriggerWords](https://runware.ai/docs/models-api/model-upload#request-positivetriggerwords) - **Type**: `string` List of positive trigger words. ### LyCORIS When `category` is set to `lycoris`, the following additional parameters are available: ### [type](https://runware.ai/docs/models-api/model-upload#request-type) - **Type**: `string` Type of the model (specific to category). **Allowed values**: `positive` `negative` ### [architecture](https://runware.ai/docs/models-api/model-upload#request-architecture) - **Type**: `string` - **Required**: true Architecture of the model. **Allowed values**: `flux1d` `flux1s` `flux2klein_4b` `flux2klein_9b` `flux2klein_base_4b` `flux2klein_base_9b` `flux_2_dev` `fluxkontextdev` `hidreamdev` `hidreamfast` `hidreamfull` `illustrious` `noobai` `pony` `qwen_image` `qwen_image_edit` `qwen_image_edit_plus` `qwen_image_layered` `sd1x` `sd3` `sdxl` `sdxllightning` `sdxlturbo` `z_image` `z_image_turbo` ### [defaultWeight](https://runware.ai/docs/models-api/model-upload#request-defaultweight) - **Type**: `float` Default weight for the model. ### [positiveTriggerWords](https://runware.ai/docs/models-api/model-upload#request-positivetriggerwords) - **Type**: `string` List of positive trigger words. ### VAE When `category` is set to `vae`, the following additional parameters are available: ### [architecture](https://runware.ai/docs/models-api/model-upload#request-architecture) - **Type**: `string` - **Required**: true Architecture of the model. **Allowed values**: `illustrious` `noobai` `pony` `sd1x` `sdxl` `sdxllightning` `sdxlturbo` ### Embeddings When `category` is set to `embeddings`, the following additional parameters are available: ### [type](https://runware.ai/docs/models-api/model-upload#request-type) - **Type**: `string` Type of the model (specific to category). **Allowed values**: `positive` `negative` ### [architecture](https://runware.ai/docs/models-api/model-upload#request-architecture) - **Type**: `string` - **Required**: true Architecture of the model. **Allowed values**: `illustrious` `noobai` `pony` `sd1x` `sdxl` `sdxllightning` `sdxlturbo` ## Response The API **streams a sequence of status messages** as your model progresses through the upload pipeline. Each message uses the same structure but indicates the current processing phase: 1. **Validated**: Model parameters and configuration have been verified. 2. **Downloaded**: Model file has been retrieved from the provided URL. 3. **Optimized**: Model has been optimized for the Sonic Inference Engine. 4. **Stored**: Model has been uploaded to distributed storage. 5. **Ready**: Model is deployed and available for use in generation tasks. ```json { "data": [ { "taskType": "modelUpload", "taskUUID": "b92ea202-349f-4560-adae-abb55a8146ee", "status": "ready", "message": "Model successfully deployed and ready for use.", "air": "myorg:42@1" } ] } ``` --- ### [taskType](https://runware.ai/docs/models-api/model-upload#response-tasktype) - **Type**: `string` - **Value**: `modelUpload` Identifier for the type of task this response belongs to. ### [taskUUID](https://runware.ai/docs/models-api/model-upload#response-taskuuid) - **Type**: `string` - **Required**: true - **Format**: `UUID v4` UUID v4 identifier echoed from the original request, used to match async responses to their tasks. ### [status](https://runware.ai/docs/models-api/model-upload#response-status) - **Type**: `string` - **Required**: true Status of the upload operation phase. **Possible values**: `validated` `downloaded` `optimized` `stored` `ready` `failed` ### [message](https://runware.ai/docs/models-api/model-upload#response-message) - **Type**: `string` - **Required**: true Status message or error details. ### [air](https://runware.ai/docs/models-api/model-upload#response-air) - **Type**: `string` The AIR identifier of the uploaded model. --- ## Account Management - **URL:** https://runware.ai/docs/models-api/account-management - **Description:** Retrieve account details, team members, API keys, and usage stats (spend, performance, errors) for your organization with the account management API. ## Introduction The `accountManagement` task **reads your organization's account data over the API**: the `team` and their roles, your API keys, the current `balance`, and usage statistics. Reach for it whenever a script needs account state that would otherwise mean opening the web console, like billing automation or a usage alert. Everything runs through the `operation` parameter: it selects the dataset and **shapes both the request and the response**. Each operation is documented in its own section below. | Operation | Returns | | --- | --- | | `getDetails` | Organization info, team, API keys, and rolling usage totals. | | `getUsageActivity` | Requests and spend over a date range, broken down by day, model, and/or API key. | | `getUsagePerformance` | Per-model inference-time percentiles over a date range. | | `getUsageErrors` | Client (`4xx`) and server (`5xx`) error counts over a date range. | The three usage operations share the same request parameters (a date window plus optional filters) and the same `usage` response envelope, **differing only in the metrics each row reports**. ## getDetails Everything about the account in one call, with **no date range or filters**. The response carries the organization identity, the current `balance`, the full `team` roster with roles, and every API key with its lifetime request count. The `usage` object here holds **rolling totals** rather than a time breakdown: credits and requests for `today`, `last7Days`, `last30Days`, and lifetime `total`. Use `getDetails` for a point-in-time picture of the account, and the operations below when you need consumption sliced across a date range. ### Request **TypeScript**: ```typescript import { createClient } from '@runware/sdk' const client = await createClient({ apiKey: process.env.RUNWARE_API_KEY }) await client.connect() const result = await client.accountManagement({ operation: 'getDetails' }) ``` **Python**: ```python import asyncio import os from runware import Runware async def main(): async with Runware(api_key=os.environ["RUNWARE_API_KEY"]) as client: result = await client.account_management({ "operation": "getDetails" }) asyncio.run(main()) ``` **cURL**: ```bash curl https://api.runware.ai/v1 \ -H "Authorization: Bearer $RUNWARE_API_KEY" \ -H "Content-Type: application/json" \ -d '[ { "taskType": "accountManagement", "taskUUID": "f4dd3dfe-955f-49d5-a785-7e3b633d6e7a", "operation": "getDetails" } ]' ``` **CLI**: ```bash runware account details ``` **JSON**: ```json { "taskType": "accountManagement", "taskUUID": "f4dd3dfe-955f-49d5-a785-7e3b633d6e7a", "operation": "getDetails" } ``` --- ### [taskType](https://runware.ai/docs/models-api/account-management#request-tasktype) - **Type**: `string` - **Required**: true - **Value**: `accountManagement` Identifier for the type of task being performed. ### [taskUUID](https://runware.ai/docs/models-api/account-management#request-taskuuid) - **Type**: `string` - **Required**: true - **Format**: `UUID v4` UUID v4 identifier for tracking tasks and matching async responses. Must be unique per task. ### [operation](https://runware.ai/docs/models-api/account-management#request-operation) - **Type**: `string` - **Required**: true - **Value**: `getDetails` The specific account management operation to perform. ### Response ```json { "data": [ { "taskType": "accountManagement", "taskUUID": "f4dd3dfe-955f-49d5-a785-7e3b633d6e7a", "operation": "getDetails", "organizationUUID": "a6379343-9ff2-46a0-996b-e4a7b3057c88", "organizationName": "Acme Corporation", "balance": { "amount": 2450.75, "freeBalance": 120.00, "currency": "USD" }, "team": [ { "name": "John Smith", "email": "john.smith@acme.com", "roles": ["Owner"], "joinedAt": "2024-01-15T10:30:00Z" } ], "apiKeys": [ { "name": "Production API Key", "apiKey": "YHluz4gk5KU4ZZWr****************", "enabled": true, "createdAt": "2024-01-20T11:00:00Z", "requests": 15420, "lastUsedAt": "2025-10-12T08:45:30Z" } ], "usage": { "today": { "credits": 35.80, "requests": 1850 }, "last7Days": { "credits": 412.25, "requests": 21400 }, "last30Days": { "credits": 1685.90, "requests": 87560 }, "total": { "credits": 48920.50, "requests": 2540318 } } } ] } ``` --- ### [taskType](https://runware.ai/docs/models-api/account-management#response-tasktype) - **Type**: `string` - **Required**: true - **Value**: `accountManagement` Identifier for the type of task this response belongs to. ### [taskUUID](https://runware.ai/docs/models-api/account-management#response-taskuuid) - **Type**: `string` - **Required**: true - **Format**: `UUID v4` UUID v4 identifier echoed from the original request, used to match async responses to their tasks. ### [operation](https://runware.ai/docs/models-api/account-management#response-operation) - **Type**: `string` - **Required**: true - **Value**: `getDetails` The account management operation that produced this response. ### [organizationName](https://runware.ai/docs/models-api/account-management#response-organizationname) - **Type**: `string` The name of the organization. ### [organizationUUID](https://runware.ai/docs/models-api/account-management#response-organizationuuid) - **Type**: `string` - **Format**: `UUID v4` Unique identifier for the organization. ### [balance](https://runware.ai/docs/models-api/account-management#response-balance) - **Path**: `balance.amount` - **Type**: `object (3 properties)` Current account balance and currency. #### [amount](https://runware.ai/docs/models-api/account-management#response-balance-amount) - **Path**: `balance.amount` - **Type**: `float` - **Required**: true Current balance amount. #### [freeBalance](https://runware.ai/docs/models-api/account-management#response-balance-freebalance) - **Path**: `balance.freeBalance` - **Type**: `float` Available free credit balance. #### [currency](https://runware.ai/docs/models-api/account-management#response-balance-currency) - **Path**: `balance.currency` - **Type**: `string` - **Required**: true Currency code. ### [team](https://runware.ai/docs/models-api/account-management#response-team) - **Path**: `team.name` - **Type**: `array of objects (4 properties)` List of team members. #### [name](https://runware.ai/docs/models-api/account-management#response-team-name) - **Path**: `team.name` - **Type**: `string` - **Required**: true Full name of the team member. #### [email](https://runware.ai/docs/models-api/account-management#response-team-email) - **Path**: `team.email` - **Type**: `string` - **Required**: true - **Format**: `email` Email address of the team member. #### [roles](https://runware.ai/docs/models-api/account-management#response-team-roles) - **Path**: `team.roles` - **Type**: `array of strings` - **Required**: true Each team member is assigned a role that determines their level of access within the organization. | Capability | Owner | Admin | Developer | | --- | --- | --- | --- | | API generation and Playground | ✓ | ✓ | ✓ | | Manage Playground workflows | ✓ | ✓ | ✓ | | Create and manage API keys | ✓ | ✓ | | | View API logs and usage analytics | ✓ | ✓ | | | Manage billing and payment methods | ✓ | ✓ | | | Invite and remove team members | ✓ | ✓ | | | Assign Admin and Developer roles | ✓ | ✓ | | | Assign Owner role | ✓ | | | | Delete organization | ✓ | | | #### [joinedAt](https://runware.ai/docs/models-api/account-management#response-team-joinedat) - **Path**: `team.joinedAt` - **Type**: `string` - **Format**: `date-time` Date and time when the member joined. ### [apiKeys](https://runware.ai/docs/models-api/account-management#response-apikeys) - **Path**: `apiKeys.apiKey` - **Type**: `array of objects (7 properties)` List of API keys associated with the account. #### [apiKey](https://runware.ai/docs/models-api/account-management#response-apikeys-apikey) - **Path**: `apiKeys.apiKey` - **Type**: `string` - **Required**: true The API key string (partially masked). #### [name](https://runware.ai/docs/models-api/account-management#response-apikeys-name) - **Path**: `apiKeys.name` - **Type**: `string` - **Required**: true Name or label for the API key. #### [description](https://runware.ai/docs/models-api/account-management#response-apikeys-description) - **Path**: `apiKeys.description` - **Type**: `string` Description of the API key. #### [enabled](https://runware.ai/docs/models-api/account-management#response-apikeys-enabled) - **Path**: `apiKeys.enabled` - **Type**: `boolean` - **Required**: true Whether the API key is active. #### [createdAt](https://runware.ai/docs/models-api/account-management#response-apikeys-createdat) - **Path**: `apiKeys.createdAt` - **Type**: `string` - **Required**: true - **Format**: `date-time` Date and time when the key was created. #### [lastUsedAt](https://runware.ai/docs/models-api/account-management#response-apikeys-lastusedat) - **Path**: `apiKeys.lastUsedAt` - **Type**: `string` - **Format**: `date-time` Date and time when the key was last used. #### [requests](https://runware.ai/docs/models-api/account-management#response-apikeys-requests) - **Path**: `apiKeys.requests` - **Type**: `integer` Total number of requests made with this key. ### [usage](https://runware.ai/docs/models-api/account-management#response-usage) - **Path**: `usage.today` - **Type**: `object (12 properties)` Account usage statistics. #### [today](https://runware.ai/docs/models-api/account-management#response-usage-today) - **Path**: `usage.today` - **Type**: `object (2 properties)` Usage stats for today. ##### [credits](https://runware.ai/docs/models-api/account-management#response-usage-today-credits) - **Path**: `usage.today.credits` - **Type**: `float` - **Required**: true Total credits consumed. ##### [requests](https://runware.ai/docs/models-api/account-management#response-usage-today-requests) - **Path**: `usage.today.requests` - **Type**: `integer` - **Required**: true Total API requests made. #### [last7Days](https://runware.ai/docs/models-api/account-management#response-usage-last7days) - **Path**: `usage.last7Days` - **Type**: `object (2 properties)` Usage stats for the last 7 days. ##### [credits](https://runware.ai/docs/models-api/account-management#response-usage-last7days-credits) - **Path**: `usage.last7Days.credits` - **Type**: `float` - **Required**: true Total credits consumed. ##### [requests](https://runware.ai/docs/models-api/account-management#response-usage-last7days-requests) - **Path**: `usage.last7Days.requests` - **Type**: `integer` - **Required**: true Total API requests made. #### [last30Days](https://runware.ai/docs/models-api/account-management#response-usage-last30days) - **Path**: `usage.last30Days` - **Type**: `object (2 properties)` Usage stats for the last 30 days. ##### [credits](https://runware.ai/docs/models-api/account-management#response-usage-last30days-credits) - **Path**: `usage.last30Days.credits` - **Type**: `float` - **Required**: true Total credits consumed. ##### [requests](https://runware.ai/docs/models-api/account-management#response-usage-last30days-requests) - **Path**: `usage.last30Days.requests` - **Type**: `integer` - **Required**: true Total API requests made. #### [total](https://runware.ai/docs/models-api/account-management#response-usage-total) - **Path**: `usage.total` - **Type**: `object (2 properties)` Total lifetime usage stats. ##### [credits](https://runware.ai/docs/models-api/account-management#response-usage-total-credits) - **Path**: `usage.total.credits` - **Type**: `float` - **Required**: true Total credits consumed. ##### [requests](https://runware.ai/docs/models-api/account-management#response-usage-total-requests) - **Path**: `usage.total.requests` - **Type**: `integer` - **Required**: true Total API requests made. ## getUsageActivity How much the account spent and how many requests it ran, over the window you set with `startDate` and `endDate`. This is the call behind a **usage dashboard** or a **monthly billing report**. `groupBy` controls how the totals are sliced. Ask for `date` and you get a `timeseries` of per-day rows. Ask for `model` or `apiKey` and the same totals come back **split by that dimension**, and you can request several at once. Each slice lands under `usage` as its own breakdown: a `data` array with one row per bucket (`count` and `spend`), plus a `meta` roll-up that totals the window and projects a 30-day spend. ### Request **TypeScript**: ```typescript import { createClient } from '@runware/sdk' const client = await createClient({ apiKey: process.env.RUNWARE_API_KEY }) await client.connect() const result = await client.accountManagement({ operation: 'getUsageActivity', startDate: '2026-07-01', endDate: '2026-07-06', groupBy: [ 'date', 'model' ], timezone: 'America/New_York' }) ``` **Python**: ```python import asyncio import os from runware import Runware async def main(): async with Runware(api_key=os.environ["RUNWARE_API_KEY"]) as client: result = await client.account_management({ "operation": "getUsageActivity", "startDate": "2026-07-01", "endDate": "2026-07-06", "groupBy": [ "date", "model" ], "timezone": "America/New_York" }) asyncio.run(main()) ``` **cURL**: ```bash curl https://api.runware.ai/v1 \ -H "Authorization: Bearer $RUNWARE_API_KEY" \ -H "Content-Type: application/json" \ -d '[ { "taskType": "accountManagement", "taskUUID": "b7e0a3f2-3c1a-4d9e-8f2b-1a2c3d4e5f60", "operation": "getUsageActivity", "startDate": "2026-07-01", "endDate": "2026-07-06", "groupBy": [ "date", "model" ], "timezone": "America/New_York" } ]' ``` **CLI**: ```bash runware account getUsageActivity ``` **JSON**: ```json { "taskType": "accountManagement", "taskUUID": "b7e0a3f2-3c1a-4d9e-8f2b-1a2c3d4e5f60", "operation": "getUsageActivity", "startDate": "2026-07-01", "endDate": "2026-07-06", "groupBy": [ "date", "model" ], "timezone": "America/New_York" } ``` --- ### [taskType](https://runware.ai/docs/models-api/account-management#request-tasktype) - **Type**: `string` - **Required**: true - **Value**: `accountManagement` Identifier for the type of task being performed. ### [taskUUID](https://runware.ai/docs/models-api/account-management#request-taskuuid) - **Type**: `string` - **Required**: true - **Format**: `UUID v4` UUID v4 identifier for tracking tasks and matching async responses. Must be unique per task. ### [operation](https://runware.ai/docs/models-api/account-management#request-operation) - **Type**: `string` - **Required**: true - **Value**: `getUsageActivity` The specific account management operation to perform. ### [startDate](https://runware.ai/docs/models-api/account-management#request-startdate) - **Type**: `string` - **Format**: `date` Start of the usage window (inclusive). ### [endDate](https://runware.ai/docs/models-api/account-management#request-enddate) - **Type**: `string` - **Format**: `date` End of the usage window (inclusive). Must be on or after startDate, and the span must not exceed 30 days. ### [models](https://runware.ai/docs/models-api/account-management#request-models) - **Type**: `array of strings` - **Max items**: `100` Restrict usage to these model AIRs. Defaults to all models. ### [apiKeys](https://runware.ai/docs/models-api/account-management#request-apikeys) - **Type**: `array of strings` - **Max items**: `100` Restrict usage to these API key UUIDs. Defaults to all keys. ### [groupBy](https://runware.ai/docs/models-api/account-management#request-groupby) - **Type**: `array of strings` - **Default**: `date,model` Breakdowns to return. ### [timezone](https://runware.ai/docs/models-api/account-management#request-timezone) - **Type**: `string` - **Default**: `UTC` IANA timezone name used for day-bucketing. ### Response ```json { "data": [ { "taskType": "accountManagement", "taskUUID": "b7e0a3f2-3c1a-4d9e-8f2b-1a2c3d4e5f60", "operation": "getUsageActivity", "startDate": "2026-07-01", "endDate": "2026-07-06", "usage": { "timeseries": { "data": [{ "date": "2026-07-01", "count": 340, "spend": 120.05154 }], "meta": { "totalRequests": 1197, "totalResults": 1197, "totalSpend": 493.7819, "avgDailySpend": 87.37, "projectedSpend": 2708.55 } }, "model": { "data": [{ "date": "2026-07-01", "model": "google:gemini@omni-flash-1.1", "modelName": "Gemini Omni Flash 1.1", "count": 207, "spend": 101.457393 }], "meta": { "totalRequests": 1197, "totalResults": 1197, "totalSpend": 493.7819, "avgDailySpend": 87.37, "projectedSpend": 2708.55 } } } } ] } ``` --- ### [taskType](https://runware.ai/docs/models-api/account-management#response-tasktype) - **Type**: `string` - **Required**: true - **Value**: `accountManagement` Identifier for the type of task this response belongs to. ### [taskUUID](https://runware.ai/docs/models-api/account-management#response-taskuuid) - **Type**: `string` - **Required**: true - **Format**: `UUID v4` UUID v4 identifier echoed from the original request, used to match async responses to their tasks. ### [operation](https://runware.ai/docs/models-api/account-management#response-operation) - **Type**: `string` - **Required**: true - **Value**: `getUsageActivity` The account management operation that produced this response. ### [startDate](https://runware.ai/docs/models-api/account-management#response-startdate) - **Type**: `string` - **Format**: `date` Start of the returned window (inclusive). ### [endDate](https://runware.ai/docs/models-api/account-management#response-enddate) - **Type**: `string` - **Format**: `date` End of the returned window (inclusive). ### [usage](https://runware.ai/docs/models-api/account-management#response-usage) - **Path**: `usage.today` - **Type**: `object (46 properties)` Account usage statistics. #### [today](https://runware.ai/docs/models-api/account-management#response-usage-today) - **Path**: `usage.today` - **Type**: `object` Usage stats for today. #### [last7Days](https://runware.ai/docs/models-api/account-management#response-usage-last7days) - **Path**: `usage.last7Days` - **Type**: `object` Usage stats for the last 7 days. #### [last30Days](https://runware.ai/docs/models-api/account-management#response-usage-last30days) - **Path**: `usage.last30Days` - **Type**: `object` Usage stats for the last 30 days. #### [total](https://runware.ai/docs/models-api/account-management#response-usage-total) - **Path**: `usage.total` - **Type**: `object` Total lifetime usage stats. #### [timeseries](https://runware.ai/docs/models-api/account-management#response-usage-timeseries) - **Path**: `usage.timeseries` - **Type**: `object (13 properties)` Per-day breakdown (from groupBy date). ##### [data](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-data) - **Path**: `usage.timeseries.data` - **Type**: `array of objects (6 properties)` - **Required**: true Rows for this breakdown. ##### [date](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-data-date) - **Path**: `usage.timeseries.data.date` - **Type**: `string` - **Format**: `date` Day bucket. ##### [model](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-data-model) - **Path**: `usage.timeseries.data.model` - **Type**: `string` Model AIR. ##### [modelName](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-data-modelname) - **Path**: `usage.timeseries.data.modelName` - **Type**: `string` Human-friendly model name. Falls back to the AIR when none exists. ##### [apiKey](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-data-apikey) - **Path**: `usage.timeseries.data.apiKey` - **Type**: `string` API key UUID. ##### [count](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-data-count) - **Path**: `usage.timeseries.data.count` - **Type**: `integer` Number of requests in this bucket. ##### [spend](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-data-spend) - **Path**: `usage.timeseries.data.spend` - **Type**: `float` Amount spent in this bucket. ##### [meta](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-meta) - **Path**: `usage.timeseries.meta` - **Type**: `object (5 properties)` - **Required**: true Roll-up totals for a breakdown. Which fields are present depends on the operation. ##### [totalRequests](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-meta-totalrequests) - **Path**: `usage.timeseries.meta.totalRequests` - **Type**: `integer` Total requests across the window. ##### [totalResults](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-meta-totalresults) - **Path**: `usage.timeseries.meta.totalResults` - **Type**: `integer` Total results produced across the window. ##### [totalSpend](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-meta-totalspend) - **Path**: `usage.timeseries.meta.totalSpend` - **Type**: `float` Total spend across the window. ##### [avgDailySpend](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-meta-avgdailyspend) - **Path**: `usage.timeseries.meta.avgDailySpend` - **Type**: `float` Average spend per day. An estimate that drifts between calls. ##### [projectedSpend](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-meta-projectedspend) - **Path**: `usage.timeseries.meta.projectedSpend` - **Type**: `float` Projected 30-day spend extrapolated from the window. An estimate that drifts between calls. #### [model](https://runware.ai/docs/models-api/account-management#response-usage-model) - **Path**: `usage.model` - **Type**: `object (13 properties)` Per-model breakdown (from groupBy model). ##### [data](https://runware.ai/docs/models-api/account-management#response-usage-model-data) - **Path**: `usage.model.data` - **Type**: `array of objects (6 properties)` - **Required**: true Rows for this breakdown. ##### [date](https://runware.ai/docs/models-api/account-management#response-usage-model-data-date) - **Path**: `usage.model.data.date` - **Type**: `string` - **Format**: `date` Day bucket. ##### [model](https://runware.ai/docs/models-api/account-management#response-usage-model-data-model) - **Path**: `usage.model.data.model` - **Type**: `string` Model AIR. ##### [modelName](https://runware.ai/docs/models-api/account-management#response-usage-model-data-modelname) - **Path**: `usage.model.data.modelName` - **Type**: `string` Human-friendly model name. Falls back to the AIR when none exists. ##### [apiKey](https://runware.ai/docs/models-api/account-management#response-usage-model-data-apikey) - **Path**: `usage.model.data.apiKey` - **Type**: `string` API key UUID. ##### [count](https://runware.ai/docs/models-api/account-management#response-usage-model-data-count) - **Path**: `usage.model.data.count` - **Type**: `integer` Number of requests in this bucket. ##### [spend](https://runware.ai/docs/models-api/account-management#response-usage-model-data-spend) - **Path**: `usage.model.data.spend` - **Type**: `float` Amount spent in this bucket. ##### [meta](https://runware.ai/docs/models-api/account-management#response-usage-model-meta) - **Path**: `usage.model.meta` - **Type**: `object (5 properties)` - **Required**: true Roll-up totals for a breakdown. Which fields are present depends on the operation. ##### [totalRequests](https://runware.ai/docs/models-api/account-management#response-usage-model-meta-totalrequests) - **Path**: `usage.model.meta.totalRequests` - **Type**: `integer` Total requests across the window. ##### [totalResults](https://runware.ai/docs/models-api/account-management#response-usage-model-meta-totalresults) - **Path**: `usage.model.meta.totalResults` - **Type**: `integer` Total results produced across the window. ##### [totalSpend](https://runware.ai/docs/models-api/account-management#response-usage-model-meta-totalspend) - **Path**: `usage.model.meta.totalSpend` - **Type**: `float` Total spend across the window. ##### [avgDailySpend](https://runware.ai/docs/models-api/account-management#response-usage-model-meta-avgdailyspend) - **Path**: `usage.model.meta.avgDailySpend` - **Type**: `float` Average spend per day. An estimate that drifts between calls. ##### [projectedSpend](https://runware.ai/docs/models-api/account-management#response-usage-model-meta-projectedspend) - **Path**: `usage.model.meta.projectedSpend` - **Type**: `float` Projected 30-day spend extrapolated from the window. An estimate that drifts between calls. #### [apiKey](https://runware.ai/docs/models-api/account-management#response-usage-apikey) - **Path**: `usage.apiKey` - **Type**: `object (13 properties)` Per-key breakdown (from groupBy apiKey). ##### [data](https://runware.ai/docs/models-api/account-management#response-usage-apikey-data) - **Path**: `usage.apiKey.data` - **Type**: `array of objects (6 properties)` - **Required**: true Rows for this breakdown. ##### [date](https://runware.ai/docs/models-api/account-management#response-usage-apikey-data-date) - **Path**: `usage.apiKey.data.date` - **Type**: `string` - **Format**: `date` Day bucket. ##### [model](https://runware.ai/docs/models-api/account-management#response-usage-apikey-data-model) - **Path**: `usage.apiKey.data.model` - **Type**: `string` Model AIR. ##### [modelName](https://runware.ai/docs/models-api/account-management#response-usage-apikey-data-modelname) - **Path**: `usage.apiKey.data.modelName` - **Type**: `string` Human-friendly model name. Falls back to the AIR when none exists. ##### [apiKey](https://runware.ai/docs/models-api/account-management#response-usage-apikey-data-apikey) - **Path**: `usage.apiKey.data.apiKey` - **Type**: `string` API key UUID. ##### [count](https://runware.ai/docs/models-api/account-management#response-usage-apikey-data-count) - **Path**: `usage.apiKey.data.count` - **Type**: `integer` Number of requests in this bucket. ##### [spend](https://runware.ai/docs/models-api/account-management#response-usage-apikey-data-spend) - **Path**: `usage.apiKey.data.spend` - **Type**: `float` Amount spent in this bucket. ##### [meta](https://runware.ai/docs/models-api/account-management#response-usage-apikey-meta) - **Path**: `usage.apiKey.meta` - **Type**: `object (5 properties)` - **Required**: true Roll-up totals for a breakdown. Which fields are present depends on the operation. ##### [totalRequests](https://runware.ai/docs/models-api/account-management#response-usage-apikey-meta-totalrequests) - **Path**: `usage.apiKey.meta.totalRequests` - **Type**: `integer` Total requests across the window. ##### [totalResults](https://runware.ai/docs/models-api/account-management#response-usage-apikey-meta-totalresults) - **Path**: `usage.apiKey.meta.totalResults` - **Type**: `integer` Total results produced across the window. ##### [totalSpend](https://runware.ai/docs/models-api/account-management#response-usage-apikey-meta-totalspend) - **Path**: `usage.apiKey.meta.totalSpend` - **Type**: `float` Total spend across the window. ##### [avgDailySpend](https://runware.ai/docs/models-api/account-management#response-usage-apikey-meta-avgdailyspend) - **Path**: `usage.apiKey.meta.avgDailySpend` - **Type**: `float` Average spend per day. An estimate that drifts between calls. ##### [projectedSpend](https://runware.ai/docs/models-api/account-management#response-usage-apikey-meta-projectedspend) - **Path**: `usage.apiKey.meta.projectedSpend` - **Type**: `float` Projected 30-day spend extrapolated from the window. An estimate that drifts between calls. ## getUsagePerformance How fast the account's models run. For a date window, each `model` row reports the **average, p90, and p99 inference time** in seconds, so you can track tail latency per model. Percentiles are only meaningful within a single model, so the data lives in the `model` breakdown and the `timeseries` breakdown **comes back empty**. ### Request **TypeScript**: ```typescript import { createClient } from '@runware/sdk' const client = await createClient({ apiKey: process.env.RUNWARE_API_KEY }) await client.connect() const result = await client.accountManagement({ operation: 'getUsagePerformance', startDate: '2026-07-01', endDate: '2026-07-06', groupBy: [ 'date', 'model' ] }) ``` **Python**: ```python import asyncio import os from runware import Runware async def main(): async with Runware(api_key=os.environ["RUNWARE_API_KEY"]) as client: result = await client.account_management({ "operation": "getUsagePerformance", "startDate": "2026-07-01", "endDate": "2026-07-06", "groupBy": [ "date", "model" ] }) asyncio.run(main()) ``` **cURL**: ```bash curl https://api.runware.ai/v1 \ -H "Authorization: Bearer $RUNWARE_API_KEY" \ -H "Content-Type: application/json" \ -d '[ { "taskType": "accountManagement", "taskUUID": "ed936635-488f-48c2-8c4d-dbf117c8a7b1", "operation": "getUsagePerformance", "startDate": "2026-07-01", "endDate": "2026-07-06", "groupBy": [ "date", "model" ] } ]' ``` **CLI**: ```bash runware account getUsagePerformance ``` **JSON**: ```json { "taskType": "accountManagement", "taskUUID": "ed936635-488f-48c2-8c4d-dbf117c8a7b1", "operation": "getUsagePerformance", "startDate": "2026-07-01", "endDate": "2026-07-06", "groupBy": [ "date", "model" ] } ``` --- ### [taskType](https://runware.ai/docs/models-api/account-management#request-tasktype) - **Type**: `string` - **Required**: true - **Value**: `accountManagement` Identifier for the type of task being performed. ### [taskUUID](https://runware.ai/docs/models-api/account-management#request-taskuuid) - **Type**: `string` - **Required**: true - **Format**: `UUID v4` UUID v4 identifier for tracking tasks and matching async responses. Must be unique per task. ### [operation](https://runware.ai/docs/models-api/account-management#request-operation) - **Type**: `string` - **Required**: true - **Value**: `getUsagePerformance` The specific account management operation to perform. ### [startDate](https://runware.ai/docs/models-api/account-management#request-startdate) - **Type**: `string` - **Format**: `date` Start of the usage window (inclusive). ### [endDate](https://runware.ai/docs/models-api/account-management#request-enddate) - **Type**: `string` - **Format**: `date` End of the usage window (inclusive). Must be on or after startDate, and the span must not exceed 30 days. ### [models](https://runware.ai/docs/models-api/account-management#request-models) - **Type**: `array of strings` - **Max items**: `100` Restrict usage to these model AIRs. Defaults to all models. ### [apiKeys](https://runware.ai/docs/models-api/account-management#request-apikeys) - **Type**: `array of strings` - **Max items**: `100` Restrict usage to these API key UUIDs. Defaults to all keys. ### [groupBy](https://runware.ai/docs/models-api/account-management#request-groupby) - **Type**: `array of strings` - **Default**: `date,model` Breakdowns to return. ### [timezone](https://runware.ai/docs/models-api/account-management#request-timezone) - **Type**: `string` - **Default**: `UTC` IANA timezone name used for day-bucketing. ### Response ```json { "data": [ { "taskType": "accountManagement", "taskUUID": "ed936635-488f-48c2-8c4d-dbf117c8a7b1", "operation": "getUsagePerformance", "startDate": "2026-07-01", "endDate": "2026-07-06", "usage": { "model": { "data": [{ "date": "2026-07-03", "model": "bytedance:video-upscaler@standard", "modelName": "Bytedance Video Upscaler", "avgInferenceTime": 134.8486, "p90InferenceTime": 226.245, "p99InferenceTime": 291.6665 }], "meta": { "totalRequests": 164, "totalResults": 164, "totalSpend": 1.6226, "avgDailySpend": 0.2704, "projectedSpend": 8.38, "avgInferenceTime": 134.8486, "p50InferenceTime": 144.49, "p90InferenceTime": 226.245, "p99InferenceTime": 291.6665 } } } } ] } ``` --- ### [taskType](https://runware.ai/docs/models-api/account-management#response-tasktype) - **Type**: `string` - **Required**: true - **Value**: `accountManagement` Identifier for the type of task this response belongs to. ### [taskUUID](https://runware.ai/docs/models-api/account-management#response-taskuuid) - **Type**: `string` - **Required**: true - **Format**: `UUID v4` UUID v4 identifier echoed from the original request, used to match async responses to their tasks. ### [operation](https://runware.ai/docs/models-api/account-management#response-operation) - **Type**: `string` - **Required**: true - **Value**: `getUsagePerformance` The account management operation that produced this response. ### [startDate](https://runware.ai/docs/models-api/account-management#response-startdate) - **Type**: `string` - **Format**: `date` Start of the returned window (inclusive). ### [endDate](https://runware.ai/docs/models-api/account-management#response-enddate) - **Type**: `string` - **Format**: `date` End of the returned window (inclusive). ### [usage](https://runware.ai/docs/models-api/account-management#response-usage) - **Path**: `usage.today` - **Type**: `object (61 properties)` Account usage statistics. #### [today](https://runware.ai/docs/models-api/account-management#response-usage-today) - **Path**: `usage.today` - **Type**: `object` Usage stats for today. #### [last7Days](https://runware.ai/docs/models-api/account-management#response-usage-last7days) - **Path**: `usage.last7Days` - **Type**: `object` Usage stats for the last 7 days. #### [last30Days](https://runware.ai/docs/models-api/account-management#response-usage-last30days) - **Path**: `usage.last30Days` - **Type**: `object` Usage stats for the last 30 days. #### [total](https://runware.ai/docs/models-api/account-management#response-usage-total) - **Path**: `usage.total` - **Type**: `object` Total lifetime usage stats. #### [timeseries](https://runware.ai/docs/models-api/account-management#response-usage-timeseries) - **Path**: `usage.timeseries` - **Type**: `object (18 properties)` Per-day breakdown (from groupBy date). ##### [data](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-data) - **Path**: `usage.timeseries.data` - **Type**: `array of objects (7 properties)` - **Required**: true Rows for this breakdown. ##### [date](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-data-date) - **Path**: `usage.timeseries.data.date` - **Type**: `string` - **Format**: `date` Day bucket. ##### [model](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-data-model) - **Path**: `usage.timeseries.data.model` - **Type**: `string` Model AIR. ##### [modelName](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-data-modelname) - **Path**: `usage.timeseries.data.modelName` - **Type**: `string` Human-friendly model name. Falls back to the AIR when none exists. ##### [apiKey](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-data-apikey) - **Path**: `usage.timeseries.data.apiKey` - **Type**: `string` API key UUID. ##### [avgInferenceTime](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-data-avginferencetime) - **Path**: `usage.timeseries.data.avgInferenceTime` - **Type**: `float | null` Average inference time in seconds, or null when there were no inferences. ##### [p90InferenceTime](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-data-p90inferencetime) - **Path**: `usage.timeseries.data.p90InferenceTime` - **Type**: `float | null` 90th-percentile inference time in seconds, or null when there were no inferences. ##### [p99InferenceTime](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-data-p99inferencetime) - **Path**: `usage.timeseries.data.p99InferenceTime` - **Type**: `float | null` 99th-percentile inference time in seconds, or null when there were no inferences. ##### [meta](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-meta) - **Path**: `usage.timeseries.meta` - **Type**: `object (9 properties)` - **Required**: true Roll-up totals for a breakdown. Which fields are present depends on the operation. ##### [totalRequests](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-meta-totalrequests) - **Path**: `usage.timeseries.meta.totalRequests` - **Type**: `integer` Total requests across the window. ##### [totalResults](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-meta-totalresults) - **Path**: `usage.timeseries.meta.totalResults` - **Type**: `integer` Total results produced across the window. ##### [totalSpend](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-meta-totalspend) - **Path**: `usage.timeseries.meta.totalSpend` - **Type**: `float` Total spend across the window. ##### [avgDailySpend](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-meta-avgdailyspend) - **Path**: `usage.timeseries.meta.avgDailySpend` - **Type**: `float` Average spend per day. An estimate that drifts between calls. ##### [projectedSpend](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-meta-projectedspend) - **Path**: `usage.timeseries.meta.projectedSpend` - **Type**: `float` Projected 30-day spend extrapolated from the window. An estimate that drifts between calls. ##### [avgInferenceTime](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-meta-avginferencetime) - **Path**: `usage.timeseries.meta.avgInferenceTime` - **Type**: `float` Average inference time in seconds. ##### [p50InferenceTime](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-meta-p50inferencetime) - **Path**: `usage.timeseries.meta.p50InferenceTime` - **Type**: `float` Median inference time in seconds. ##### [p90InferenceTime](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-meta-p90inferencetime) - **Path**: `usage.timeseries.meta.p90InferenceTime` - **Type**: `float` 90th-percentile inference time in seconds. ##### [p99InferenceTime](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-meta-p99inferencetime) - **Path**: `usage.timeseries.meta.p99InferenceTime` - **Type**: `float` 99th-percentile inference time in seconds. #### [model](https://runware.ai/docs/models-api/account-management#response-usage-model) - **Path**: `usage.model` - **Type**: `object (18 properties)` Per-model breakdown (from groupBy model). ##### [data](https://runware.ai/docs/models-api/account-management#response-usage-model-data) - **Path**: `usage.model.data` - **Type**: `array of objects (7 properties)` - **Required**: true Rows for this breakdown. ##### [date](https://runware.ai/docs/models-api/account-management#response-usage-model-data-date) - **Path**: `usage.model.data.date` - **Type**: `string` - **Format**: `date` Day bucket. ##### [model](https://runware.ai/docs/models-api/account-management#response-usage-model-data-model) - **Path**: `usage.model.data.model` - **Type**: `string` Model AIR. ##### [modelName](https://runware.ai/docs/models-api/account-management#response-usage-model-data-modelname) - **Path**: `usage.model.data.modelName` - **Type**: `string` Human-friendly model name. Falls back to the AIR when none exists. ##### [apiKey](https://runware.ai/docs/models-api/account-management#response-usage-model-data-apikey) - **Path**: `usage.model.data.apiKey` - **Type**: `string` API key UUID. ##### [avgInferenceTime](https://runware.ai/docs/models-api/account-management#response-usage-model-data-avginferencetime) - **Path**: `usage.model.data.avgInferenceTime` - **Type**: `float | null` Average inference time in seconds, or null when there were no inferences. ##### [p90InferenceTime](https://runware.ai/docs/models-api/account-management#response-usage-model-data-p90inferencetime) - **Path**: `usage.model.data.p90InferenceTime` - **Type**: `float | null` 90th-percentile inference time in seconds, or null when there were no inferences. ##### [p99InferenceTime](https://runware.ai/docs/models-api/account-management#response-usage-model-data-p99inferencetime) - **Path**: `usage.model.data.p99InferenceTime` - **Type**: `float | null` 99th-percentile inference time in seconds, or null when there were no inferences. ##### [meta](https://runware.ai/docs/models-api/account-management#response-usage-model-meta) - **Path**: `usage.model.meta` - **Type**: `object (9 properties)` - **Required**: true Roll-up totals for a breakdown. Which fields are present depends on the operation. ##### [totalRequests](https://runware.ai/docs/models-api/account-management#response-usage-model-meta-totalrequests) - **Path**: `usage.model.meta.totalRequests` - **Type**: `integer` Total requests across the window. ##### [totalResults](https://runware.ai/docs/models-api/account-management#response-usage-model-meta-totalresults) - **Path**: `usage.model.meta.totalResults` - **Type**: `integer` Total results produced across the window. ##### [totalSpend](https://runware.ai/docs/models-api/account-management#response-usage-model-meta-totalspend) - **Path**: `usage.model.meta.totalSpend` - **Type**: `float` Total spend across the window. ##### [avgDailySpend](https://runware.ai/docs/models-api/account-management#response-usage-model-meta-avgdailyspend) - **Path**: `usage.model.meta.avgDailySpend` - **Type**: `float` Average spend per day. An estimate that drifts between calls. ##### [projectedSpend](https://runware.ai/docs/models-api/account-management#response-usage-model-meta-projectedspend) - **Path**: `usage.model.meta.projectedSpend` - **Type**: `float` Projected 30-day spend extrapolated from the window. An estimate that drifts between calls. ##### [avgInferenceTime](https://runware.ai/docs/models-api/account-management#response-usage-model-meta-avginferencetime) - **Path**: `usage.model.meta.avgInferenceTime` - **Type**: `float` Average inference time in seconds. ##### [p50InferenceTime](https://runware.ai/docs/models-api/account-management#response-usage-model-meta-p50inferencetime) - **Path**: `usage.model.meta.p50InferenceTime` - **Type**: `float` Median inference time in seconds. ##### [p90InferenceTime](https://runware.ai/docs/models-api/account-management#response-usage-model-meta-p90inferencetime) - **Path**: `usage.model.meta.p90InferenceTime` - **Type**: `float` 90th-percentile inference time in seconds. ##### [p99InferenceTime](https://runware.ai/docs/models-api/account-management#response-usage-model-meta-p99inferencetime) - **Path**: `usage.model.meta.p99InferenceTime` - **Type**: `float` 99th-percentile inference time in seconds. #### [apiKey](https://runware.ai/docs/models-api/account-management#response-usage-apikey) - **Path**: `usage.apiKey` - **Type**: `object (18 properties)` Per-key breakdown (from groupBy apiKey). ##### [data](https://runware.ai/docs/models-api/account-management#response-usage-apikey-data) - **Path**: `usage.apiKey.data` - **Type**: `array of objects (7 properties)` - **Required**: true Rows for this breakdown. ##### [date](https://runware.ai/docs/models-api/account-management#response-usage-apikey-data-date) - **Path**: `usage.apiKey.data.date` - **Type**: `string` - **Format**: `date` Day bucket. ##### [model](https://runware.ai/docs/models-api/account-management#response-usage-apikey-data-model) - **Path**: `usage.apiKey.data.model` - **Type**: `string` Model AIR. ##### [modelName](https://runware.ai/docs/models-api/account-management#response-usage-apikey-data-modelname) - **Path**: `usage.apiKey.data.modelName` - **Type**: `string` Human-friendly model name. Falls back to the AIR when none exists. ##### [apiKey](https://runware.ai/docs/models-api/account-management#response-usage-apikey-data-apikey) - **Path**: `usage.apiKey.data.apiKey` - **Type**: `string` API key UUID. ##### [avgInferenceTime](https://runware.ai/docs/models-api/account-management#response-usage-apikey-data-avginferencetime) - **Path**: `usage.apiKey.data.avgInferenceTime` - **Type**: `float | null` Average inference time in seconds, or null when there were no inferences. ##### [p90InferenceTime](https://runware.ai/docs/models-api/account-management#response-usage-apikey-data-p90inferencetime) - **Path**: `usage.apiKey.data.p90InferenceTime` - **Type**: `float | null` 90th-percentile inference time in seconds, or null when there were no inferences. ##### [p99InferenceTime](https://runware.ai/docs/models-api/account-management#response-usage-apikey-data-p99inferencetime) - **Path**: `usage.apiKey.data.p99InferenceTime` - **Type**: `float | null` 99th-percentile inference time in seconds, or null when there were no inferences. ##### [meta](https://runware.ai/docs/models-api/account-management#response-usage-apikey-meta) - **Path**: `usage.apiKey.meta` - **Type**: `object (9 properties)` - **Required**: true Roll-up totals for a breakdown. Which fields are present depends on the operation. ##### [totalRequests](https://runware.ai/docs/models-api/account-management#response-usage-apikey-meta-totalrequests) - **Path**: `usage.apiKey.meta.totalRequests` - **Type**: `integer` Total requests across the window. ##### [totalResults](https://runware.ai/docs/models-api/account-management#response-usage-apikey-meta-totalresults) - **Path**: `usage.apiKey.meta.totalResults` - **Type**: `integer` Total results produced across the window. ##### [totalSpend](https://runware.ai/docs/models-api/account-management#response-usage-apikey-meta-totalspend) - **Path**: `usage.apiKey.meta.totalSpend` - **Type**: `float` Total spend across the window. ##### [avgDailySpend](https://runware.ai/docs/models-api/account-management#response-usage-apikey-meta-avgdailyspend) - **Path**: `usage.apiKey.meta.avgDailySpend` - **Type**: `float` Average spend per day. An estimate that drifts between calls. ##### [projectedSpend](https://runware.ai/docs/models-api/account-management#response-usage-apikey-meta-projectedspend) - **Path**: `usage.apiKey.meta.projectedSpend` - **Type**: `float` Projected 30-day spend extrapolated from the window. An estimate that drifts between calls. ##### [avgInferenceTime](https://runware.ai/docs/models-api/account-management#response-usage-apikey-meta-avginferencetime) - **Path**: `usage.apiKey.meta.avgInferenceTime` - **Type**: `float` Average inference time in seconds. ##### [p50InferenceTime](https://runware.ai/docs/models-api/account-management#response-usage-apikey-meta-p50inferencetime) - **Path**: `usage.apiKey.meta.p50InferenceTime` - **Type**: `float` Median inference time in seconds. ##### [p90InferenceTime](https://runware.ai/docs/models-api/account-management#response-usage-apikey-meta-p90inferencetime) - **Path**: `usage.apiKey.meta.p90InferenceTime` - **Type**: `float` 90th-percentile inference time in seconds. ##### [p99InferenceTime](https://runware.ai/docs/models-api/account-management#response-usage-apikey-meta-p99inferencetime) - **Path**: `usage.apiKey.meta.p99InferenceTime` - **Type**: `float` 99th-percentile inference time in seconds. ## getUsageErrors Reliability, sliced the same way `getUsageActivity` slices spend. Each row splits failures into **client errors** (`4xx`) and **server errors** (`5xx`), and the `meta` roll-up carries the window's `totalErrors` and an `errorRate` as a percentage. Group by `model` or `apiKey` to see **which one is failing**. ### Request **TypeScript**: ```typescript import { createClient } from '@runware/sdk' const client = await createClient({ apiKey: process.env.RUNWARE_API_KEY }) await client.connect() const result = await client.accountManagement({ operation: 'getUsageErrors', startDate: '2026-07-01', endDate: '2026-07-06', groupBy: [ 'date', 'model' ] }) ``` **Python**: ```python import asyncio import os from runware import Runware async def main(): async with Runware(api_key=os.environ["RUNWARE_API_KEY"]) as client: result = await client.account_management({ "operation": "getUsageErrors", "startDate": "2026-07-01", "endDate": "2026-07-06", "groupBy": [ "date", "model" ] }) asyncio.run(main()) ``` **cURL**: ```bash curl https://api.runware.ai/v1 \ -H "Authorization: Bearer $RUNWARE_API_KEY" \ -H "Content-Type: application/json" \ -d '[ { "taskType": "accountManagement", "taskUUID": "cb460b4c-0d63-4fe2-9694-2115b2ce2161", "operation": "getUsageErrors", "startDate": "2026-07-01", "endDate": "2026-07-06", "groupBy": [ "date", "model" ] } ]' ``` **CLI**: ```bash runware account getUsageErrors ``` **JSON**: ```json { "taskType": "accountManagement", "taskUUID": "cb460b4c-0d63-4fe2-9694-2115b2ce2161", "operation": "getUsageErrors", "startDate": "2026-07-01", "endDate": "2026-07-06", "groupBy": [ "date", "model" ] } ``` --- ### [taskType](https://runware.ai/docs/models-api/account-management#request-tasktype) - **Type**: `string` - **Required**: true - **Value**: `accountManagement` Identifier for the type of task being performed. ### [taskUUID](https://runware.ai/docs/models-api/account-management#request-taskuuid) - **Type**: `string` - **Required**: true - **Format**: `UUID v4` UUID v4 identifier for tracking tasks and matching async responses. Must be unique per task. ### [operation](https://runware.ai/docs/models-api/account-management#request-operation) - **Type**: `string` - **Required**: true - **Value**: `getUsageErrors` The specific account management operation to perform. ### [startDate](https://runware.ai/docs/models-api/account-management#request-startdate) - **Type**: `string` - **Format**: `date` Start of the usage window (inclusive). ### [endDate](https://runware.ai/docs/models-api/account-management#request-enddate) - **Type**: `string` - **Format**: `date` End of the usage window (inclusive). Must be on or after startDate, and the span must not exceed 30 days. ### [models](https://runware.ai/docs/models-api/account-management#request-models) - **Type**: `array of strings` - **Max items**: `100` Restrict usage to these model AIRs. Defaults to all models. ### [apiKeys](https://runware.ai/docs/models-api/account-management#request-apikeys) - **Type**: `array of strings` - **Max items**: `100` Restrict usage to these API key UUIDs. Defaults to all keys. ### [groupBy](https://runware.ai/docs/models-api/account-management#request-groupby) - **Type**: `array of strings` - **Default**: `date,model` Breakdowns to return. ### [timezone](https://runware.ai/docs/models-api/account-management#request-timezone) - **Type**: `string` - **Default**: `UTC` IANA timezone name used for day-bucketing. ### Response ```json { "data": [ { "taskType": "accountManagement", "taskUUID": "cb460b4c-0d63-4fe2-9694-2115b2ce2161", "operation": "getUsageErrors", "startDate": "2026-07-01", "endDate": "2026-07-06", "usage": { "timeseries": { "data": [{ "date": "2026-07-03", "clientErrors": 126, "serverErrors": 0 }], "meta": { "totalErrors": 128, "errorRate": 78.05 } }, "model": { "data": [{ "date": "2026-07-03", "model": "bytedance:video-upscaler@standard", "modelName": "Bytedance Video Upscaler", "clientErrors": 126, "serverErrors": 0 }], "meta": { "totalErrors": 128, "errorRate": 78.05 } } } } ] } ``` --- ### [taskType](https://runware.ai/docs/models-api/account-management#response-tasktype) - **Type**: `string` - **Required**: true - **Value**: `accountManagement` Identifier for the type of task this response belongs to. ### [taskUUID](https://runware.ai/docs/models-api/account-management#response-taskuuid) - **Type**: `string` - **Required**: true - **Format**: `UUID v4` UUID v4 identifier echoed from the original request, used to match async responses to their tasks. ### [operation](https://runware.ai/docs/models-api/account-management#response-operation) - **Type**: `string` - **Required**: true - **Value**: `getUsageErrors` The account management operation that produced this response. ### [startDate](https://runware.ai/docs/models-api/account-management#response-startdate) - **Type**: `string` - **Format**: `date` Start of the returned window (inclusive). ### [endDate](https://runware.ai/docs/models-api/account-management#response-enddate) - **Type**: `string` - **Format**: `date` End of the returned window (inclusive). ### [usage](https://runware.ai/docs/models-api/account-management#response-usage) - **Path**: `usage.today` - **Type**: `object (37 properties)` Account usage statistics. #### [today](https://runware.ai/docs/models-api/account-management#response-usage-today) - **Path**: `usage.today` - **Type**: `object` Usage stats for today. #### [last7Days](https://runware.ai/docs/models-api/account-management#response-usage-last7days) - **Path**: `usage.last7Days` - **Type**: `object` Usage stats for the last 7 days. #### [last30Days](https://runware.ai/docs/models-api/account-management#response-usage-last30days) - **Path**: `usage.last30Days` - **Type**: `object` Usage stats for the last 30 days. #### [total](https://runware.ai/docs/models-api/account-management#response-usage-total) - **Path**: `usage.total` - **Type**: `object` Total lifetime usage stats. #### [timeseries](https://runware.ai/docs/models-api/account-management#response-usage-timeseries) - **Path**: `usage.timeseries` - **Type**: `object (10 properties)` Per-day breakdown (from groupBy date). ##### [data](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-data) - **Path**: `usage.timeseries.data` - **Type**: `array of objects (6 properties)` - **Required**: true Rows for this breakdown. ##### [date](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-data-date) - **Path**: `usage.timeseries.data.date` - **Type**: `string` - **Format**: `date` Day bucket. ##### [model](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-data-model) - **Path**: `usage.timeseries.data.model` - **Type**: `string` Model AIR. ##### [modelName](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-data-modelname) - **Path**: `usage.timeseries.data.modelName` - **Type**: `string` Human-friendly model name. Falls back to the AIR when none exists. ##### [apiKey](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-data-apikey) - **Path**: `usage.timeseries.data.apiKey` - **Type**: `string` API key UUID. ##### [clientErrors](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-data-clienterrors) - **Path**: `usage.timeseries.data.clientErrors` - **Type**: `integer` Number of 4xx (client) errors in this bucket. ##### [serverErrors](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-data-servererrors) - **Path**: `usage.timeseries.data.serverErrors` - **Type**: `integer` Number of 5xx (server) errors in this bucket. ##### [meta](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-meta) - **Path**: `usage.timeseries.meta` - **Type**: `object (2 properties)` - **Required**: true Roll-up totals for a breakdown. Which fields are present depends on the operation. ##### [totalErrors](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-meta-totalerrors) - **Path**: `usage.timeseries.meta.totalErrors` - **Type**: `integer` Total errors across the window. ##### [errorRate](https://runware.ai/docs/models-api/account-management#response-usage-timeseries-meta-errorrate) - **Path**: `usage.timeseries.meta.errorRate` - **Type**: `float` Error rate across the window, as a percentage. #### [model](https://runware.ai/docs/models-api/account-management#response-usage-model) - **Path**: `usage.model` - **Type**: `object (10 properties)` Per-model breakdown (from groupBy model). ##### [data](https://runware.ai/docs/models-api/account-management#response-usage-model-data) - **Path**: `usage.model.data` - **Type**: `array of objects (6 properties)` - **Required**: true Rows for this breakdown. ##### [date](https://runware.ai/docs/models-api/account-management#response-usage-model-data-date) - **Path**: `usage.model.data.date` - **Type**: `string` - **Format**: `date` Day bucket. ##### [model](https://runware.ai/docs/models-api/account-management#response-usage-model-data-model) - **Path**: `usage.model.data.model` - **Type**: `string` Model AIR. ##### [modelName](https://runware.ai/docs/models-api/account-management#response-usage-model-data-modelname) - **Path**: `usage.model.data.modelName` - **Type**: `string` Human-friendly model name. Falls back to the AIR when none exists. ##### [apiKey](https://runware.ai/docs/models-api/account-management#response-usage-model-data-apikey) - **Path**: `usage.model.data.apiKey` - **Type**: `string` API key UUID. ##### [clientErrors](https://runware.ai/docs/models-api/account-management#response-usage-model-data-clienterrors) - **Path**: `usage.model.data.clientErrors` - **Type**: `integer` Number of 4xx (client) errors in this bucket. ##### [serverErrors](https://runware.ai/docs/models-api/account-management#response-usage-model-data-servererrors) - **Path**: `usage.model.data.serverErrors` - **Type**: `integer` Number of 5xx (server) errors in this bucket. ##### [meta](https://runware.ai/docs/models-api/account-management#response-usage-model-meta) - **Path**: `usage.model.meta` - **Type**: `object (2 properties)` - **Required**: true Roll-up totals for a breakdown. Which fields are present depends on the operation. ##### [totalErrors](https://runware.ai/docs/models-api/account-management#response-usage-model-meta-totalerrors) - **Path**: `usage.model.meta.totalErrors` - **Type**: `integer` Total errors across the window. ##### [errorRate](https://runware.ai/docs/models-api/account-management#response-usage-model-meta-errorrate) - **Path**: `usage.model.meta.errorRate` - **Type**: `float` Error rate across the window, as a percentage. #### [apiKey](https://runware.ai/docs/models-api/account-management#response-usage-apikey) - **Path**: `usage.apiKey` - **Type**: `object (10 properties)` Per-key breakdown (from groupBy apiKey). ##### [data](https://runware.ai/docs/models-api/account-management#response-usage-apikey-data) - **Path**: `usage.apiKey.data` - **Type**: `array of objects (6 properties)` - **Required**: true Rows for this breakdown. ##### [date](https://runware.ai/docs/models-api/account-management#response-usage-apikey-data-date) - **Path**: `usage.apiKey.data.date` - **Type**: `string` - **Format**: `date` Day bucket. ##### [model](https://runware.ai/docs/models-api/account-management#response-usage-apikey-data-model) - **Path**: `usage.apiKey.data.model` - **Type**: `string` Model AIR. ##### [modelName](https://runware.ai/docs/models-api/account-management#response-usage-apikey-data-modelname) - **Path**: `usage.apiKey.data.modelName` - **Type**: `string` Human-friendly model name. Falls back to the AIR when none exists. ##### [apiKey](https://runware.ai/docs/models-api/account-management#response-usage-apikey-data-apikey) - **Path**: `usage.apiKey.data.apiKey` - **Type**: `string` API key UUID. ##### [clientErrors](https://runware.ai/docs/models-api/account-management#response-usage-apikey-data-clienterrors) - **Path**: `usage.apiKey.data.clientErrors` - **Type**: `integer` Number of 4xx (client) errors in this bucket. ##### [serverErrors](https://runware.ai/docs/models-api/account-management#response-usage-apikey-data-servererrors) - **Path**: `usage.apiKey.data.serverErrors` - **Type**: `integer` Number of 5xx (server) errors in this bucket. ##### [meta](https://runware.ai/docs/models-api/account-management#response-usage-apikey-meta) - **Path**: `usage.apiKey.meta` - **Type**: `object (2 properties)` - **Required**: true Roll-up totals for a breakdown. Which fields are present depends on the operation. ##### [totalErrors](https://runware.ai/docs/models-api/account-management#response-usage-apikey-meta-totalerrors) - **Path**: `usage.apiKey.meta.totalErrors` - **Type**: `integer` Total errors across the window. ##### [errorRate](https://runware.ai/docs/models-api/account-management#response-usage-apikey-meta-errorrate) - **Path**: `usage.apiKey.meta.errorRate` - **Type**: `float` Error rate across the window, as a percentage. --- ## Media Storage - **URL:** https://runware.ai/docs/models-api/media-storage - **Description:** Upload media to your Runware storage or delete it by UUID, for any image, video, audio, or 3D model input reused across the API. ## Introduction The `mediaStorage` task **stores media in your Runware account and returns a reusable UUID**, so you can hand an image, video, audio, or 3D model to any task that accepts media inputs without re-uploading it each time. It also **deletes stored media** when you no longer need it. Every call is a single `operation`, either an `upload` or a `delete`, sent as one task object in the usual request array. ## Upload An `upload` takes the media as a **publicly accessible URL, a data URI, or a base64 string**, stores it, and returns a `mediaUUID` and `mediaURL` you can reuse as input anywhere in the API. ### Request **TypeScript**: ```typescript import { createClient } from '@runware/sdk' const client = await createClient({ apiKey: process.env.RUNWARE_API_KEY }) await client.connect() const result = await client.mediaStorage({ operation: 'upload', media: 'data:image/png;base64,iVBORw0KGgo...' }) ``` **Python**: ```python import asyncio import os from runware import Runware async def main(): async with Runware(api_key=os.environ["RUNWARE_API_KEY"]) as client: result = await client.media_storage({ "operation": "upload", "media": "data:image/png;base64,iVBORw0KGgo..." }) asyncio.run(main()) ``` **cURL**: ```bash curl https://api.runware.ai/v1 \ -H "Authorization: Bearer $RUNWARE_API_KEY" \ -H "Content-Type: application/json" \ -d '[ { "taskType": "mediaStorage", "taskUUID": "50836053-a0ee-4cf5-b9d6-ae7c5d140ada", "operation": "upload", "media": "data:image/png;base64,iVBORw0KGgo..." } ]' ``` **CLI**: ```bash runware media upload "data:image/png;base64,iVBORw0KGgo..." ``` **JSON**: ```json { "taskType": "mediaStorage", "taskUUID": "50836053-a0ee-4cf5-b9d6-ae7c5d140ada", "operation": "upload", "media": "data:image/png;base64,iVBORw0KGgo..." } ``` --- ### [taskType](https://runware.ai/docs/models-api/media-storage#request-tasktype) - **Type**: `string` - **Required**: true - **Value**: `mediaStorage` Identifier for the type of task being performed. ### [taskUUID](https://runware.ai/docs/models-api/media-storage#request-taskuuid) - **Type**: `string` - **Required**: true - **Format**: `UUID v4` UUID v4 identifier for tracking tasks and matching async responses. Must be unique per task. ### [operation](https://runware.ai/docs/models-api/media-storage#request-operation) - **Type**: `string` - **Required**: true - **Value**: `upload` Store new media and return its UUID and URL. ### [media](https://runware.ai/docs/models-api/media-storage#request-media) - **Type**: `string` - **Required**: true For upload, the media as a publicly accessible URL, data URI, or base64 string. For delete, the mediaUUID of the media to remove. ### Response The response returns the stored media's **UUID and URL**. ```json { "data": [ { "taskType": "mediaStorage", "taskUUID": "50836053-a0ee-4cf5-b9d6-ae7c5d140ada", "operation": "upload", "mediaUUID": "989ba605-1449-4e1e-b462-cd83ec9c1a67", "mediaURL": "https://mm.runware.ai/media-storage/ws/2/id/989ba605-1449-4e1e-b462-cd83ec9c1a67.png" } ] } ``` --- ### [taskType](https://runware.ai/docs/models-api/media-storage#response-tasktype) - **Type**: `string` - **Required**: true - **Value**: `mediaStorage` Identifier for the type of task this response belongs to. ### [taskUUID](https://runware.ai/docs/models-api/media-storage#response-taskuuid) - **Type**: `string` - **Required**: true - **Format**: `UUID v4` UUID v4 identifier echoed from the original request, used to match async responses to their tasks. ### [operation](https://runware.ai/docs/models-api/media-storage#response-operation) - **Type**: `string` - **Required**: true - **Value**: `upload` The media storage operation that produced this response. ### [mediaUUID](https://runware.ai/docs/models-api/media-storage#response-mediauuid) - **Type**: `string` - **Required**: true - **Format**: `UUID v4` UUID of the stored media. ### [mediaURL](https://runware.ai/docs/models-api/media-storage#response-mediaurl) - **Type**: `string` - **Required**: true - **Format**: `uri` URL where the stored media is accessible. ## Delete A `delete` removes media you stored earlier. Pass its `mediaUUID` as the `media` value. ### Request **TypeScript**: ```typescript import { createClient } from '@runware/sdk' const client = await createClient({ apiKey: process.env.RUNWARE_API_KEY }) await client.connect() const result = await client.mediaStorage({ operation: 'delete', media: '989ba605-1449-4e1e-b462-cd83ec9c1a67' }) ``` **Python**: ```python import asyncio import os from runware import Runware async def main(): async with Runware(api_key=os.environ["RUNWARE_API_KEY"]) as client: result = await client.media_storage({ "operation": "delete", "media": "989ba605-1449-4e1e-b462-cd83ec9c1a67" }) asyncio.run(main()) ``` **cURL**: ```bash curl https://api.runware.ai/v1 \ -H "Authorization: Bearer $RUNWARE_API_KEY" \ -H "Content-Type: application/json" \ -d '[ { "taskType": "mediaStorage", "taskUUID": "b7e0a3f2-3c1a-4d9e-8f2b-1a2c3d4e5f60", "operation": "delete", "media": "989ba605-1449-4e1e-b462-cd83ec9c1a67" } ]' ``` **CLI**: ```bash runware media delete 989ba605-1449-4e1e-b462-cd83ec9c1a67 ``` **JSON**: ```json { "taskType": "mediaStorage", "taskUUID": "b7e0a3f2-3c1a-4d9e-8f2b-1a2c3d4e5f60", "operation": "delete", "media": "989ba605-1449-4e1e-b462-cd83ec9c1a67" } ``` --- ### [taskType](https://runware.ai/docs/models-api/media-storage#request-tasktype) - **Type**: `string` - **Required**: true - **Value**: `mediaStorage` Identifier for the type of task being performed. ### [taskUUID](https://runware.ai/docs/models-api/media-storage#request-taskuuid) - **Type**: `string` - **Required**: true - **Format**: `UUID v4` UUID v4 identifier for tracking tasks and matching async responses. Must be unique per task. ### [operation](https://runware.ai/docs/models-api/media-storage#request-operation) - **Type**: `string` - **Required**: true - **Value**: `delete` Permanently remove previously stored media by its UUID. ### [media](https://runware.ai/docs/models-api/media-storage#request-media) - **Type**: `string` - **Required**: true For upload, the media as a publicly accessible URL, data URI, or base64 string. For delete, the mediaUUID of the media to remove. ### Response The response returns the **deleted media's UUID**, so you can confirm what was removed. ```json { "data": [ { "taskType": "mediaStorage", "taskUUID": "b7e0a3f2-3c1a-4d9e-8f2b-1a2c3d4e5f60", "operation": "delete", "mediaUUID": "989ba605-1449-4e1e-b462-cd83ec9c1a67" } ] } ``` --- ### [taskType](https://runware.ai/docs/models-api/media-storage#response-tasktype) - **Type**: `string` - **Required**: true - **Value**: `mediaStorage` Identifier for the type of task this response belongs to. ### [taskUUID](https://runware.ai/docs/models-api/media-storage#response-taskuuid) - **Type**: `string` - **Required**: true - **Format**: `UUID v4` UUID v4 identifier echoed from the original request, used to match async responses to their tasks. ### [operation](https://runware.ai/docs/models-api/media-storage#response-operation) - **Type**: `string` - **Required**: true - **Value**: `delete` The media storage operation that produced this response. ### [mediaUUID](https://runware.ai/docs/models-api/media-storage#response-mediauuid) - **Type**: `string` - **Required**: true - **Format**: `UUID v4` UUID of the stored media. --- ## Task Details - **URL:** https://runware.ai/docs/models-api/task-details - **Description:** Retrieve the original request and response for any previously executed task. Useful for debugging, recovering past results, and auditing API interactions. ## Introduction The `getTaskDetails` task retrieves the **complete request and response objects** for any previously executed task. Pass the `taskUUID` of a past task to recover its original request payload and the API response it produced. It answers two questions: **what exactly did we send**, when a request failed and the payload is in doubt, and **what did we get back**, when the response was never stored on your side. **The returned `request` and `response` objects are untyped**, because their structure depends on the original task type. They are the whole objects, exactly as they were sent and received. > [!NOTE] > The `taskUUID` in this request refers to the UUID of the task you want to inspect. The response echoes it back along with the original request and response objects. ## Request The Runware API always accepts an array of objects as input, where each object represents a **specific task to be performed**. The structure of the object varies depending on the type of the task. For this section, we will focus on the parameters related to the **task details task**. The following JSON snippet shows the basic structure of a request object. **TypeScript**: ```typescript import { createClient } from '@runware/sdk' const client = await createClient({ apiKey: process.env.RUNWARE_API_KEY }) await client.connect() const result = await client.getTaskDetails({ taskUUID: 'a770f077-f413-47de-9dac-be0b26a35da6' }) ``` **Python**: ```python import asyncio import os from runware import Runware async def main(): async with Runware(api_key=os.environ["RUNWARE_API_KEY"]) as client: result = await client.get_task_details({ "taskUUID": "a770f077-f413-47de-9dac-be0b26a35da6" }) asyncio.run(main()) ``` **cURL**: ```bash curl https://api.runware.ai/v1 \ -H "Authorization: Bearer $RUNWARE_API_KEY" \ -H "Content-Type: application/json" \ -d '[ { "taskType": "getTaskDetails", "taskUUID": "a770f077-f413-47de-9dac-be0b26a35da6" } ]' ``` **CLI**: ```bash runware result a770f077-f413-47de-9dac-be0b26a35da6 ``` **JSON**: ```json { "taskType": "getTaskDetails", "taskUUID": "a770f077-f413-47de-9dac-be0b26a35da6" } ``` --- ### [taskType](https://runware.ai/docs/models-api/task-details#request-tasktype) - **Type**: `string` - **Required**: true - **Value**: `getTaskDetails` Identifier for the type of task being performed. ### [taskUUID](https://runware.ai/docs/models-api/task-details#request-taskuuid) - **Type**: `string` - **Required**: true - **Format**: `UUID v4` UUID v4 identifier for tracking tasks and matching async responses. Must be unique per task. ## Response The response always includes the original `request` array and a `response` object. **The `response` is the full API envelope**, carrying either a `data` array if the task completed or an `errors` array if it failed. Both objects are untyped because their structure depends on the original task type. ### Successful task When the original task completed successfully, the `response` object contains a `data` array with the results. ```json { "data": [ { "taskType": "getTaskDetails", "taskUUID": "a770f077-f413-47de-9dac-be0b26a35da6", "request": [ { "taskType": "imageInference", "model": "runware:101@1", "positivePrompt": "a cat", "width": 1024, "height": 1024, "numberResults": 1, "includeCost": true, "taskUUID": "a770f077-f413-47de-9dac-be0b26a35da6" } ], "response": { "data": [ { "taskType": "imageInference", "taskUUID": "a770f077-f413-47de-9dac-be0b26a35da6", "imageUUID": "77da2d99-a6d3-44d9-b8c0-ae9fb06b6200", "imageURL": "https://im.runware.ai/image/os/a14d18/ws/2/ii/77da2d99-a6d3-44d9-b8c0-ae9fb06b6200.jpg", "cost": 0.0013 } ] } } ] } ``` ### Failed task When the original task failed, the `response` object contains an `errors` array with the error details from the original failure. ```json { "data": [ { "taskType": "getTaskDetails", "taskUUID": "b880f077-e514-58ef-0ebd-ce1c37b46eb7", "request": [ { "taskType": "imageInference", "model": "runware:400@1", "positivePrompt": "a landscape", "width": 1024, "height": 1024, "numberResults": 1, "inputs": { "referenceImages": [ "https://im.runware.ai/image/ws/5/bucket/media-storage/ii/4e7a91c3-28d5-4f6b-a0e2-7c3d8f1b5a94", "https://im.runware.ai/image/ws/5/bucket/media-storage/ii/d2f08b47-9c31-4a85-be6f-5e9a12c7d403", "https://im.runware.ai/image/ws/5/bucket/media-storage/ii/8b5c3e19-f7a2-4d60-91c4-a6e8d0f23b71", "https://im.runware.ai/image/ws/5/bucket/media-storage/ii/c1d94f6a-3b82-47e5-a5c0-9f2e71d08b36", "https://im.runware.ai/image/ws/5/bucket/media-storage/ii/7a0e5d93-6f14-4c28-b9d7-e3c1a84f2650" ] }, "taskUUID": "b880f077-e514-58ef-0ebd-ce1c37b46eb7" } ], "response": { "errors": [ { "code": "invalidReferenceImagesCount", "message": "Invalid number of elements for 'referenceImages' parameter. Reference images must contain between 0 and 4.", "parameter": "inputs.referenceImages", "type": "string[]", "documentation": "https://runware.ai/docs", "taskUUID": "b880f077-e514-58ef-0ebd-ce1c37b46eb7" } ] } } ] } ``` ### Task not found If the provided `taskUUID` does not exist or belongs to a different organization, the API returns a standard error response. ```json { "data": [], "errors": [ { "code": "taskNotFound", "message": "No task found for the provided 'taskUUID'. The taskUUID may not exist or may belong to a different organization.", "parameter": "taskUUID", "type": "string", "documentation": "https://runware.ai/docs", "taskUUID": "abcdc144-7364-4a7c-b6e4-fadb3dbf2f67" } ] } ``` --- ### [taskType](https://runware.ai/docs/models-api/task-details#response-tasktype) - **Type**: `string` - **Required**: true - **Value**: `getTaskDetails` Identifier for the type of task this response belongs to. ### [taskUUID](https://runware.ai/docs/models-api/task-details#response-taskuuid) - **Type**: `string` - **Required**: true - **Format**: `UUID v4` UUID v4 identifier echoed from the original request, used to match async responses to their tasks. ### [request](https://runware.ai/docs/models-api/task-details#response-request) - **Type**: `array of objects` - **Required**: true The original request array sent for this task. The structure of each object depends on the task type. ### [response](https://runware.ai/docs/models-api/task-details#response-response) - **Type**: `object` - **Required**: true The original API response for this task. Contains a `data` array when the task completed successfully, or an `errors` array when the task failed. ---