# Documentation This file contains the complete documentation in markdown format for LLM consumption. --- ## Getting started with the Runware API **URL:** https://runware.ai/docs/platform/introduction **Description:** Get started with the Runware API. Learn the core concepts and send your first task across image, video, audio, and more. ## Introduction Welcome to the **Runware platform documentation**. We have a mission: to enable any team to launch AI media generation features with **low budgets** and **no AI expertise**. Our custom-designed [Sonic Inference Engine®](https://runware.ai/sonic-inference-engine/) delivers high-quality media at **sub-second speeds**. We have built this unique platform from scratch, hosted on our own infrastructure powered by renewable energy. By optimizing the entire AI stack from the OS level upwards, we've achieved exceptional speeds and cost efficiency that we pass directly to you. The Runware API is a single endpoint spanning **image, video, audio, 3D, and text generation**. It abstracts models and providers behind a unified interface, so you can integrate any AI media capability with the same consistent patterns regardless of modality. ## Getting started To start using the Runware API: 1. [Sign up](https://my.runware.ai/signup) for a Runware account. 2. Get your API key from the dashboard. 3. Learn how to [connect and authenticate](https://runware.ai/docs/platform/authentication) with the Runware API. 4. Explore the [Models](https://runware.ai/docs/models) to find the right one for your use case and start building. ### Your first request Generate an image with a single API call. This example uses [FLUX.2 \[dev\]](https://runware.ai/docs/models/flux-2-dev) to create an image from a text prompt: **JSON**: ```json [ { "taskType": "imageInference", "taskUUID": "a770f077-f413-47de-9dac-be0b26a35da6", "positivePrompt": "A golden retriever sitting on a park bench, cinematic lighting", "model": "runware:400@1", "width": 1024, "height": 1024 } ] ``` **cURL**: ```bash curl -X POST https://api.runware.ai/v1 \\ -H "Content-Type: application/json" \\ -H "Authorization: Bearer " \\ -d '[ { "taskType": "imageInference", "taskUUID": "a770f077-f413-47de-9dac-be0b26a35da6", "positivePrompt": "A golden retriever sitting on a park bench, cinematic lighting", "model": "runware:400@1", "width": 1024, "height": 1024 } ]' ``` **JavaScript**: ```javascript import { Runware } from "@runware/sdk-js"; const runware = new Runware({ apiKey: "" }); const images = await runware.requestImages({ positivePrompt: "A golden retriever sitting on a park bench, cinematic lighting", model: "runware:400@1", width: 1024, height: 1024, }); console.log(images[0].imageURL); ``` **Python**: ```python import asyncio from runware import Runware, IImageInference async def main(): runware = Runware(api_key="") await runware.connect() request = IImageInference( positivePrompt="A golden retriever sitting on a park bench, cinematic lighting", model="runware:400@1", width=1024, height=1024, ) images = await runware.imageInference(requestImage=request) print(images[0].imageURL) asyncio.run(main()) ``` ## Core API concepts The Runware API follows a consistent design pattern across all our services. Understanding these core concepts will help you work effectively with any of our endpoints. ### Task-based architecture The Runware API is built around the concept of **tasks**. Each request represents a specific task to be performed, whether that's generating an image, synthesizing speech, creating a video, or removing a background. This task-based architecture enables a **consistent request structure** across all modalities, **asynchronous processing** for computationally intensive operations, and **efficient resource allocation** based on task requirements. Every API call accepts an array of objects as input, where each object represents an individual **task** to be performed. You can send as many tasks as you need in a single request, and each task will be processed independently. ### Common request parameters Every API request shares these fundamental parameters: - **taskType**: Identifies which operation to perform (e.g., `imageInference`, `videoInference`, `audioInference`, `imageUpload`). - **taskUUID**: A unique identifier (UUID v4) you generate for tracking the request and matching it with responses. If a task fails or behaves unexpectedly, providing the `taskUUID` when contacting support enables us to quickly locate the request. - **includeCost**: Optional flag to include cost information with each response. ```json [ { "taskType": "imageInference", "taskUUID": "a770f077-f413-47de-9dac-be0b26a35da6", "includeCost": true, // Image generation parameters... }, { "taskType": "videoInference", "taskUUID": "b880f077-e514-58ef-0ebd-ce1c37b46eb7", "includeCost": true, // Video generation parameters... } ] ``` ### Common response structure All API responses follow a consistent format. Each response contains: - **taskType**: Echoes the type of task originally requested. - **taskUUID**: Mirrors the unique identifier you provided. - **cost**: Included when requested, showing the exact cost associated with the task. Additional fields in the response vary depending on the task type, but this consistent structure makes working with different API features straightforward. Results are delivered in the format shown below. Each message can contain **one or multiple results**, depending on the task. For example, when generating multiple images, you might receive them progressively as each completes rather than waiting for all of them at once. Generated output URLs are retained for 7 days by default. This can be configured per request using the `ttl` parameter. ```json { "data": [ { "taskType": "imageInference", "taskUUID": "a770f077-f413-47de-9dac-be0b26a35da6", "imageUUID": "77da2d99-a6d3-44d9-b8c0-ae9fb06b6200", "imageURL": "https://im.runware.ai/image/ws/0.5/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://im.runware.ai/video/ws/0.5/vi/b7db282d-2943-4f12-992f-77df3ad3ec71.mp4", "cost": 0.18 } ] } ``` ## Platform topics Core concepts that apply across all modalities and services. [ ### Task Polling Detailed guide to handling API responses and task states.](https://runware.ai/docs/platform/task-polling)[ ### Streaming Stream real-time responses for text inference tasks.](https://runware.ai/docs/platform/streaming)[ ### Webhooks Receive real-time notifications for long-running tasks via webhooks.](https://runware.ai/docs/platform/webhooks)[ ### Errors Troubleshoot common issues with error codes and messages.](https://runware.ai/docs/platform/errors)[ ### Rate Limits Learn about request limits and best practices for scaling.](https://runware.ai/docs/platform/rate-limits)[ ### Pricing Understand our cost structure and billing models.](https://runware.ai/docs/platform/pricing) ## SDKs & Integrations Accelerate your development with our official libraries. [ ### JavaScript SDK Build robust web applications with our JS/TS client.](https://runware.ai/docs/platform/javascript)[ ### Python SDK Integrate AI into your backend or data pipelines easily.](https://runware.ai/docs/platform/python)[ ### ComfyUI Run your ComfyUI workflows at scale on Runware infrastructure.](https://runware.ai/docs/platform/comfyui)[ ### Vercel AI SDK Seamlessly integrate with the Vercel AI SDK ecosystem.](https://runware.ai/docs/platform/vercel-ai)[ ### OpenAI Compatibility Use any OpenAI-compatible client with Runware's text inference.](https://runware.ai/docs/platform/openai) ## Utilities Helper tools to manage your integration. [ ### Model Search Find and filter through our extensive model library via API.](https://runware.ai/docs/platform/model-search)[ ### Model Upload Upload your own models to the Runware platform for public or private use.](https://runware.ai/docs/platform/model-upload)[ ### Account Management Programmatically manage your account settings and keys.](https://runware.ai/docs/platform/account-management)[ ### Image Upload Upload reference images for image-to-image workflows.](https://runware.ai/docs/platform/image-upload)[ ### Task Details Retrieve the original request and response for any past task.](https://runware.ai/docs/platform/task-details) --- ## Connection & Authentication **URL:** https://runware.ai/docs/platform/authentication **Description:** Learn how to connect and authenticate with the Runware API using HTTP REST or WebSockets. ## Authentication To interact with the Runware API, you need to authenticate your requests using an API key. This key is unique to your account and is used to identify you when making requests. You can create multiple keys for different projects or environments (development, production, staging), add descriptions to them, and revoke them at any time. With the teams feature, you can also share keys with your team members. To create an API key, simply sign up on [Runware](https://my.runware.ai/signup) and visit the "API Keys" page. Then, click "Create Key" and fill the details for your new key. ## HTTP (REST) We recommend using [WebSockets](#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. Authentication can be done by including the authentication object as the first element in the array, or by using the `Authorization` header with the value `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 will return a JSON object with the `data` property. This property is an array containing all the response objects. Each object will contain the `taskType` and the `taskUUID` of the request it's responding to, as well as other properties related to the task. ```json { "data": [ { "taskType": "imageInference", "taskUUID": "39d7207a-87ef-4c93-8082-1431f9c1dc97", "imageUUID": "b7db282d-2943-4f12-992f-77df3ad3ec71", "imageURL": "https://im.runware.ai/image/ws/0.5/ii/b7db282d-2943-4f12-992f-77df3ad3ec71.jpg" } ] } ``` If there's an error, the API will not return the `data` property. Instead, it will return the `error` property, containing the error 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**. To connect you can use one of the SDKs we provide ([JavaScript](https://runware.ai/docs/platform/javascript), [Python](https://runware.ai/docs/platform/python)) or manually. 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. ```json [ { "taskType": "authentication", "apiKey": "" } ] ``` #### Response After you've made the authentication request the API will return an object with the `connectionSessionUUID` parameter. This string is unique to your connection and is used to resume connections in case of disconnection (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://my.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: ```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**. --- ## Task Polling **URL:** https://runware.ai/docs/platform/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. Alternatively, you can use [Webhooks](https://runware.ai/docs/platform/webhooks) to receive results via HTTP POST as soon as they are ready, without polling. > [!NOTE] > If you are using the [JavaScript](https://runware.ai/docs/platform/javascript) or [Python](https://runware.ai/docs/platform/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. ```json { "taskType": "getResponse", "taskUUID": "50836053-a0ee-4cf5-b9d6-ae7c5d140ada" } ``` --- ### [taskType](#request-tasktype) - **Type**: `const:getResponse` - **Required**: true - **Value**: `getResponse` The type of task to perform. ### [taskUUID](#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, while failed generations are moved 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://im.runware.ai/video/ws/0.5/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/platform/errors", "taskUUID": "24cd5dff-cb81-4db5-8506-b72a9425f9d1" } ] } ``` --- ### [taskType](#response-tasktype) - **Type**: `string` - **Required**: true - **Value**: `getResponse` Type of the task. ### [taskUUID](#response-taskuuid) - **Type**: `string` - **Required**: true - **Format**: `UUID v4` UUID of the task. ### [status](#response-status) - **Type**: `string` - **Required**: true Current status of the task. **Possible values**: `processing` `success` `error` ### [progress](#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](#response-error) - **Path**: `error.code` - **Type**: `object (2 properties)` Error details if the task failed. #### [code](#response-error-code) - **Path**: `error.code` - **Type**: `string` Error code. #### [message](#response-error-message) - **Path**: `error.message` - **Type**: `string` Error message description. --- ## Streaming (SSE) **URL:** https://runware.ai/docs/platform/streaming **Description:** Stream text inference results token-by-token using Server-Sent Events. Learn how to enable streaming and parse the SSE response format. ## Overview 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. This is particularly useful for chat interfaces and any application where **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: ```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.0 } } ] ``` The response will be an SSE stream instead of a single JSON object. Each event contains 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/platform/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 contains a small 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} ``` You can display reasoning content in a collapsible section or debug panel, while streaming the final response directly to the user. ### Multiple results When you set `numberResults` greater than 1, multiple completions stream on the same connection. Each chunk includes a `resultIndex` field so you can tell which result it belongs to, since 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. Request with cost and usage enabled ```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.0 }, "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 the presence of `errors` in your parsing logic and handle them accordingly. Error fields follow the same structure as [standard API errors](https://runware.ai/docs/platform/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/platform/webhooks **Description:** Receive real-time notifications when your tasks complete using webhooks. Learn how to configure, secure, and handle webhook deliveries from Runware. ## Overview Webhooks allow you to receive real-time HTTP POST notifications when your generation tasks complete, eliminating the need to poll for results. When a task finishes processing, Runware sends the complete response to your specified URL automatically. This is especially useful for long-running operations like video generation, batch processing where tasks complete at different times, or integrations with external systems that need immediate notifications. For an alternative approach using client-side polling, see [Task Polling](https://runware.ai/docs/platform/task-polling). ## How it works You provide a webhook URL when submitting a task. Runware processes your request asynchronously, and when the task completes, sends an HTTP POST request to your URL with the complete task response as JSON. Your endpoint must respond with a 2xx status code to confirm receipt. If it doesn't, Runware will retry delivery automatically (see [Retry behavior](#retry-behavior)). For batch requests with multiple results, each completed item triggers a separate webhook call as results become available. ## Configuration Include the `webhookURL` parameter in your API request: ```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 support authentication through URL parameters. You can include tokens, API keys, or custom 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 contains the complete JSON response for your task. The structure matches the standard API response for the corresponding task type: ```json { "taskType": "imageInference", "taskUUID": "a770f077-f413-47de-9dac-be0b26a35da6", "imageUUID": "550e8400-e29b-41d4-a716-446655440000", "imageURL": "https://im.runware.ai/image/ws/0.5/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 webhook endpoint must respond with an HTTP status code between 200-299 to confirm receipt. The response should be returned quickly, ideally within 5 seconds. If you need to perform heavy processing, respond immediately with a 200 status and handle the work asynchronously. **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 webhooks aren't being received, verify your endpoint is publicly accessible and responding with 2xx status codes. Check server logs for incoming requests and ensure SSL certificates are valid for HTTPS endpoints. For local development, use ngrok to test connectivity. If your endpoint times out, make sure you're responding immediately with a 200 status and moving heavy processing to background jobs. Webhook delivery is considered successful only when your endpoint returns a 2xx response within the timeout window. --- ## Errors **URL:** https://runware.ai/docs/platform/errors **Description:** Understanding error responses from the Runware API and how to handle them in your integration. ## Overview 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://my.runware.ai/signup", "parameter": "apiKey", "taskType": "authentication" } ] } ``` Each object in the `errors` array represents a single failed operation. When sending multiple tasks in one request errors are scoped to the specific task that failed, while other tasks in the same request 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. | | `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 When using the HTTP REST API, the response also includes a standard HTTP status code alongside the `errors` array. These codes indicate 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** - Too many requests hit the API too quickly. See [Rate Limits](https://runware.ai/docs/platform/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 do not have HTTP status codes. For WebSocket integrations, use the `code` field in the error object to determine the error category. ## Handling errors For programmatic retry decisions, use HTTP status codes when on REST, or the error `code` field when on WebSocket. For debugging, always log the full `message` and `taskUUID`. The task UUID is the fastest way to get help from our support team. ### 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`). 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/platform/rate-limits) for detailed retry implementation patterns. --- ## Rate Limits **URL:** https://runware.ai/docs/platform/rate-limits **Description:** Understanding platform rate limits and best practices for building resilient integrations with Runware. ## How we handle capacity Runware operates on a shared infrastructure model with finite processing capacity. Rather than enforcing hard rate limits that reject requests arbitrarily, we use dynamic queue-based systems that balance load across all users while prioritizing active workloads. This approach maximizes platform accessibility while maintaining service quality. You won't hit artificial walls, but you will experience graceful degradation under high load rather than immediate rejection. **Current approach:** - **No hard rate limits** - We don't reject requests based on arbitrary thresholds. - **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, you'll experience increased latency rather than immediate failures. ## What to expect Under normal conditions, requests are processed quickly and reliably. When platform capacity is reached, here's 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\. Timeout potential** - Extremely long queues may result in timeout errors after waiting too long. **4\. 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`** - Queue capacity exceeded, implement retry with exponential backoff. - **`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. ## 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 we recommend implementing robust retry logic. ## Best practices ### Implement retry logic Always implement exponential backoff for failed requests. This is critical for resilient integrations. **TypeScript**: ```typescript async function generateWithRetry(params: any, maxRetries = 3) { for (let i = 0; i < maxRetries; i++) { try { return await runware.imageInference(params); } catch (error: any) { // Retry on capacity errors if (error.status === 429 || error.status === 503) { const delay = Math.pow(2, i) * 1000; // 1s, 2s, 4s await new Promise(resolve => setTimeout(resolve, delay)); continue; } // Don't retry other errors throw error; } } throw new Error('Max retries exceeded'); } ``` **Python**: ```python import time async def generate_with_retry(params, max_retries=3): for i in range(max_retries): try: return await runware.image_inference(params) except Exception as error: # Retry on capacity errors if hasattr(error, 'status') and error.status in [429, 503]: delay = (2 ** i) * 1000 # 1s, 2s, 4s time.sleep(delay / 1000) continue # Don't retry other errors raise error raise Exception('Max retries exceeded') ``` ### 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 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 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:** - No hard rate limits, but shared infrastructure with finite capacity - Graceful degradation through queueing under load - Third-party provider limits affect service availability **Your responsibilities:** - Implement exponential backoff retry logic - Manage concurrency (2-4 concurrent requests recommended) - Monitor latency and adjust request patterns **Need guarantees?** - Contact sales for dedicated capacity, SLAs, and custom infrastructure This approach balances accessibility with reliability. By following these best practices, you'll build integrations that gracefully handle capacity constraints and maintain high uptime. --- ## Pricing **URL:** https://runware.ai/docs/platform/pricing **Description:** How Runware pricing works, from compute-based billing to understanding costs in your integration. ## Pay as you go Our pricing philosophy is simple: **we optimize models to run faster, and we pass those savings directly to you**. Unlike platforms that charge a flat fee per generation regardless of inference time, our architecture is based on **optimized compute time**, so fewer GPU seconds means lower cost. Pay only for what you use, with no subscriptions or commitments. ## Pricing models We operate with two primary pricing structures depending on the model type: ### Serverless (Optimized Compute) For most open-source models (like Stable Diffusion, Flux, etc.) that we host and optimize, pricing is based on **compute time**. - **Granular billing**: You are charged for the exact resources used to generate your output. - **Speed discounts**: As we optimize our inference engine to be faster, the cost per generation drops automatically. - **No idle costs**: You don't pay for cold starts or idle GPU time. > [!NOTE] > **Example**: If we optimize a model to run 2x faster, your cost for that generation effectively drops by ~50%. ### Fixed Price For closed-source or partner models where we do not control the underlying infrastructure optimization, we may offer **fixed per-request pricing**. - **Predictable costs**: You know exactly how much each request costs upfront. - **Standardized**: Prices are set based on the provider's rates or license agreements. Our aggregate request volume across the platform allows us to negotiate competitive rates with providers, often resulting in lower per-request pricing than integrating with them directly. For high-volume deployments, contact our [sales team](https://runware.ai/contact) to discuss custom pricing. ## What affects cost The cost of a generation depends on several factors: | Factor | Impact | | --- | --- | | **Model** | Different models have different compute requirements and provider rates. | | **Resolution** | Higher output resolution requires more processing time. | | **Duration** | Longer video or audio outputs cost more. | | **Steps** | More inference steps increase compute time (serverless models). | | **Batch size** | Cost scales linearly with the number of outputs requested. | For serverless models, anything that increases GPU time increases cost. For fixed-price models, costs are determined per request based on the provider's pricing structure. ## Understanding costs All costs are denominated in **USD**. Your account balance is deducted in real-time as you generate content, and you can top up or configure auto-reload in the [Dashboard](https://runware.ai/dashboard). Your balance does not expire. To avoid service interruptions, you can configure **auto-reload** to automatically top up your balance when it falls below a threshold. The Dashboard also lets you set up **low-balance alerts** and **backup payment methods**. Failed requests are not charged. You only pay for successful generations. To see the exact cost of any request, include the `includeCost` parameter in your API call. The response will contain a `cost` field showing the amount in USD deducted for that specific task. > [!NOTE] > To see the pricing for a specific model, check its page in the [Models](https://runware.ai/docs/models) section. You can also generate a test request in the [Playground](https://runware.ai/playground) to see the exact cost before integrating. --- ## JavaScript library **URL:** https://runware.ai/docs/platform/javascript **Description:** Integrate Runware's API with our JavaScript library. Get started with code examples and comprehensive usage instructions. ## Introduction The Runware JavaScript SDK provides a **high-performance WebSocket-based interface** built for modern web applications requiring AI-powered media processing. Unlike traditional REST APIs that require establishing new connections for each request, the SDK maintains **persistent connections** that improve performance for applications requiring multiple operations or real-time feedback. The SDK handles all the complexity of **connection management, authentication, and error recovery** while exposing Runware's complete feature set through an intuitive Promise-based API. **Asynchronous operations** for tasks that require longer processing times, such as video generation, are handled automatically. You don't need to manage polling or status checking manually, all the complexity is managed behind the scenes. ## Key SDK benefits ### Performance advantages **Reduced latency** is achieved by eliminating the connection establishment overhead that occurs with each HTTP request. In applications performing multiple operations, this can significantly reduce total processing time compared to REST-based approaches. **Progressive result delivery** allows your application to display completed results immediately as they finish, rather than waiting for entire batches. This creates a more responsive user experience, particularly valuable when generating multiple variations or conducting iterative workflows. ### Reliability features **Automatic resilience** ensures your application remains functional even when network conditions change. The SDK detects connection issues and re-establishes connectivity transparently, queuing operations during brief disconnections and resuming when connectivity returns. **Concurrent operation efficiency** leverages the persistent connection to handle multiple simultaneous requests without connection overhead. This makes the SDK particularly effective for applications that need to perform different types of operations simultaneously. ### When to choose the JavaScript SDK The JavaScript SDK is optimal for applications that prioritize **performance and real-time feedback**. Consider this SDK when your application needs to perform multiple operations frequently, provide immediate user feedback during processing, or integrate AI capabilities as a core interactive feature rather than an occasional utility. Source: [https://github.com/Runware/sdk-js](https://github.com/Runware/sdk-js) ## Installation Install the SDK using your preferred package manager: ```bash npm install @runware/sdk-js ``` Or using Yarn: ```bash yarn add @runware/sdk-js ``` ## Basic setup Get your API key from the [Runware dashboard](https://my.runware.ai) and initialize the SDK directly: ```javascript import { Runware } from "@runware/sdk-js"; const runware = new Runware({ apiKey: "your-api-key-here" }); const images = await runware.requestImages({ positivePrompt: "A serene mountain landscape at sunset", model: "runware:101@1", width: 1024, height: 1024, }); console.log('Generated image:', images[0].imageURL); ``` The SDK automatically handles **connection establishment, authentication, and response formatting**, allowing you to focus on your application logic rather than infrastructure concerns. ## Initialization patterns ### Synchronous initialization The standard pattern creates the SDK instance immediately and establishes connections on-demand: ```javascript import { Runware } from "@runware/sdk-js"; const runware = new Runware({ apiKey: "your-api-key-here", shouldReconnect: true, globalMaxRetries: 3, }); // Connection established automatically on first request const images = await runware.requestImages({ positivePrompt: "A bustling city street at night", model: "runware:101@1", width: 1024, height: 1024, }); ``` This approach is **ideal for most applications** because it's simple and the connection is established when needed. ### Asynchronous initialization For applications requiring **guaranteed connection readiness** before proceeding: ```javascript const runware = await Runware.initialize({ apiKey: "your-api-key-here", timeoutDuration: 60000, }); // Connection is established and ready const images = await runware.requestImages({ positivePrompt: "Professional headshot portrait", model: "runware:101@1", width: 1024, height: 1024, }); // Clean shutdown when application terminates await runware.disconnect(); ``` This pattern is useful when you need to **ensure connection establishment** before performing operations, such as in server applications or when you want to handle connection errors upfront. ### Manual connection control For applications requiring **explicit connection lifecycle management**: ```javascript const runware = new Runware({ apiKey: "your-api-key-here" }); // Explicitly ensure connection is ready await runware.ensureConnection(); // Perform operations with guaranteed connection const images = await runware.requestImages({ positivePrompt: "Professional headshot portrait", model: "runware:101@1", width: 1024, height: 1024, }); // Clean shutdown when application terminates await runware.disconnect(); ``` The `ensureConnection()` method guarantees that the WebSocket connection is established before proceeding, while `disconnect()` provides clean connection termination. ## Progressive result delivery One of the SDK's most powerful features is **progressive result delivery**, which allows you to receive completed images immediately as they finish generating rather than waiting for entire batches: ```javascript const images = await runware.requestImages({ positivePrompt: "A collection of architectural sketches", model: "runware:101@1", width: 1024, height: 1024, numberResults: 5, onPartialImages: (partialImages, error) => { if (error) { console.error('Generation error:', error); return; } // Update UI immediately as each image completes partialImages.forEach((image, index) => { displayImage(image.imageURL); updateProgress(partialImages.length, 5); }); }, }); console.log('All images completed'); ``` The progressive delivery pattern enables user experiences where users **can see completed results immediately** rather than waiting for entire batches to finish. The `onPartialImages` callback receives arrays of completed images as they become available. ## Asynchronous operations Some operations like video generation require **extended processing time** and use asynchronous workflows. The SDK handles all the complexity automatically, including polling for status updates and retrieving final results when ready. ### Understanding async processing When you call methods for long-running operations, the SDK: 1. **Submits your request** and receives an immediate task acknowledgment. 2. **Polls for status updates** automatically. 3. **Returns the final results** once processing completes. This happens transparently, you use the same async/await patterns regardless of operation duration. ### Video generation example Video operations demonstrate the async processing workflow: ```javascript import { Runware } from '@runware/sdk-js'; async function generateVideo() { const runware = new Runware({ apiKey: process.env.RUNWARE_API_KEY }); await runware.connect(); const payload = { positivePrompt: "A serene mountain landscape at sunset", model: "klingai:5@3", duration: 10, width: 1920, height: 1080 }; // This call handles all async complexity internally const response = await runware.videoInference(payload); console.log(`Generated video: ${response[0].videoURL}`); } generateVideo(); ``` The `videoInference` method appears to work like any other async function, but internally manages the **submission, polling, and result retrieval** workflow automatically. ### Handling long operations For operations that may take several minutes, configure appropriate timeouts and retry behavior. See [Configuration options](#configuration-options) for detailed setup: ```javascript // Configure timeouts for long-running operations const runware = new Runware({ apiKey: process.env.RUNWARE_API_KEY, timeout: 600000, // 10 minutes for complex video generation maxRetries: 3, retryDelay: 2000 }); await runware.connect(); // SDK handles extended processing time automatically const payload = { positivePrompt: "Complex cinematic sequence with multiple scenes", model: "google:3@0", duration: 8, width: 1280, height: 720 }; const response = await runware.videoInference(payload); ``` **Timeout configuration** is particularly important for video operations, which can take significantly longer than image generation depending on duration and complexity. ## Concurrent operations The SDK's WebSocket architecture excels at **handling multiple simultaneous operations** without the connection overhead typical of HTTP-based approaches: ```javascript const runware = new Runware({ apiKey: "your-api-key-here" }); // Execute completely different operations simultaneously const [ generatedImages, upscaledImage, backgroundRemoved, imageCaption, ] = await Promise.all([ runware.requestImages({ positivePrompt: "Abstract digital art", numberResults: 3, width: 1024, height: 1024, }), runware.upscaleGan({ inputImage: "some-uuid", upscaleFactor: 4, }), runware.removeImageBackground({ inputImage: "some-uuid", }), runware.requestImageToText({ inputImage: "some-uuid", }), ]); ``` This concurrent execution capability is particularly powerful for **workflow automation** or **batch processing**. ### Long-running concurrent operations The same concurrent patterns work efficiently for **multiple long-running operations** like video generation: ```javascript async function generateMultipleVideos() { const runware = new Runware({ apiKey: process.env.RUNWARE_API_KEY }); await runware.connect(); // Start multiple video generations concurrently const videoTasks = [ runware.videoInference({ positivePrompt: "Ocean waves at sunset", model: "klingai:5@3", duration: 10 }), runware.videoInference({ positivePrompt: "City traffic time-lapse", model: "klingai:5@3", duration: 10 }), runware.videoInference({ positivePrompt: "Forest in autumn", model: "klingai:5@3", duration: 10 }) ]; // All operations process simultaneously const results = await Promise.all(videoTasks); results.forEach((videos, index) => { console.log(`Video ${index + 1}: ${videos[0].videoURL}`); }); } ``` Each operation polls independently, maximizing **throughput for batch processing** scenarios. ## Configuration options The SDK accepts several configuration options that control connection behavior and default settings: ```javascript const runware = new Runware({ apiKey: "your-api-key-here", // Connection management shouldReconnect: true, // Enable automatic reconnection (default: true) globalMaxRetries: 3, // Default retry attempts for all requests (default: 2) timeoutDuration: 90000, // Timeout in milliseconds (default: 60000) // Custom WebSocket endpoint (optional) url: "wss://custom-endpoint.com/v1", }); ``` The **shouldReconnect** option enables automatic reconnection when WebSocket connections are lost, which is essential for maintaining reliability in web applications where network conditions can vary. **globalMaxRetries** sets the default number of retry attempts for all requests. Individual requests can override this setting using their own `retry` parameter. **timeoutDuration** controls how long the SDK waits for responses before timing out operations. This is particularly important for complex generations that may take longer to complete. ## Error handling The SDK provides error information to help you handle failures appropriately: ```javascript try { const images = await runware.requestImages({ positivePrompt: "A detailed architectural rendering", model: "runware:101@1", width: 1024, height: 1024, steps: 50, }); // Process successful results console.log('Generated images:', images); } catch (error) { // Error information available for debugging and user feedback console.error('Generation failed:', { message: error.message, taskUUID: error.taskUUID }); // Handle the error appropriately for your application showErrorMessage(error.message); } ``` When using progressive result delivery, errors can occur during the generation process: ```javascript const images = await runware.requestImages({ positivePrompt: "A series of landscape photographs", numberResults: 8, width: 1024, height: 1024, onPartialImages: (partialImages, error) => { if (error) { console.error('Generation error:', error); // Some images may have succeeded before the error if (partialImages.length) { console.log(`Partial success: ${partialImages.length} images completed`); processPartialResults(partialImages); } return; } // Normal progress updateProgressBar(partialImages.length, 8); displayResults(partialImages); } }); ``` The `onPartialImages` callback receives both successful partial results and any errors that occur, allowing you to handle partial successes gracefully. ## Per-request configuration Individual requests can override global SDK settings for specific needs: ```javascript const images = await runware.requestImages({ positivePrompt: "Ultra-detailed fantasy artwork", model: "runware:101@1", width: 1024, height: 1024, // Override global settings for this specific request retry: 5, // More retries for important operations includeCost: true, // Include cost information in response onPartialImages: (partial) => { // Custom progress handling for this specific request updateSpecializedUI(partial); }, }); ``` The `retry` parameter allows you to specify different retry behavior for individual requests, while `includeCost` adds cost information to the response when needed. Each request can also have its own `onPartialImages` callback for customized progress handling. ## TypeScript support The SDK includes **TypeScript definitions** that provide compile-time type checking and IntelliSense support: ```typescript import { Runware, IImageInference, IImage, IError, ETaskType, } from "@runware/sdk-js"; const runware = new Runware({ apiKey: "your-api-key-here" }); // Type-safe request parameters const requestParams: IImageInference = { positivePrompt: "A professional product photograph", model: "runware:101@1", width: 1024, height: 1024, steps: 30, }; // Fully typed responses const images: IImage[] = await runware.requestImages(requestParams); // Type-safe error handling const handleStreamingError = ( partialImages: IImage[], error: IError | null ) => { if (error) { console.error(`Task ${error.taskUUID} failed: ${error.message}`); } }; ``` TypeScript support extends to **all SDK methods, configuration options, and response types**, enabling better development experience and reduced runtime errors in production applications. --- ## Python library **URL:** https://runware.ai/docs/platform/python **Description:** Integrate Runware's API with our Python library. Get started with code examples and comprehensive usage instructions. ## Introduction The Runware Python SDK provides a **WebSocket-based interface** built for Python applications that need AI-powered media processing. Using Python's async/await patterns, the SDK handles connection management, authentication, and error recovery while exposing Runware's capabilities through a clean, Pythonic API. The SDK is designed for server-side applications where you need reliable AI integration. You can use it to build web APIs or handle batch processing jobs, with support for both image and video workflows. The setup is straightforward and handles the complexity for you. The SDK automatically handles **asynchronous operations** for tasks that require longer processing times, such as video generation. You don't need to manage polling or status checking manually, the SDK handles all the complexity behind the scenes. ## Key SDK benefits ### Built for Python The SDK uses **async/await patterns** that integrate naturally with modern Python frameworks like FastAPI and asyncio-based applications. Your applications stay responsive even during intensive AI operations thanks to the asynchronous architecture. **Comprehensive type hints** provide better IDE support, enable static analysis with tools like mypy, and help catch errors before they reach production. The API follows **Python conventions** for method naming and error handling, so it feels natural if you're already comfortable with Python development. ### Performance advantages **Persistent WebSocket connections** eliminate the connection overhead that occurs with traditional HTTP requests. This provides measurable performance improvements when you're doing multiple operations or batch processing. **Concurrent operations** work seamlessly with Python's asyncio, letting you handle multiple requests simultaneously without blocking your application. ### When to use the Python SDK Choose the Python SDK for **server-side applications** that need reliable AI integration. It's especially effective for web APIs, batch processing systems, and applications where you need robust error handling and automatic retry logic. Source: [https://github.com/Runware/sdk-python](https://github.com/Runware/sdk-python) ## Installation Install the SDK using pip: ```bash pip install runware ``` ## Basic setup The Python SDK supports both environment variable and direct API key configuration. For security best practices, use environment variables: ```bash export RUNWARE_API_KEY="your-api-key-here" ``` Then initialize and use the SDK: ```python import asyncio from runware import Runware, IImageInference async def main(): # SDK reads RUNWARE_API_KEY automatically runware = Runware() await runware.connect() request = IImageInference( positivePrompt="A serene mountain landscape at sunset", model="runware:101@1", width=1024, height=1024 ) images = await runware.imageInference(requestImage=request) print(f"Generated image: {images[0].imageURL}") if __name__ == "__main__": asyncio.run(main()) ``` The SDK automatically handles **connection establishment, authentication, and response parsing**, allowing you to focus on your application logic. ## Connection management ### Automatic connection handling The Python SDK requires explicit connection establishment but handles reconnection automatically: ```python from runware import Runware async def main(): runware = Runware(api_key="your-api-key-here") # Establish connection before making requests await runware.connect() # Perform operations - connection maintained automatically request = IImageInference( positivePrompt="A bustling city street at night", model="runware:101@1", width=1024, height=1024 ) images = await runware.imageInference(requestImage=request) # Connection cleanup (optional - handled automatically) await runware.disconnect() ``` ### Connection configuration For applications with specific requirements, customize connection behavior: ```python runware = Runware( api_key="your-api-key-here", timeout=120, # Custom timeout for operations max_retries=5, # Retry attempts for failed requests retry_delay=2.0 # Delay between retries in seconds ) ``` **Connection lifecycle** is managed explicitly in Python, giving you control over when connections are established and terminated. This is particularly useful in **server applications** where you want to maintain connections across multiple requests. ## Asynchronous operations Some operations like video generation require **extended processing time** and use asynchronous workflows. The SDK handles all the complexity automatically, including polling for status updates and retrieving final results when ready. ### Understanding async processing When you call methods for long-running operations, the SDK: 1. **Submits your request** and receives an immediate task acknowledgment. 2. **Polls for status updates** automatically. 3. **Returns the final results** once processing completes. This happens transparently, you use the same async/await patterns regardless of operation duration. ### Video generation example Video operations demonstrate the async processing workflow: ```python import asyncio from runware import Runware, IVideoInference async def main(): runware = Runware() await runware.connect() request = IVideoInference( positivePrompt="A serene mountain landscape at sunset", model="klingai:5@3", duration=10 ) # This call handles all async complexity internally videos = await runware.videoInference(requestVideo=request) print(f"Generated video: {videos[0].videoURL}") if __name__ == "__main__": asyncio.run(main()) ``` The `videoInference` method appears to work like any other async function, but internally manages the **submission, polling, and result retrieval** workflow automatically. ### Handling long operations For operations that may take several minutes, configure appropriate timeouts and retry behavior. See [Configuration options](#configuration-options) for detailed setup: ```python # Configure timeouts for long-running operations runware = Runware( timeout=600, # 10 minutes for complex video generation max_retries=3, retry_delay=2.0 ) await runware.connect() # SDK handles extended processing time automatically request = IVideoInference( positivePrompt="Complex cinematic sequence with multiple scenes", model="google:3@0", duration=8, width=1280, height=720 ) videos = await runware.videoInference(requestVideo=request) ``` **Timeout configuration** is particularly important for video operations, which can take significantly longer than image generation depending on duration and complexity. ## Concurrent operations The SDK's async design excels at handling **multiple simultaneous operations**: ```python import asyncio from runware import Runware, IImageInference, IImageUpscale, IImageBackgroundRemoval async def main(): runware = Runware() await runware.connect() # Execute multiple operations concurrently results = await asyncio.gather( runware.imageInference(requestImage=IImageInference( positivePrompt="Abstract digital art", model="runware:101@1", width=1024, height=1024 )), runware.imageUpscale(upscaleGanPayload=IImageUpscale( inputImage="existing-image-uuid", upscaleFactor=4 )), runware.imageBackgroundRemoval(removeImageBackgroundPayload=IImageBackgroundRemoval( image_initiator="portrait-path.jpg" )) ) generated_images, upscaled_image, background_removed = results ``` This concurrent execution pattern is particularly powerful for **batch processing**, **workflow automation**, and **applications that need to perform multiple operations** on the same or different inputs simultaneously. ### Long-running concurrent operations The same concurrent patterns work efficiently for **multiple long-running operations** like video generation: ```python import asyncio async def generate_multiple_videos(): runware = Runware() await runware.connect() # Start multiple video generations concurrently video_tasks = [ runware.videoInference(requestVideo=IVideoInference( positivePrompt="Ocean waves at sunset", model="klingai:5@3", duration=10 )), runware.videoInference(requestVideo=IVideoInference( positivePrompt="City traffic time-lapse", model="klingai:5@3", duration=10 )), runware.videoInference(requestVideo=IVideoInference( positivePrompt="Forest in autumn", model="klingai:5@3", duration=10 )) ] # All operations process simultaneously results = await asyncio.gather(*video_tasks) for i, videos in enumerate(results): print(f"Video {i+1}: {videos[0].videoURL}") ``` Each operation polls independently, maximizing **throughput for batch processing** scenarios. ## Error handling The SDK provides comprehensive error handling with detailed information for debugging and user feedback: ```python from runware import Runware async def main(): runware = Runware() await runware.connect() try: request = IImageInference( positivePrompt="A detailed architectural rendering", model="runware:101@1", width=1024, height=1024 ) images = await runware.imageInference(requestImage=request) print(f"Success: {len(images)} images generated") except Exception as e: # Error information available for debugging and user feedback print(f"Generation failed: {e}") # Handle the error appropriately for your application ``` ### Batch operation error handling When processing multiple operations, handle partial failures gracefully: ```python async def process_batch(image_requests): runware = Runware() await runware.connect() results = [] for i, request in enumerate(image_requests): try: images = await runware.imageInference(requestImage=request) results.append({"index": i, "success": True, "images": images}) except Exception as e: results.append({"index": i, "success": False, "error": str(e)}) return results ``` ## Integration patterns ### FastAPI integration The SDK integrates seamlessly with FastAPI for building AI-powered web APIs: ```python from fastapi import FastAPI, HTTPException from runware import Runware, IImageInference import asyncio app = FastAPI() runware = Runware() @app.on_event("startup") async def startup(): await runware.connect() @app.on_event("shutdown") async def shutdown(): await runware.disconnect() @app.post("/generate-image") async def generate_image(prompt: str): try: request = IImageInference( positivePrompt=prompt, model="runware:101@1", width=1024, height=1024 ) images = await runware.imageInference(requestImage=request) return {"image_url": images[0].imageURL} except Exception as e: raise HTTPException(status_code=500, detail=str(e)) ``` ### Batch processing workflows For processing large datasets or multiple files: ```python import asyncio from pathlib import Path from runware import Runware, IImageBackgroundRemoval async def process_images_batch(image_folder: Path, batch_size: int = 10): runware = Runware() await runware.connect() image_files = list(image_folder.glob("*.jpg")) for i in range(0, len(image_files), batch_size): batch = image_files[i:i + batch_size] # Process batch concurrently tasks = [ runware.imageBackgroundRemoval( removeImageBackgroundPayload=IImageBackgroundRemoval( image_initiator=str(img) ) ) for img in batch ] results = await asyncio.gather(*tasks, return_exceptions=True) # Handle results and errors for j, result in enumerate(results): if isinstance(result, Exception): print(f"Failed to process {batch[j]}: {result}") else: print(f"Processed {batch[j]}: {result[0].imageURL}") ``` ## Configuration options ### Environment-based configuration The recommended approach for production applications: ```python import os from runware import Runware # Reads from RUNWARE_API_KEY environment variable runware = Runware() # Or explicitly specify environment variable name runware = Runware(api_key=os.getenv("CUSTOM_API_KEY_NAME")) ``` ### Programmatic configuration For applications requiring dynamic configuration: ```python runware = Runware( api_key="your-api-key-here", timeout=180, # 3 minutes timeout for complex operations max_retries=3, # Retry attempts for failed operations retry_delay=1.5, # Delay between retries base_url="wss://custom-endpoint.com/v1" # Custom endpoint ) ``` **Timeout configuration** is particularly important for applications processing high-resolution images or using complex models that may require extended processing time. **Retry configuration** allows you to balance between reliability and responsiveness, with higher retry counts improving success rates in unstable network conditions. ## Type safety and IDE support The SDK provides comprehensive type hints for better development experience: ```python from runware import ( Runware, IImageInference, IImageUpscale ) from typing import List async def generate_and_upscale(prompt: str) -> List[str]: runware = Runware() await runware.connect() # Type-safe request construction request: IImageInference = IImageInference( positivePrompt=prompt, model="runware:101@1", width=512, height=512 ) images = await runware.imageInference(requestImage=request) # Upscale the first image upscale_request: IImageUpscale = IImageUpscale( inputImage=images[0].imageURL, upscaleFactor=2 ) upscaled = await runware.imageUpscale(upscaleGanPayload=upscale_request) return [upscaled[0].imageURL] ``` Type hints enable **static analysis with mypy**, **better IDE autocompletion**, and **reduced runtime errors** in production applications. ## Best practices ### Connection lifecycle management **Establish connections early** in your application lifecycle, particularly in web applications where you'll handle multiple requests. Reuse connections across requests rather than establishing new ones for each operation. **Handle connection cleanup** properly in long-running applications to prevent resource leaks, especially important in server environments. ### Error resilience **Implement comprehensive error handling** that distinguishes between recoverable and non-recoverable errors. Use the SDK's built-in retry mechanisms for transient failures. **Log errors with context** including task UUIDs for debugging and monitoring in production environments. ### Performance optimization **Use concurrent operations** with `asyncio.gather()` when processing multiple independent requests to maximize throughput. **Configure appropriate timeouts** based on your operation types and infrastructure requirements. **Batch operations** when possible to reduce connection overhead and improve overall system efficiency. --- ## ComfyUI integration **URL:** https://runware.ai/docs/platform/comfyui **Description:** Get started with Runware's official ComfyUI integration. Use cloud-based image generation capabilities with the flexibility of ComfyUI's node-based workflow. ## Introduction Runware's ComfyUI integration brings our powerful cloud infrastructure directly into ComfyUI's node-based workflow environment. This integration **eliminates the need for specific hardware** while maintaining all the flexibility and control that makes ComfyUI special. ![ComfyUI interface showing Runware Image Inference with model settings, prompt, and preview of a woman with vibrant hair and dark makeup](https://runware.ai/docs/assets/image-screenshot.D-94JGV5_Z17zqK6.jpg) ComfyUI is a powerful tool that offers a node-based interface, allowing users to visually construct complex image generation workflows by connecting different components. However, running ComfyUI locally typically requires significant computational resources, particularly a high-end GPU with substantial VRAM. Our integration solves this challenge by handling **all resource-intensive operations in the cloud**. The Runware integration provides a comprehensive set of nodes that connect to different Runware API features, including image generation, editing, enhancement, and more. These nodes enable you to create advanced image generation workflows without worrying about hardware limitations or performance issues, while maintaining the ability to run multiple complex workflows simultaneously and with consistent performance. ## Installation ### Step 1: Install ComfyUI First, ensure you have ComfyUI installed. You can follow the [pre-built package guide](https://docs.comfy.org/get_started/pre_package) or the [manual installation guide](https://docs.comfy.org/get_started/manual_install). ### Step 2: Install ComfyUI-Runware Make sure your system have Python 3.10 or higher installed. You can install the Runware nodes for ComfyUI using two different methods: #### Option 1: Using ComfyUI Manager (Recommended) If you already have the `ComfyUI-Manager` custom node installed, this is the simplest method: 1. Open ComfyUI Manager. 2. Click on "Custom Nodes Manager". 3. Search for "Runware" or "Runware.ai". 4. Click install or update. 5. Restart ComfyUI to apply the changes. If you don't have ComfyUI Manager installed yet or are using the beta ComfyUI desktop version, follow the instructions on the [ComfyUI-Manager GitHub Repository](https://github.com/ltdrdata/ComfyUI-Manager?tab=readme-ov-file#installation). #### Option 2: Manual installation If you prefer manual installation or don't have ComfyUI Manager, follow these steps: ```bash cd custom_nodes git clone https://github.com/Runware/ComfyUI-Runware.git cd ComfyUI-Runware pip install -r requirements.txt ``` To start ComfyUI with our nodes: ```bash python main.py --front-end-version Comfy-Org/ComfyUI_frontend@latest ``` If you're running without a GPU, add the `--cpu` flag: ```bash python main.py --cpu --front-end-version Comfy-Org/ComfyUI_frontend@latest ``` ### Step 3: Explore workflows Inside the `ComfyUI-Runware` custom node folder, you'll find a `workflows` folder with pre-made workflows to get you started. These examples demonstrate different features and capabilities of our nodes. You can load these workflows through the ComfyUI interface to explore and modify them to create your custom workflows. They are also available in our [GitHub repository](https://github.com/Runware/ComfyUI-Runware/tree/main/workflows). ## API key setup When you first run any workflow using Runware nodes, you'll be prompted to enter your API key. This one-time setup connects your workflow to our cloud infrastructure. > [!NOTE] > You can also manage your API key later through the Runware API Manager node, which allows you to update or change your credentials at any time. ## Available nodes Our integration provides a comprehensive set of nodes for ComfyUI that connect to different Runware API features: ### Configuration nodes - **Runware API Manager**: Set or change your API keys and adjust the max connection timeout directly in ComfyUI, no need to edit config files manually. ### Image generation nodes - **Runware Image Inference**: Perform advanced tasks like text-to-image, inpainting, outpainting, and more. - **Runware PhotoMaker v2**: Create consistent character identities and styles with our photomaker pipeline. - **Runware Model**: Choose specific models to connect with image inference. - **Runware Refiner**: Polish and enhance generated images with advanced tools. - **Runware VAE**: Search and connect a VAE to Image inference. ### Enhancement nodes - **Runware LoRA**: Search and select LoRAs to enhance your workflow. - **Runware LoRA Combine**: Combine up to three LoRAs together for complex effects. - **Runware ControlNet Preprocessor**: Prepare images before using them as guide images in ControlNet. - **Runware ControlNet**: Guide your image generation with ControlNet and guide images. - **Runware ControlNet Combine**: Create complex workflows using multiple ControlNets. - **Runware Embedding**: Search and connect embeddings to image inference. - **Runware Embedding Combine**: Combine multiple embeddings together. - **Runware IP-Adapter**: Use reference images to guide the style and content of generated images. - **Runware IP-Adapter Combine**: Merge multiple IP-Adapter inputs for sophisticated image conditioning. ### Image tools nodes - **Runware Image Upscale**: Enhance image resolution up to 4x. - **Runware Background Removal**: Effortlessly separate subjects from backgrounds. - **Runware Image Masking**: Automatically detect and mask specific elements like faces, hands, and more. - **Runware Image Caption**: Generate descriptive text from images for further workflow integration. ## Support & community This is the official Runware integration, maintained by Runware Inc. We're here to help you every step of the way! Join our [Discord community](https://discord.gg/aJ4UzvBqNU) to share your creations, get help with node configurations, connect with other creators, receive updates about new features... and much more! ### Troubleshooting If you encounter issues while using the Runware nodes in ComfyUI, here's a checklist of things to verify: - Your API key is correctly entered in the API Manager node. - Your internet connection is stable and working. - You've installed the latest version of the ComfyUI-Runware nodes. - ComfyUI has been restarted after installation. - All Python dependencies were successfully installed. - All nodes are properly connected in your workflow. - Required input parameters have values provided. - Model IDs and other references are correct. - Image dimensions are within supported ranges. - API timeout settings are appropriate for your connection speed. - You have sufficient credits in your Runware account. - The ComfyUI console shows no Python errors. When troubleshooting, always check the ComfyUI console for specific error messages that can help identify the exact issue. The console will display a task UUID for any API requests. You can submit this UUID to our support team on Discord or via support page, and we will help you resolve the issue. You can also submit an issue on our [GitHub repository](https://github.com/Runware/ComfyUI-Runware). --- ## Vercel AI SDK integration **URL:** https://runware.ai/docs/platform/vercel-ai **Description:** Use Runware's image generation capabilities through the Vercel AI SDK with our community provider. Complete setup guide and usage examples. ## Introduction The Runware provider for Vercel AI SDK allows you to integrate Runware's image generation capabilities directly into applications built with the Vercel AI SDK. This integration provides a **standardized interface** that follows Vercel's conventions while maintaining **full access to Runware's advanced features** and flexible API. Source code: [https://github.com/Runware/ai-sdk-provider](https://github.com/Runware/ai-sdk-provider) ## Installation Install the provider package alongside the Vercel AI SDK: ```bash npm install @runware/ai-sdk-provider ai@^4.3.16 ``` ## Basic setup Before you start generating images, you'll need to configure your API key. The simplest approach is to set it as an environment variable, which **keeps your credentials secure** and makes deployment easier: ```bash export RUNWARE_API_KEY="your-api-key-here" ``` For advanced configuration options like setting the API key in code or custom connection settings, see the [custom provider configuration](#custom-provider-configuration) section below. Once your API key is configured, you can generate your first image with just a few lines of code: ```javascript import { runware } from '@runware/ai-sdk-provider'; import { experimental_generateImage as generateImage } from 'ai'; const { image } = await generateImage({ model: runware.image('runware:101@1'), prompt: 'A serene mountain landscape at sunset', size: '1024x1024', }); console.log('Generated image:', image.url); ``` That's it! Your first AI-generated image is ready. The provider **handles all the API communication, authentication, and response formatting automatically**. ## Key integration concepts ### Model selection with AIR IDs Runware uses the AIR ID system to identify models across different sources. When working with the Vercel AI SDK provider, you'll specify models using this standardized format: ```javascript // High-quality generation with FLUX.1 Dev const fluxDev = runware.image('runware:101@1'); // Ultra-fast generation with FLUX.1 Schnell const fluxSchnell = runware.image('runware:100@1'); // Community models from Civitai const civitaiModel = runware.image('civitai:133005@782002'); // Your own fine-tuned models const customModel = runware.image('custom:your-model@1'); ``` Each model offers different strengths and characteristics. You can explore the full catalog and find the perfect model for your use case in the [Model Explorer](https://my.runware.ai/models/all). ### Accessing advanced features While the Vercel AI SDK provides a clean, standardized interface, Runware's API offers extensive customization options. You can access these advanced features through the `providerOptions.runware` object: ```javascript const { image } = await generateImage({ model: runware.image('runware:101@1'), prompt: 'A cyberpunk cityscape with neon lights', size: '1024x1024', providerOptions: { runware: { steps: 30, // Higher steps for better quality CFGScale: 7.5, // How closely to follow the prompt scheduler: 'DPM++ 2M', // Sampling algorithm seed: 42, // For reproducible results }, }, }); ``` This approach gives you the best of both worlds: the simplicity and consistency of the Vercel AI SDK with **full access to Runware's powerful features**. For a complete list of available parameters and their effects, see our [Model Explorer](https://runware.ai/docs/models). ## Common usage patterns ### Image transformation Transform existing images while preserving their basic structure. This technique is perfect for style transfer or enhancement: ```javascript const { image } = await generateImage({ model: runware.image('runware:97@2'), // HiDream Dev prompt: 'vibrant cyberpunk style with neon lighting', size: '1024x1024', providerOptions: { runware: { seedImage: 'image-uuid-or-url', // Accepts UUID, URL, or Base64 strength: 0.7, // Controls transformation intensity steps: 20, }, }, }); ``` The `strength` parameter is crucial here. Lower values (0.1-0.4) preserve more of the original image structure, while higher values (0.7-1.0) allow more dramatic transformations. Start with 0.6 to 0.8 for most use cases. ### Batch generation Generate multiple variations of the same concept in a single request. This is particularly useful for giving users choices or A/B testing different approaches: ```javascript // Configure the model to allow multiple images // Note: This model configuration pattern is specific to the Vercel AI SDK const model = runware.image('runware:100@1', { maxImagesPerCall: 4, outputFormat: 'webp', }); const { images } = await generateImage({ model, prompt: 'A friendly AI assistant robot in a modern office', n: 4, // Generate 4 variations size: '1024x1024', providerOptions: { runware: { steps: 4, // Schnell model works well with fewer steps }, }, }); // Process each generated variation images.forEach((img, index) => { console.log(`Variation ${index + 1}:`, img.url); }); ``` Runware excels at batch generation, supporting **up to 20 images in a single request without any speed penalties**. ### Precise editing with inpainting Inpainting allows you to selectively replace parts of an image while keeping the rest intact. It's like intelligent content-aware fill, but guided by AI and your specific prompts: ```javascript const { image } = await generateImage({ model: runware.image('runware:102@1'), // FLUX.1 Fill - specialized for inpainting prompt: 'A beautiful zen garden with cherry blossoms and stone lanterns', size: '1024x1024', providerOptions: { runware: { seedImage: 'base-image-uuid', // Your source image maskImage: 'mask-image-uuid', // Black/white mask defining edit areas steps: 25, }, }, }); ``` To use inpainting effectively, create masks using any image editor where **white pixels indicate areas to regenerate and black pixels are preserved**. This technique is powerful for removing unwanted objects, changing backgrounds, or adding new elements to existing images. ## Configuration options ### Default provider The simplest setup uses environment variables for configuration, which works great for most applications: ```javascript import { runware } from '@runware/ai-sdk-provider'; // Automatically uses RUNWARE_API_KEY from environment ``` This default provider handles authentication automatically and connects to Runware's standard API endpoint. ### Custom provider configuration For more complex applications, you might need custom configuration. The provider supports additional options for flexibility, such as API proxying or custom authentication flows: ```javascript import { createRunware } from '@runware/ai-sdk-provider'; const runware = createRunware({ apiKey: 'your-specific-api-key', // Override environment variable baseURL: 'https://your-proxy.com/v1', // Custom endpoint for proxying headers: { 'X-Proxy-Auth': 'token', // Additional headers as needed } }); ``` ### Model configuration The Vercel AI SDK allows you to configure models with default parameters, which is different from Runware's native SDKs but provides a convenient way to avoid repeating common settings. These defaults apply to every generation with that model instance: ```javascript const highQualityModel = runware.image('runware:101@1', { outputFormat: 'png', // Always use PNG for this model outputQuality: 95, // High quality checkNSFW: true, // Enable content filtering steps: 30, // Default to high quality scheduler: 'DPM++ 2M', // Preferred scheduler }); // Now every generation with this model uses these defaults const { image } = await generateImage({ model: highQualityModel, prompt: 'A stunning landscape photography', size: '1024x1024', // Configuration is already applied }); ``` This pattern is especially useful when you have different quality tiers or specific use cases in your application. Note that this model configuration approach is specific to the Vercel AI SDK integration. ## Error handling Robust error handling is essential for production applications. The provider includes descriptive error messages to help you debug issues quickly and provide meaningful feedback to users: ```javascript try { const { image } = await generateImage({ model: runware.image('runware:101@1'), prompt: 'A detailed architectural rendering', size: '1024x1024', }); // Success - use the generated image console.log('Generated successfully:', image.url); } catch (error) { if (error.name === 'RunwareAPIError') { // API-specific errors with detailed information console.error('Runware API Error:', error.message); console.error('Status Code:', error.status); } else { // Network errors, timeout, or other issues console.error('Request failed:', error.message); } } ``` Common error scenarios include insufficient credits, invalid model IDs, unsupported parameter combinations, or network connectivity issues. The provider surfaces these clearly so your application can respond appropriately and provide good user experience. ## TypeScript support The provider includes comprehensive TypeScript definitions for all APIs, model configurations, and response types. Your IDE will provide autocomplete and type checking for the entire feature set. --- ## OpenAI Compatibility **URL:** https://runware.ai/docs/platform/openai **Description:** Use Runware's text inference through any OpenAI-compatible client. Drop-in replacement with the same endpoint format, streaming, and SDK support. ## Introduction Runware exposes a fully **OpenAI-compatible chat completions endpoint** at `https://api.runware.ai/v1/chat/completions`. If you already use the OpenAI SDK or any tool that speaks the OpenAI protocol, you can point it at Runware by changing two values: the **base URL** and the **API key**. This is the fastest way to get started with Runware's text inference. There is **no Runware-specific parsing required**, so any OpenAI-compatible client or framework will work out of the box. > [!NOTE] > If you need access to Runware-specific features like `taskUUID` tracking, `includeCost`, or the `async` delivery method, use the [native API](https://runware.ai/docs/platform/streaming) instead. The OpenAI-compatible endpoint focuses on broad compatibility with the standard OpenAI request and response format. ## Quick start Send a standard chat completion request to `https://api.runware.ai/v1/chat/completions` using your Runware API key and a Runware model ID: ```json { "model": "minimax:m2.7@0", "messages": [ { "role": "user", "content": "What is the capital of France?" } ], "max_completion_tokens": 256 } ``` The request format is identical to the [OpenAI Chat Completions API](https://platform.openai.com/docs/api-reference/chat/create). The only difference is that `model` uses a **Runware AIR ID** (e.g., `minimax:m2.7@0`, `google:gemini@3.1-pro`) instead of an OpenAI model name. **curl**: ```bash curl -X POST https://api.runware.ai/v1/chat/completions \ -H "Authorization: Bearer $RUNWARE_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "minimax:m2.7@0", "messages": [{"role": "user", "content": "What is the capital of France?"}], "max_completion_tokens": 256 }' ``` **Python**: ```python from openai import OpenAI client = OpenAI( api_key="your_runware_api_key", base_url="https://api.runware.ai/v1", ) response = client.chat.completions.create( model="minimax:m2.7@0", messages=[{"role": "user", "content": "What is the capital of France?"}], max_completion_tokens=256, ) print(response.choices[0].message.content) ``` **TypeScript**: ```typescript import OpenAI from 'openai'; const client = new OpenAI({ apiKey: 'your_runware_api_key', baseURL: 'https://api.runware.ai/v1', }); const response = await client.chat.completions.create({ model: 'minimax:m2.7@0', messages: [{ role: 'user', content: 'What is the capital of France?' }], max_completion_tokens: 256, }); console.log(response.choices[0].message.content); ``` ## Streaming Set `"stream": true` to receive tokens as they are generated, exactly like you would with the OpenAI API. To include token counts at the end of the stream, add `stream_options`: ```json { "model": "minimax:m2.7@0", "stream": true, "stream_options": { "include_usage": true }, "messages": [ { "role": "user", "content": "Tell me a joke" } ], "max_completion_tokens": 512 } ``` The SSE response format is **identical to OpenAI's**. Content arrives in `choices[0].delta.content`, and the stream ends with `data: [DONE]`. ### Streaming with OpenAI SDKs The OpenAI Python and TypeScript SDKs handle all SSE parsing for you: **Python**: ```python from openai import OpenAI client = OpenAI( api_key="your_runware_api_key", base_url="https://api.runware.ai/v1", ) with client.chat.completions.stream( model="minimax:m2.7@0", messages=[{"role": "user", "content": "Tell me a joke"}], max_tokens=512, ) as stream: for text in stream.text_stream: print(text, end="", flush=True) ``` **TypeScript**: ```typescript import OpenAI from 'openai'; const client = new OpenAI({ apiKey: 'your_runware_api_key', baseURL: 'https://api.runware.ai/v1', }); const stream = await client.chat.completions.create({ model: 'minimax:m2.7@0', messages: [{ role: 'user', content: 'Tell me a joke' }], max_tokens: 512, stream: true, }); for await (const chunk of stream) { const content = chunk.choices[0]?.delta?.content; if (content) process.stdout.write(content); } ``` **curl**: ```bash curl -N -X POST https://api.runware.ai/v1/chat/completions \ -H "Authorization: Bearer $RUNWARE_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "minimax:m2.7@0", "stream": true, "stream_options": {"include_usage": true}, "messages": [{"role": "user", "content": "Tell me a joke"}], "max_completion_tokens": 512 }' ``` ### Reasoning models Models that support internal reasoning (like MiniMax M2.7) stream reasoning tokens in `choices[0].delta.reasoning_content` before the final response appears in `choices[0].delta.content`. This follows the same pattern as OpenAI's reasoning models. ```text // First chunk - role assignment data: {"id":"chatcmpl-e36b09e6-7a1c-4d8f-b5e2-9c4a3f6d8e1b","object":"chat.completion.chunk","model":"minimax:m2.7@0","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]} // Reasoning chunks - choices[0].delta.reasoning_content data: {"id":"chatcmpl-e36b09e6-7a1c-4d8f-b5e2-9c4a3f6d8e1b","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"reasoning_content":"The user asks 2+2. Simple arithmetic."},"finish_reason":null}]} // Actual response - switches to choices[0].delta.content data: {"id":"chatcmpl-e36b09e6-7a1c-4d8f-b5e2-9c4a3f6d8e1b","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"4"},"finish_reason":null}]} // Usage chunk (when stream_options.include_usage is set) data: {"id":"chatcmpl-e36b09e6-7a1c-4d8f-b5e2-9c4a3f6d8e1b","object":"chat.completion.chunk","choices":[],"usage":{"prompt_tokens":51,"completion_tokens":38,"total_tokens":89,"cost":0.000134}} // Final chunk - finish reason data: {"id":"chatcmpl-e36b09e6-7a1c-4d8f-b5e2-9c4a3f6d8e1b","object":"chat.completion.chunk","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]} data: [DONE] ``` ## Key differences from OpenAI While the endpoint is fully compatible with the OpenAI protocol, there are a few things to be aware of: | Aspect | OpenAI | Runware | | --- | --- | --- | | **Model IDs** | `gpt-4o`, `gpt-4o-mini` | AIR format: `minimax:m2.7@0`, `google:gemini@3.1-pro` | | **Authentication** | OpenAI API key | Runware API key (same `Authorization: Bearer` header) | | **Base URL** | `https://api.openai.com/v1` | `https://api.runware.ai/v1` | | **Available models** | OpenAI models only | Multiple providers: MiniMax, Google Gemini, and more | | **Naming convention** | snake\_case (`finish_reason`, `reasoning_content`) | snake\_case (same as OpenAI on this endpoint) | > [!NOTE] > This endpoint uses **snake\_case** field names (`finish_reason`, `max_tokens`) to match the OpenAI convention. The [native API](https://runware.ai/docs/platform/streaming) uses **camelCase** (`finishReason`, `maxTokens`). ## Key differences from the native API If you are choosing between the OpenAI-compatible endpoint and the native Runware API, here is how they compare: | | Native API | OpenAI-compatible | | --- | --- | --- | | **Endpoint** | `https://api.runware.ai/v1` | `https://api.runware.ai/v1/chat/completions` | | **Request format** | Array of task objects with `taskType` and `taskUUID` | Single object (standard OpenAI format) | | **Streaming trigger** | `"deliveryMethod": "stream"` | `"stream": true` | | **Async support** | Yes (`"deliveryMethod": "async"` with webhooks/polling) | No | | **Cost tracking** | `includeCost: true` on the request | Included in the `usage` chunk when `stream_options.include_usage` is set | | **Usage tracking** | `includeUsage: true` on the request | `stream_options: { "include_usage": true }` | | **Task tracking** | `taskUUID` for request/response correlation | Standard `id` field on response chunks | | **Naming convention** | camelCase | snake\_case | Use the **OpenAI-compatible endpoint** when you want the fastest integration path or are already working with the OpenAI SDK. Use the **native API** when you want a consistent request format across all Runware modalities (images, video, audio, text, 3d) and access to features like async delivery and task-level tracking. --- ## Model Search API **URL:** https://runware.ai/docs/platform/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. ```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](#request-tasktype) - **Type**: `const:modelSearch` - **Required**: true - **Value**: `modelSearch` The type of task to perform. ### [taskUUID](#request-taskuuid) - **Type**: `string` - **Format**: `UUID v4` UUID v4 identifier for tracking tasks and matching async responses. Must be unique per task. ### [search](#request-search) - **Type**: `string` - **Required**: true Search query to find models by name, description or AIR ID. ### [tags](#request-tags) - **Type**: `array of strings` Filter models by specific tags. ### [category](#request-category) - **Type**: `string` Filter models by category. **Allowed values**: `checkpoint` `lora` `lycoris` `vae` `embeddings` ### [type](#request-type) - **Type**: `string` Filter checkpoint models by type. Only applicable when category is `checkpoint`. **Allowed values**: `base` `inpainting` `refiner` ### [architecture](#request-architecture) - **Type**: `string` Filter by model architecture. ### [conditioning](#request-conditioning) - **Type**: `string` Filter ControlNet models by their conditioning type. **Allowed values**: `blur` `canny` `depth` `gray` `hed` `inpaint` `inpaintdepth` `lineart` `lowquality` `normal` `openmlsd` `openpose` `outfit` `pix2pix` `qrcode` `scribble` `seg` `shuffle` `sketch` `softedge` `tile` ### [visibility](#request-visibility) - **Type**: `string` - **Default**: `all` Filter by visibility status (e.g., public, private, all). **Allowed values**: `public` `private` `all` ### [limit](#request-limit) - **Type**: `integer` - **Min**: `1` - **Max**: `100` - **Default**: `20` Maximum number of results to return. ### [offset](#request-offset) - **Type**: `integer` - **Min**: `0` - **Default**: `0` Number of results to skip for pagination. ## 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](#response-tasktype) - **Type**: `string` - **Required**: true - **Value**: `modelSearch` Identifier for the type of task being performed ### [taskUUID](#response-taskuuid) - **Type**: `string` - **Required**: true - **Format**: `UUID v4` UUID v4 identifier for tracking tasks and matching async responses. Must be unique per task. ### [totalResults](#response-totalresults) - **Type**: `integer` - **Required**: true - **Min**: `0` Total number of models matching the search criteria. ### [results](#response-results) - **Path**: `results.air` - **Type**: `array of objects (11 properties)` - **Required**: true List of models found. #### [air](#response-results-air) - **Path**: `results.air` - **Type**: `string` - **Required**: true Artificial Intelligence Resource identifier. #### [name](#response-results-name) - **Path**: `results.name` - **Type**: `string` - **Required**: true Name of the model. #### [version](#response-results-version) - **Path**: `results.version` - **Type**: `string` - **Required**: true Version of the model. #### [category](#response-results-category) - **Path**: `results.category` - **Type**: `string` - **Required**: true Category of the model (e.g., checkpoint, lora). #### [architecture](#response-results-architecture) - **Path**: `results.architecture` - **Type**: `string` Model architecture (e.g., sdxl, flux). #### [imageURL](#response-results-imageurl) - **Path**: `results.imageURL` - **Type**: `string` - **Required**: true - **Format**: `URI` URL of the model's representative image. #### [thumbnailURL](#response-results-thumbnailurl) - **Path**: `results.thumbnailURL` - **Type**: `string` - **Required**: true - **Format**: `URI` URL of the model's thumbnail image. #### [tags](#response-results-tags) - **Path**: `results.tags` - **Type**: `array of strings` List of tags associated with the model. #### [private](#response-results-private) - **Path**: `results.private` - **Type**: `boolean` Whether the model is private. #### [primary](#response-results-primary) - **Path**: `results.primary` - **Type**: `boolean` Whether this is the primary version of the model. #### [baseModel](#response-results-basemodel) - **Path**: `results.baseModel` - **Type**: `string` The base model this model is derived from. --- ## Model Upload **URL:** https://runware.ai/docs/platform/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 have full control over who can access your models. Set them as **public** (accessible to all platform users) or **private** (restricted to your organization). The API also supports **multiple versions** of the same model, allowing you to iterate on weights or configurations while maintaining a clean version 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. ```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](#request-tasktype) - **Type**: `const:modelUpload` - **Required**: true - **Value**: `modelUpload` The type of task to perform. ### [taskUUID](#request-taskuuid) - **Type**: `string` - **Format**: `UUID v4` UUID v4 identifier for tracking tasks and matching async responses. Must be unique per task. ### [category](#request-category) - **Type**: `string` - **Required**: true Category of the model. **Allowed values**: `checkpoint` `lora` `lycoris` `vae` `embeddings` ### [format](#request-format) - **Type**: `string` - **Required**: true Format of the model file. **Allowed values**: `safetensors` ### [air](#request-air) - **Type**: `string` Artificial Intelligence Resource identifier. Format: `provider:model@version`. ### [uniqueIdentifier](#request-uniqueidentifier) - **Type**: `string` Unique identifier for the model. ### [name](#request-name) - **Type**: `string` - **Required**: true Name of the model. ### [version](#request-version) - **Type**: `string` - **Required**: true Version of the model. ### [downloadURL](#request-downloadurl) - **Type**: `string` - **Required**: true - **Format**: `URI` URL where the model file is hosted. ### [private](#request-private) - **Type**: `boolean` - **Default**: `false` Whether the model should be private. ### [heroImageURL](#request-heroimageurl) - **Type**: `string` - **Format**: `URI` URL of the hero image. ### [tags](#request-tags) - **Type**: `array of strings` Tags associated with the model. ### [shortDescription](#request-shortdescription) - **Type**: `string` Short description of the model. ### [comment](#request-comment) - **Type**: `string` Additional comments or notes. ### Checkpoints When `category` is set to `checkpoint`, the following additional parameters are available: ### [type](#request-type) - **Type**: `string` Type of the model (specific to category). **Allowed values**: `base` `inpainting` `refiner` ### [architecture](#request-architecture) - **Type**: `string` - **Required**: true Architecture of the model. **Allowed values**: `sd1x` `sd1lcm` `sd1distilled` `sdhyper` `sd2x` `sdxl` `sdxllcm` `sdxldistilled` `sdxlturbo` `sdxlhyper` `sdxllightning` `illustrious` `noobai` `pony` `flux1s` `flux1d` `fluxkontextdev` `z_image` `z_image_turbo` ### [defaultScheduler](#request-defaultscheduler) - **Type**: `string` Default scheduler. ### [defaultSteps](#request-defaultsteps) - **Type**: `integer` - **Min**: `1` Default number of inference steps. ### [defaultCFG](#request-defaultcfg) - **Type**: `float` - **Min**: `0` Default classifier-free guidance scale. ### [defaultStrength](#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](#request-type) - **Type**: `string` Type of the model (specific to category). **Allowed values**: `positive` `negative` ### [architecture](#request-architecture) - **Type**: `string` - **Required**: true Architecture of the model. **Allowed values**: `sd1x` `sd1lcm` `sd1distilled` `sdhyper` `sd2x` `sd3` `sdxl` `sdxllcm` `sdxldistilled` `sdxlturbo` `sdxlhyper` `sdxllightning` `illustrious` `noobai` `pony` `flux1s` `flux1d` `fluxkontextdev` `flux_2_dev` `flux2klein_base_4b` `flux2klein_4b` `flux2klein_base_9b` `flux2klein_9b` `z_image` `z_image_turbo` `auraflow` `hidreamfast` `hidreamdev` `hidreamfull` `qwen_image` `qwen_image_edit` `qwen_image_edit_plus` `qwen_image_layered` `wan_2_2_a14b_t2v` `wan_2_2_a14b_i2v` ### [defaultWeight](#request-defaultweight) - **Type**: `float` Default weight for the model. ### [positiveTriggerWords](#request-positivetriggerwords) - **Type**: `string` List of positive trigger words. ### LyCORIS When `category` is set to `lycoris`, the following additional parameters are available: ### [type](#request-type) - **Type**: `string` Type of the model (specific to category). **Allowed values**: `positive` `negative` ### [architecture](#request-architecture) - **Type**: `string` - **Required**: true Architecture of the model. **Allowed values**: `sd1x` `sd1lcm` `sd1distilled` `sdhyper` `sd2x` `sd3` `sdxl` `sdxllcm` `sdxldistilled` `sdxlturbo` `sdxlhyper` `sdxllightning` `illustrious` `noobai` `pony` `flux1s` `flux1d` `fluxkontextdev` `flux_2_dev` `flux2klein_base_4b` `flux2klein_4b` `flux2klein_base_9b` `flux2klein_9b` `z_image` `z_image_turbo` `auraflow` `hidreamfast` `hidreamdev` `hidreamfull` `qwen_image` `qwen_image_edit` `qwen_image_edit_plus` `qwen_image_layered` `wan_2_2_a14b_t2v` `wan_2_2_a14b_i2v` ### [defaultWeight](#request-defaultweight) - **Type**: `float` Default weight for the model. ### [positiveTriggerWords](#request-positivetriggerwords) - **Type**: `string` List of positive trigger words. ### VAE When `category` is set to `vae`, the following additional parameters are available: ### [architecture](#request-architecture) - **Type**: `string` - **Required**: true Architecture of the model. **Allowed values**: `sd1x` `sd1lcm` `sd1distilled` `sdhyper` `sdxl` `sdxllcm` `sdxldistilled` `sdxlturbo` `sdxlhyper` `sdxllightning` `illustrious` `noobai` `pony` ### Embeddings When `category` is set to `embeddings`, the following additional parameters are available: ### [type](#request-type) - **Type**: `string` Type of the model (specific to category). **Allowed values**: `positive` `negative` ### [architecture](#request-architecture) - **Type**: `string` - **Required**: true Architecture of the model. **Allowed values**: `sd1x` `sd1lcm` `sd1distilled` `sdhyper` `sdxl` `sdxllcm` `sdxldistilled` `sdxlturbo` `sdxlhyper` `sdxllightning` `illustrious` `noobai` `pony` ## 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](#response-tasktype) - **Type**: `string` - **Value**: `modelUpload` Identifier for the type of task being performed ### [taskUUID](#response-taskuuid) - **Type**: `string` - **Required**: true - **Format**: `UUID v4` UUID v4 identifier for tracking tasks and matching async responses. Must be unique per task. ### [status](#response-status) - **Type**: `string` - **Required**: true Status of the upload operation phase. **Possible values**: `validated` `downloaded` `optimized` `stored` `ready` `failed` ### [message](#response-message) - **Type**: `string` - **Required**: true Status message or error details. ### [air](#response-air) - **Type**: `string` The AIR identifier of the uploaded model. --- ## Account Management **URL:** https://runware.ai/docs/platform/account-management **Description:** Retrieve account details, team information, API keys, and usage statistics for your organization using the account management API. ## Introduction The `accountManagement` task provides **programmatic access to your organization's account information**, including team members, API keys, balance, and usage statistics. This is useful for building internal dashboards or monitoring tools that integrate with your Runware account. Currently, only the `getDetails` operation is available. Additional operations for managing settings, team members, and API keys will be added in future updates. ## 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 **account management task**. The following JSON snippet shows the basic structure of a request object. ```json [ { "taskType": "accountManagement", "taskUUID": "f4dd3dfe-955f-49d5-a785-7e3b633d6e7a", "operation": "getDetails" } ] ``` --- ### [taskType](#request-tasktype) - **Type**: `const:accountManagement` - **Required**: true - **Value**: `accountManagement` The type of task to perform. ### [taskUUID](#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](#request-operation) - **Type**: `string` - **Required**: true The specific account management operation to perform. **Allowed values**: `getDetails` ## Response Results will be delivered in the format below. ```json { "data": [ { "taskType": "accountManagement", "taskUUID": "f4dd3dfe-955f-49d5-a785-7e3b633d6e7a", "operation": "getDetails", "organizationUUID": "a6379343-9ff2-46a0-996b-e4a7b3057c88", "organizationName": "Acme Corporation", "AIRSource": "acme", "balance": 2450.75, "team": [ { "name": "John Smith", "email": "john.smith@acme.com", "roles": [ "Owner" ], "joinedAt": "2024-01-15T10:30:00Z" }, { "name": "Emily Johnson", "email": "emily.johnson@acme.com", "roles": [ "Admin" ], "joinedAt": "2024-03-22T14:20:00Z" }, { "name": "Michael Chen", "email": "michael.chen@acme.com", "roles": [ "Developer" ], "joinedAt": "2024-05-10T09:15:00Z" } ], "apiKeys": [ { "name": "Production API Key", "apiKey": "YHluz4gk5KU4ZZWr****************", "description": "Main production environment key", "createdAt": "2024-01-20T11:00:00Z", "enabled": true, "requests": 15420, "lastUsedAt": "2025-10-12T08:45:30Z" }, { "name": "Development API Key", "apiKey": "fhVbIFjuDlSwZJgY****************", "description": "Testing and development", "createdAt": "2024-02-05T16:30:00Z", "enabled": true, "requests": 3287, "lastUsedAt": "2025-10-11T15:22:18Z" } ], "usage": { "total": { "credits": 48920.50, "requests": 2540318 }, "today": { "credits": 35.80, "requests": 1850 }, "last7Days": { "credits": 412.25, "requests": 21400 }, "last30Days": { "credits": 1685.90, "requests": 87560 } } } ] } ``` --- ### [taskType](#response-tasktype) - **Type**: `string` - **Required**: true - **Value**: `accountManagement` Identifier for the type of task being performed ### [taskUUID](#response-taskuuid) - **Type**: `string` - **Required**: true - **Format**: `UUID v4` UUID v4 identifier for tracking tasks and matching async responses. Must be unique per task. ### [organizationName](#response-organizationname) - **Type**: `string` - **Required**: true The name of the organization. ### [organizationUUID](#response-organizationuuid) - **Type**: `string` - **Required**: true - **Format**: `UUID v4` Unique identifier for the organization. ### [balance](#response-balance) - **Path**: `balance.amount` - **Type**: `object (3 properties)` - **Required**: true Current account balance and currency. #### [amount](#response-balance-amount) - **Path**: `balance.amount` - **Type**: `float` - **Required**: true Current balance amount. #### [freeBalance](#response-balance-freebalance) - **Path**: `balance.freeBalance` - **Type**: `float` Available free credit balance. #### [currency](#response-balance-currency) - **Path**: `balance.currency` - **Type**: `string` - **Required**: true Currency code (e.g., USD). ### [team](#response-team) - **Path**: `team.name` - **Type**: `array of objects (4 properties)` - **Required**: true List of team members. #### [name](#response-team-name) - **Path**: `team.name` - **Type**: `string` - **Required**: true Full name of the team member. #### [email](#response-team-email) - **Path**: `team.email` - **Type**: `string` - **Required**: true - **Format**: `EMAIL` Email address of the team member. #### [roles](#response-team-roles) - **Path**: `team.roles` - **Type**: `array of strings` - **Required**: true Roles assigned to the team member. #### [joinedAt](#response-team-joinedat) - **Path**: `team.joinedAt` - **Type**: `string` - **Format**: `DATE-TIME` Date and time when the member joined. ### [apiKeys](#response-apikeys) - **Path**: `apiKeys.apiKey` - **Type**: `array of objects (7 properties)` - **Required**: true List of API keys associated with the account. #### [apiKey](#response-apikeys-apikey) - **Path**: `apiKeys.apiKey` - **Type**: `string` - **Required**: true The API key string (partially masked). #### [name](#response-apikeys-name) - **Path**: `apiKeys.name` - **Type**: `string` - **Required**: true Name or label for the API key. #### [description](#response-apikeys-description) - **Path**: `apiKeys.description` - **Type**: `string` Description of the API key. #### [enabled](#response-apikeys-enabled) - **Path**: `apiKeys.enabled` - **Type**: `boolean` - **Required**: true Whether the API key is active. #### [createdAt](#response-apikeys-createdat) - **Path**: `apiKeys.createdAt` - **Type**: `string` - **Required**: true - **Format**: `DATE-TIME` Date and time when the key was created. #### [lastUsedAt](#response-apikeys-lastusedat) - **Path**: `apiKeys.lastUsedAt` - **Type**: `string` - **Format**: `DATE-TIME` Date and time when the key was last used. #### [requests](#response-apikeys-requests) - **Path**: `apiKeys.requests` - **Type**: `integer` Total number of requests made with this key. ### [usage](#response-usage) - **Path**: `usage.today` - **Type**: `object (12 properties)` - **Required**: true Usage statistics for different time periods. #### [today](#response-usage-today) - **Path**: `usage.today` - **Type**: `object (2 properties)` - **Required**: true Usage stats for today. ##### [credits](#response-usage-today-credits) - **Path**: `usage.today.credits` - **Type**: `float` - **Required**: true Total credits consumed. ##### [requests](#response-usage-today-requests) - **Path**: `usage.today.requests` - **Type**: `integer` - **Required**: true Total API requests made. #### [last7Days](#response-usage-last7days) - **Path**: `usage.last7Days` - **Type**: `object (2 properties)` - **Required**: true Usage stats for the last 7 days. ##### [credits](#response-usage-last7days-credits) - **Path**: `usage.last7Days.credits` - **Type**: `float` - **Required**: true Total credits consumed. ##### [requests](#response-usage-last7days-requests) - **Path**: `usage.last7Days.requests` - **Type**: `integer` - **Required**: true Total API requests made. #### [last30Days](#response-usage-last30days) - **Path**: `usage.last30Days` - **Type**: `object (2 properties)` - **Required**: true Usage stats for the last 30 days. ##### [credits](#response-usage-last30days-credits) - **Path**: `usage.last30Days.credits` - **Type**: `float` - **Required**: true Total credits consumed. ##### [requests](#response-usage-last30days-requests) - **Path**: `usage.last30Days.requests` - **Type**: `integer` - **Required**: true Total API requests made. #### [total](#response-usage-total) - **Path**: `usage.total` - **Type**: `object (2 properties)` - **Required**: true Total lifetime usage stats. ##### [credits](#response-usage-total-credits) - **Path**: `usage.total.credits` - **Type**: `float` - **Required**: true Total credits consumed. ##### [requests](#response-usage-total-requests) - **Path**: `usage.total.requests` - **Type**: `integer` - **Required**: true Total API requests made. --- ## Image Upload **URL:** https://runware.ai/docs/platform/image-upload **Description:** Learn how to upload images to use in various tasks, including image-to-image generation, background removal, upscaling, and more. ## Introduction Images can be uploaded to the Runware platform for use as inputs in other tasks like image-to-image generation, upscaling, ControlNet preprocessing, and background removal. A few things to keep in mind: - Valid extensions are: `jpeg`, `jpg`, `png`, `webp`, `bmp` and `gif`. - There is no limit on image size but we save them with a maximum of 2048 pixels in width or height, maintaining the original aspect ratio. - Images are deleted 30 days after last use. As long as you continue using them, we will continue saving them indefinitely. > [!NOTE] > Support for uploading additional media types (video, audio) is planned for a future release. ## 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 **image upload task**. The following JSON snippet shows the basic structure of a request object. **All properties are explained in detail in the next section**. ```json [ { "taskType": "imageUpload", "taskUUID": "50836053-a0ee-4cf5-b9d6-ae7c5d140ada", "image": "data:image/png;base64,iVBORw0KGgo..." } ] ``` --- ### [taskType](#request-tasktype) - **Type**: `const:imageUpload` - **Required**: true - **Value**: `imageUpload` ### [taskUUID](#request-taskuuid) - **Type**: `string` - **Required**: true - **Format**: `UUID v4` UUID v4 identifier for tracking tasks and matching async responses. Must be unique per task. ### [image](#request-image) - **Type**: `string` - **Required**: true Image to upload (URL, Data URI, or Base64). ## Response Results will be delivered in the format below. ```json { "data": { "taskType": "imageUpload", "taskUUID": "9ed8a593-5515-46f3-9cd7-81ab0508176c", "imageUUID": "989ba605-1449-4e1e-b462-cd83ec9c1a67" } } ``` --- ### [taskType](#response-tasktype) - **Type**: `string` - **Required**: true - **Value**: `imageUpload` Identifier for the type of task being performed ### [taskUUID](#response-taskuuid) - **Type**: `string` - **Required**: true - **Format**: `UUID v4` UUID v4 identifier for tracking tasks and matching async responses. Must be unique per task. ### [imageUUID](#response-imageuuid) - **Type**: `string` - **Required**: true Unique identifier for the uploaded image --- ## Task Details **URL:** https://runware.ai/docs/platform/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. This is useful for **debugging** failed requests by inspecting the exact payload that was sent, **recovering** responses that your application didn't store, and **auditing** historical API interactions. The returned `request` and `response` objects are untyped because their structure depends on the original task type. They are the whole original 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. ```json [ { "taskType": "getTaskDetails", "taskUUID": "a770f077-f413-47de-9dac-be0b26a35da6" } ] ``` --- ### [taskType](#request-tasktype) - **Type**: `const:getTaskDetails` - **Required**: true - **Value**: `getTaskDetails` The type of task to perform. ### [taskUUID](#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 `request` is the original array of task objects you sent to the API. The `response` is the full API response envelope, containing either a `data` array (if the task completed successfully) or an `errors` array (if the task 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/ws/0.5/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](#response-tasktype) - **Type**: `string` - **Required**: true - **Value**: `getTaskDetails` Identifier for the type of task being performed ### [taskUUID](#response-taskuuid) - **Type**: `string` - **Required**: true - **Format**: `UUID v4` UUID v4 identifier for tracking tasks and matching async responses. Must be unique per task. ### [request](#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](#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. ---