NAV
cURL Ruby Python JavaScript

Quick Start

Generate your first AI image in under a minute.

1. Get Your API Key

Get your API key from the API Keys page. You'll need it for all API requests.

2. Generate an Image

Copy this command, replace YOUR_API_TOKEN, and run it:

curl -X POST "https://runapi.ai/api/v1/nano_banana/text_to_image" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"model": "nano-banana", "prompt": "A cute cat wearing a space helmet"}'
require 'net/http'
require 'uri'
require 'json'

uri = URI('https://runapi.ai/api/v1/nano_banana/text_to_image')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
request['Content-Type'] = 'application/json'
request.body = { model: 'nano-banana', prompt: 'A cute cat wearing a space helmet' }.to_json

response = http.request(request)
puts response.body
import requests

response = requests.post(
    'https://runapi.ai/api/v1/nano_banana/text_to_image',
    headers={'Authorization': 'Bearer YOUR_API_TOKEN'},
    json={'model': 'nano-banana', 'prompt': 'A cute cat wearing a space helmet'}
)
print(response.json())
fetch('https://runapi.ai/api/v1/nano_banana/text_to_image', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    model: 'nano-banana',
    prompt: 'A cute cat wearing a space helmet'
  })
})
.then(res => res.json())
.then(data => console.log(data));

Response:

{
  "id": "281e5b0f...f39b9"
}

This creates an image generation task and returns a task ID.

3. Get Your Image

Use the task ID to check the result:

curl "https://runapi.ai/api/v1/nano_banana/text_to_image/YOUR_TASK_ID" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
task_id = 'YOUR_TASK_ID'
uri = URI("https://runapi.ai/api/v1/nano_banana/text_to_image/#{task_id}")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'

response = http.request(request)
puts response.body
task_id = 'YOUR_TASK_ID'
response = requests.get(
    f'https://runapi.ai/api/v1/nano_banana/text_to_image/{task_id}',
    headers={'Authorization': 'Bearer YOUR_API_TOKEN'}
)
print(response.json())
const taskId = 'YOUR_TASK_ID';

fetch(`https://runapi.ai/api/v1/nano_banana/text_to_image/${taskId}`, {
  headers: { 'Authorization': 'Bearer YOUR_API_TOKEN' }
})
.then(res => res.json())
.then(data => console.log(data));

Response when completed:

{
  "id": "281e5b0f...f39b9",
  "status": "completed",
  "model": "nano-banana",
  "images": [
    {
      "url": "https://file.runapi.ai/generated/image1.png"
    }
  ]
}

Poll this endpoint every 5 seconds until status is completed (usually 10-30 seconds). The images array contains your generated image objects.

Tips

Use Callbacks for Production: Instead of polling, provide a callback_url to receive automatic notifications when your task completes. This is more efficient and reliable. See Callbacks below.

Common First-Time Errors:

Error Cause Solution
401 Unauthorized Invalid or missing key Check your API key is correct and included in the header
403 Forbidden Key limit reached or permission denied Check the key has access and has not hit its spending cap
422 Unprocessable Invalid parameters Check required fields: model and prompt
402 Payment Required Insufficient credits Purchase credits or check your balance

Overview

Authentication

runapi.ai uses API keys to authenticate requests. Include your key in the Authorization header:

Authorization: Bearer YOUR_API_TOKEN

Get your API key from the API Keys page.

Base URL

Most API requests (image, video, music generation) should be made to:

https://runapi.ai/api/v1

LLM endpoints use SDK-compatible paths for seamless client integration:

SDK Base URL Endpoints
Anthropic SDK https://runapi.ai /v1/messages, /v1/models
OpenAI SDK https://runapi.ai/v1 /chat/completions, /responses, /models
Gemini (via OpenAI SDK) https://runapi.ai/v1beta/openai /chat/completions, /models

Each SDK constructs the full URL differently — the Anthropic SDK appends /v1/messages to the base, while the OpenAI SDK appends /models directly. The base URLs above ensure all requests land on the correct endpoint without any code changes beyond the URL.

DeepSeek models (deepseek-v4-flash, deepseek-v4-pro) are available through both the Anthropic SDK (/v1/messages) and the OpenAI SDK (/chat/completions), and appear in each SDK's models.list(). Call GET /v1/models to see every model available to your key.

Pricing

Plan pricing and credit options are available at runapi.ai/pricing. For per-model credit usage, see the Credits section in the API area.

Callbacks

Callbacks let us notify your system when a task finishes. Provide a callback_url in your request, and we'll send a POST request to that URL with the final result.

1) Create a callback secret

In the account dashboard, open API Keys and generate a Callback Secret. Save the Base64 value; you'll use it to verify callback signatures.

2) Configure callback_url

Example: include callback_url when creating a task.

{
  "model": "nano-banana",
  "prompt": "A serene mountain landscape",
  "callback_url": "https://your-app.com/callbacks/nano-banana"
}

3) Verify callback signatures

Each callback request includes these headers:

Signature algorithm:

Example: callback signature verification using the raw body.

const crypto = require('crypto');

function verifyCallback(headers, rawBody, secret) {
  const callbackId = headers['x-callback-id'];
  const callbackTimestamp = headers['x-callback-timestamp'];
  const signatureHeader = headers['x-callback-signature'] || '';

  const signedContent = `${callbackId}.${callbackTimestamp}.${rawBody}`;
  const secretBytes = Buffer.from(secret, 'base64');
  const computedSigBase64 = crypto
    .createHmac('sha256', secretBytes)
    .update(signedContent)
    .digest('base64');

  const signatures = signatureHeader
    .split(',')
    .map(s => s.trim())
    .filter(Boolean);

  return signatures.some(expectedSig => {
    if (expectedSig.length !== computedSigBase64.length) {
      return false;
    }
    const expectedBuffer = Buffer.from(expectedSig, 'base64');
    const computedBuffer = Buffer.from(computedSigBase64, 'base64');
    return crypto.timingSafeEqual(expectedBuffer, computedBuffer);
  });
}
import base64
import hashlib
import hmac

def verify_callback(headers, raw_body, secret):
    callback_id = headers.get('X-Callback-Id')
    callback_timestamp = headers.get('X-Callback-Timestamp')
    signature_header = headers.get('X-Callback-Signature', '')

    signed_content = f"{callback_id}.{callback_timestamp}.{raw_body}"
    secret_bytes = base64.b64decode(secret)
    computed_sig_base64 = base64.b64encode(
        hmac.new(secret_bytes, signed_content.encode('utf-8'), hashlib.sha256).digest()
    ).decode('utf-8')

    signatures = [s.strip() for s in signature_header.split(',') if s.strip()]
    return any(hmac.compare_digest(sig, computed_sig_base64) for sig in signatures)
require "base64"
require "openssl"

def verify_callback(headers, raw_body, secret)
  callback_id = headers["x-callback-id"]
  callback_timestamp = headers["x-callback-timestamp"]
  signature_header = headers["x-callback-signature"].to_s

  signed_content = "#{callback_id}.#{callback_timestamp}.#{raw_body}"
  secret_bytes = Base64.decode64(secret)
  computed_sig = Base64.strict_encode64(
    OpenSSL::HMAC.digest("sha256", secret_bytes, signed_content)
  )

  signatures = signature_header.split(",").map(&:strip).reject(&:empty?)
  signatures.any? { |sig| secure_compare(sig, computed_sig) }
end

def secure_compare(a, b)
  return false unless a.bytesize == b.bytesize

  l = a.unpack("C*")
  res = 0
  b.each_byte { |byte| res |= byte ^ l.shift }
  res.zero?
end

Callback payload

The callback body matches the task status response for the same endpoint. Example:

Example: callback payload for a completed task.

{
  "id": "281e5b0*********************f39b9",
  "status": "completed",
  "model": "nano-banana",
  "images": [
    {
      "url": "https://file.runapi.ai/generated/image1.png"
    }
  ]
}

Retry policy

If your endpoint returns a non-2xx response or times out, we'll retry up to 10 times with increasing delays. Respond with a 2xx status quickly and process the payload asynchronously.

Local webhook testing

Test callbacks on your local machine without a public URL. The runapi listen command opens a connection to RunAPI and forwards callback events to a local endpoint — similar to stripe listen.

Install the CLI

Install RunAPI CLI:

curl -fsSL https://runapi.ai/cli/install.sh | sh
runapi login

If you already have the CLI installed, make sure it's up to date.

Forward events to your local server

Start listening and forwarding:

runapi listen --forward-to http://localhost:3000/webhooks
Ready! Webhook signing secret: 4a8b2c...
Forwarding to http://localhost:3000/webhooks
[1] task=281e5b0...f39b9 status=completed → http://localhost:3000/webhooks 200
[2] task=93fa7e1...a82c4 status=completed → http://localhost:3000/webhooks 200

The CLI prints a webhook signing secret on startup. Use this secret in your local application to verify callback signatures. The verification code is identical to production — only the secret string differs.

Trigger a test event

Create a task without callback_url:

curl -X POST https://runapi.ai/api/v1/nano_banana/text_to_image \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "nano-banana", "prompt": "A mountain landscape"}'
require "runapi"

client = RunApi::NanoBanana::Client.new(api_key: "YOUR_API_KEY")
client.text_to_images.create(
  model: "nano-banana",
  prompt: "A mountain landscape"
)
import requests

response = requests.post(
    "https://runapi.ai/api/v1/nano_banana/text_to_image",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    json={"model": "nano-banana", "prompt": "A mountain landscape"},
)
print(response.json())
import RunApi from "@runapi.ai/sdk";

const client = new RunApi({ apiKey: "YOUR_API_KEY" });
await client.nanoBanana.textToImages.create({
  model: "nano-banana",
  prompt: "A mountain landscape",
});

Do not include a callback_url in the request. When the task completes, the event appears in your runapi listen terminal and is forwarded to your local server.

If your local endpoint returns a non-2xx response, the CLI leaves the event unacknowledged and retries it instead of marking the task delivered.

Verify signatures locally

The forwarded callback includes the same X-Callback-Id, X-Callback-Timestamp, and X-Callback-Signature headers as production callbacks. Use the listen signing secret (printed on CLI startup) instead of your production callback secret.

The signature algorithm is identical — see Verify callback signatures above.

Routing rules

Scenario Where callbacks go
callback_url set Your public URL (production behavior, unchanged)
No callback_url, runapi listen running Forwarded to your local server via CLI
No callback_url, no listener running Callback is dropped (not queued for later)

CLI reference

Flag Description
--forward-to <url> Local URL to POST callbacks to. Without this flag, events are printed to the terminal but not forwarded.
--api-key <key> API key. Overrides RUNAPI_API_KEY environment variable.
--base-url <url> API base URL. Defaults to https://runapi.ai.

SDKs, CLI, and Agent Skills

RunAPI publishes public SDKs, the runapi CLI, and portable agent skills under the runapi-ai GitHub organization.

Use these links when you want package-first integrations instead of raw HTTP requests.

SDK Index

Each model has one multi-language SDK repository with JavaScript, Ruby, and Go source. JavaScript packages are published under @runapi.ai/*; Go modules live under each <model>-sdk/go module; Ruby SDK source is public and RubyGems publishing is temporarily deferred.

ElevenLabs SDK

Flux Kontext SDK

Flux 2 SDK

GPT Image SDK

GPT Image 2 SDK

GPT-4o Image SDK

Grok Imagine SDK

Hailuo SDK

Ideogram V3 SDK

Imagen 4 SDK

Infinitalk SDK

Kling SDK

Luma SDK

Nano Banana SDK

Qwen 2 SDK

Recraft SDK

Runway SDK

Seedance SDK

Seedream SDK

Suno SDK

Topaz SDK

Veo 3 SDK

Wan SDK

Z Image SDK

RunAPI CLI

runapi is the command-line client for RunAPI — one binary calls 100+ AI models with a JSON-first interface that maps cleanly to scripts, CI pipelines, and agent runtimes.

Install

Linux / macOS (servers, CI, Dockerfiles):

curl -fsSL https://runapi.ai/cli/install.sh | sh

Homebrew (macOS / Linux):

brew install runapi-ai/tap/runapi

Or paste this prompt to your AI agent (Claude Code, Codex, Gemini CLI, OpenClaw, Hermes):

Install the RunAPI CLI on this machine and wire it into this agent runtime:

1. Run `curl -fsSL https://runapi.ai/cli/install.sh | sh`.
2. Save my API key with `printf '%s' "$RUNAPI_API_KEY" | runapi auth import-token --token -`
   (or run `runapi login` if I'm on a laptop with a browser).
3. Install the CLI skill into this runtime with `runapi agent install-skill --target <claude|codex|gemini|openclaw|hermes>`.
4. Confirm it works by running `runapi version` and `runapi auth status`.

The curl installer detects OS/arch (Linux/macOS, amd64/arm64), verifies a SHA-256 checksum from https://runapi.ai/cli/latest.json, and refuses to write the binary on musl libc distros (Alpine) rather than installing a binary that will crash at runtime.

Pin a release or use a mirror

# Pin to a specific tag
curl -fsSL https://runapi.ai/cli/install.sh | sh -s -- --version v0.1.0

# Install somewhere else
curl -fsSL https://runapi.ai/cli/install.sh | sh -s -- --dir ~/.local/bin

Environment variables also work: RUNAPI_VERSION, RUNAPI_INSTALL_DIR, RUNAPI_INSTALL_BASE, and RUNAPI_DOWNLOAD_BASE (set to a private mirror to fetch the release archive from your own CDN).

Release metadata is published as a stable JSON contract that build pipelines can verify against without depending on the install script:

Each manifest lists Linux and macOS amd64/arm64 archive URLs with their SHA-256 sums.

Headless authentication

The CLI reads credentials from --api-key, then RUNAPI_API_KEY, then ~/.config/runapi/config.json. Override the API endpoint with RUNAPI_BASE_URL.

# Recommended: pipe the key so it never appears in `ps` or shell history
printf '%s' "$RUNAPI_API_KEY" | runapi auth import-token --token -
runapi auth status

# Alternative: keep the key in the environment for the current shell only
export RUNAPI_API_KEY=<your-key>
runapi auth status

auth import-token verifies the key against /api/v1/me before writing; pass --skip-verify to bypass when bootstrapping an offline image. Avoid --token "$RUNAPI_API_KEY" directly on the command line — the value would be visible in ps -ef to other users on the host.

Agent runtime skill

Install the matching CLI skill into a supported agent runtime so commands like runapi suno generate are documented locally:

runapi agent install-skill --target claude
runapi agent install-skill --target codex
runapi agent install-skill --target gemini
runapi agent install-skill --target openclaw
runapi agent install-skill --target hermes
runapi agent list-targets

The skill content lives at runapi-ai/cli-skill and is tagged in lockstep with CLI releases. Use --target-dir <path> to install into a non-standard location.

Agent Skills

RunAPI skills are portable instructions for Codex, Claude Code, and Gemini CLI. Model skill repositories use pure model names, while sdk-skill and cli-skill route SDK and CLI workflows.

Claude

The Claude API provides access to Anthropic's Claude language models. The endpoint is fully compatible with the Anthropic Messages API, so you can use the official Anthropic SDK with RunAPI as the base URL.

Endpoint: POST https://runapi.ai/v1/messages

SDK Quickstart

Using the Anthropic Python SDK:

import anthropic

client = anthropic.Anthropic(
    api_key="YOUR_API_TOKEN",
    base_url="https://runapi.ai"
)

message = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    messages=[
        {"role": "user", "content": "Hello, Claude!"}
    ]
)
print(message.content[0].text)
import Anthropic from '@anthropic-ai/sdk';

const client = new Anthropic({
  apiKey: 'YOUR_API_TOKEN',
  baseURL: 'https://runapi.ai',
});

const message = await client.messages.create({
  model: 'claude-sonnet-4-6',
  max_tokens: 1024,
  messages: [
    { role: 'user', content: 'Hello, Claude!' }
  ],
});
console.log(message.content[0].text);
require "anthropic"

client = Anthropic::Client.new(
  api_key: "YOUR_API_TOKEN",
  base_url: "https://runapi.ai"
)

message = client.messages.create(
  model: "claude-sonnet-4-6",
  max_tokens: 1024,
  messages: [
    { role: "user", content: "Hello, Claude!" }
  ]
)
puts message.content.first.text
curl -X POST "https://runapi.ai/v1/messages" \
  -H "x-api-key: YOUR_API_TOKEN" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet-4-6",
    "max_tokens": 1024,
    "messages": [
      {"role": "user", "content": "Hello, Claude!"}
    ]
  }'

Set base_url (or baseURL) to https://runapi.ai and use your RunAPI API key. Everything else works exactly like the official Anthropic API.

Claude Code

Connect Claude Code to RunAPI:

ANTHROPIC_BASE_URL=https://runapi.ai ANTHROPIC_API_KEY=YOUR_API_TOKEN claude

Set the ANTHROPIC_BASE_URL and ANTHROPIC_API_KEY environment variables, then launch Claude Code as usual.

Claude Authentication

Claude API supports two authentication methods:

Method Header Example
Anthropic-style x-api-key x-api-key: YOUR_API_TOKEN
Bearer token Authorization Authorization: Bearer YOUR_API_TOKEN

Both methods use the same RunAPI API key. The x-api-key header is recommended for compatibility with the Anthropic SDK.

Models

Model ID Description
claude-opus-4-7 Strongest general model for complex tasks
claude-opus-4-6 High-end reasoning model for complex tasks
claude-sonnet-4-6 Best balance of speed and capability
claude-opus-4-5-20251101 High-end reasoning model with tool and reasoning controls
claude-sonnet-4-5-20250929 Balanced chat model with include_thoughts support
claude-haiku-4-5-20251001 Fastest and most affordable

Official aliases are accepted and canonicalized before storage: claude-opus-4-5 -> claude-opus-4-5-20251101, claude-sonnet-4-5 -> claude-sonnet-4-5-20250929, and claude-haiku-4-5 -> claude-haiku-4-5-20251001.

List Models

List Claude models in Anthropic-compatible format:

curl -X GET "https://runapi.ai/v1/models" \
  -H "x-api-key: YOUR_API_TOKEN"
{
  "data": [
    {
      "type": "model",
      "id": "claude-opus-4-7",
      "display_name": "Claude Opus 4.7",
      "created_at": "2026-05-05T08:00:00Z"
    }
  ],
  "has_more": false,
  "first_id": "claude-opus-4-7",
  "last_id": "claude-haiku-4-5-20251001"
}

Count Tokens

Count input tokens before sending a message:

curl -X POST "https://runapi.ai/v1/messages/count_tokens" \
  -H "x-api-key: YOUR_API_TOKEN" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet-4-6",
    "messages": [
      {"role": "user", "content": "Count the tokens for this request."}
    ]
  }'
{
  "input_tokens": 12
}

POST /v1/messages/count_tokens

This endpoint accepts the same Claude Messages request shape and returns a local estimate of input tokens only. Image blocks use a fixed 512-token heuristic instead of model-specific vision counting. Use the final usage from POST /v1/messages for exact billed token counts.

Create a Message

Create a non-streaming message:

curl -X POST "https://runapi.ai/v1/messages" \
  -H "x-api-key: YOUR_API_TOKEN" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet-4-6",
    "max_tokens": 1024,
    "system": "You are a helpful assistant.",
    "messages": [
      {"role": "user", "content": "Explain quantum computing in simple terms."}
    ]
  }'
message = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    system="You are a helpful assistant.",
    messages=[
        {"role": "user", "content": "Explain quantum computing in simple terms."}
    ]
)
const message = await client.messages.create({
  model: 'claude-sonnet-4-6',
  max_tokens: 1024,
  system: 'You are a helpful assistant.',
  messages: [
    { role: 'user', content: 'Explain quantum computing in simple terms.' }
  ],
});
message = client.messages.create(
  model: "claude-sonnet-4-6",
  max_tokens: 1024,
  system: "You are a helpful assistant.",
  messages: [
    { role: "user", content: "Explain quantum computing in simple terms." }
  ]
)

Response:

{
  "id": "msg_01XFDUDYJgAACzvnptvVoYEL",
  "type": "message",
  "role": "assistant",
  "content": [
    {
      "type": "text",
      "text": "Quantum computing uses quantum bits (qubits)..."
    }
  ],
  "model": "claude-sonnet-4-6",
  "stop_reason": "end_turn",
  "usage": {
    "input_tokens": 25,
    "output_tokens": 150
  }
}

POST /v1/messages

Parameters

Parameter Type Required Description
model string Yes Model ID (see Models above)
messages array Yes Array of message objects with role and content
max_tokens integer Yes Maximum tokens to generate
system string No System prompt
stream boolean No Enable SSE streaming (default: false)
temperature number No Sampling temperature (0-1)
top_p number No Nucleus sampling threshold
top_k integer No Top-k sampling
tools array No Tool definitions; web access uses googleSearch when supported
tool_choice object No Tool selection strategy
stop_sequences array No Custom stop sequences
thinking object No Extended thinking configuration
reasoning_effort string No "low" or "high" reasoning control
include_thoughts boolean No Claude Sonnet only; includes internal reasoning output when supported
metadata object No Request metadata

Headers

Header Required Description
x-api-key Yes Your RunAPI API key
anthropic-version No API version string
anthropic-beta No Beta feature flags (e.g., interleaved-thinking-2025-05-14)
Content-Type Yes Must be application/json

Multimodal Input

Send text plus an image in one Claude request:

{
  "model": "claude-sonnet-4-6",
  "max_tokens": 1024,
  "messages": [
    {
      "role": "user",
      "content": [
        { "type": "text", "text": "What is in this image?" },
        {
          "type": "image_url",
          "image_url": {
            "url": "https://cdn.runapi.ai/public/samples/image.jpg"
          }
        }
      ]
    }
  ]
}

Claude accepts the standard Anthropic message format. For multimodal requests, keep media blocks inside messages[].content and use the image_url structure shown above.

Web Access and Reasoning

Enable web access plus reasoning controls:

{
  "model": "claude-sonnet-4-6",
  "max_tokens": 1024,
  "reasoning_effort": "high",
  "include_thoughts": true,
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "googleSearch"
      }
    }
  ],
  "messages": [
    {
      "role": "user",
      "content": "Find the latest public information about Claude 4.6."
    }
  ]
}

Streaming

Stream a response with SSE:

curl -X POST "https://runapi.ai/v1/messages" \
  -H "x-api-key: YOUR_API_TOKEN" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet-4-6",
    "max_tokens": 1024,
    "stream": true,
    "messages": [
      {"role": "user", "content": "Write a haiku about coding."}
    ]
  }'
with client.messages.stream(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    messages=[
        {"role": "user", "content": "Write a haiku about coding."}
    ]
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)
const stream = await client.messages.stream({
  model: 'claude-sonnet-4-6',
  max_tokens: 1024,
  messages: [
    { role: 'user', content: 'Write a haiku about coding.' }
  ],
});

for await (const event of stream) {
  if (event.type === 'content_block_delta') {
    process.stdout.write(event.delta.text);
  }
}
client.messages.create(
  model: "claude-sonnet-4-6",
  max_tokens: 1024,
  stream: true,
  messages: [
    { role: "user", content: "Write a haiku about coding." }
  ]
) do |event|
  print event.content_block_delta.delta.text if event.type == "content_block_delta"
end

Set stream: true to receive Server-Sent Events (SSE). The response is streamed as a series of events:

SSE Event Types

Event Type Description
message_start Session started, includes message metadata
content_block_start New content block begins
content_block_delta Incremental text content
content_block_stop Content block completed
message_delta Final metadata (stop_reason, usage)
message_stop Stream completed

Billing

Claude API uses token-based billing. Credits are calculated based on actual input and output token usage:

Model Input (per 1K tokens) Output (per 1K tokens)
claude-opus-4-7 15 credits 75 credits
claude-opus-4-6 15 credits 75 credits
claude-sonnet-4-6 3 credits 15 credits
claude-opus-4-5-20251101 15 credits 75 credits
claude-sonnet-4-5-20250929 3 credits 15 credits
claude-haiku-4-5-20251001 1 credit 5 credits

A provisional hold (based on credits_per_call) is placed when the request starts. After the response completes, credits are settled based on actual token usage from the usage field.

Veo 3.1

Veo 3.1 on RunAPI creates high-quality videos from text prompts and images. It supports text-to-video, image-to-video, and reference-based generation with two model variants: Quality and Fast.

Model Variants

Model Description Pricing Best For
veo-3.1 Quality model with highest fidelity Pricing Professional content, highest quality
veo-3.1-fast Fast variant with strong results Pricing Fast iterations and drafts

Choose Your Generation Mode

Scenario Mode Input Required
Generate video purely from text description Text to Video Text prompt only
Animate from a single starting image Image to Video 1 image + prompt
Create smooth transition between two images Image to Video 2 images + prompt
Generate video inspired by reference images Reference Images 1-3 reference images + prompt

Generate Video (Text to Video)

Create a video from text prompt:

curl -X POST "https://runapi.ai/api/v1/veo_3_1/text_to_video" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "A dog playing in a park on a sunny day, running through grass with a ball in its mouth",
    "model": "veo-3.1-fast",
    "input_mode": "text",
    "aspect_ratio": "16:9",
    "duration_seconds": 8,
    "enable_translation": true,
    "callback_url": "https://your-domain.com/api/callback"
  }'
require 'net/http'
require 'uri'
require 'json'

uri = URI('https://runapi.ai/api/v1/veo_3_1/text_to_video')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
request['Content-Type'] = 'application/json'
request.body = {
  prompt: 'A dog playing in a park on a sunny day, running through grass with a ball in its mouth',
  model: 'veo-3.1-fast',
  input_mode: 'text',
  aspect_ratio: '16:9',
  duration_seconds: 8,
  enable_translation: true,
  callback_url: 'https://your-domain.com/api/callback'
}.to_json

response = http.request(request)
puts response.body
import requests

url = 'https://runapi.ai/api/v1/veo_3_1/text_to_video'
headers = {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
}
data = {
    'prompt': 'A dog playing in a park on a sunny day, running through grass with a ball in its mouth',
    'model': 'veo-3.1-fast',
    'input_mode': 'text',
    'aspect_ratio': '16:9',
    'duration_seconds': 8,
    'enable_translation': True,
    'callback_url': 'https://your-domain.com/api/callback'
}

response = requests.post(url, headers=headers, json=data)
print(response.json())
const data = {
  prompt: 'A dog playing in a park on a sunny day, running through grass with a ball in its mouth',
  model: 'veo-3.1-fast',
  input_mode: 'text',
  aspect_ratio: '16:9',
  duration_seconds: 8,
  enable_translation: true,
  callback_url: 'https://your-domain.com/api/callback'
};

fetch('https://runapi.ai/api/v1/veo_3_1/text_to_video', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => console.log(data));

HTTP 202 - Task accepted:

{
  "id": "281e5b0*********************f39b9",
  "status": "processing"
}

Generate a video from a text description.

HTTP Request

POST https://runapi.ai/api/v1/veo_3_1/text_to_video

Request Parameters

Parameter Type Required Description
prompt string Yes Text description of the desired video content
model string Yes Model to use: veo-3.1 (Quality) or veo-3.1-fast (Fast)
input_mode string No Input mode (default: text)
aspect_ratio string No Video aspect ratio: 16:9, 9:16, auto (default: 16:9)
duration_seconds integer No Generated video duration: 4, 6, or 8 seconds (default: 8)
seeds integer No Random seed for reproducibility (10000-99999)
enable_translation boolean No Auto-translate prompt to English (default: true)
watermark string No Optional watermark text to add to video
callback_url string No URL for completion callback

Aspect Ratio Options

Response

Returns a task ID for checking generation status:

Field Type Description
id string Unique task identifier

Callback Format

If callback_url is provided, a POST request will be sent when generation completes.

Success Response: - Includes videos array with generated video details (url, resolution, has_audio) - For Image to Video: Contains sources array with input image URLs

Failed Response: - Contains error message describing the failure reason

Success callback example:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "videos": [
    {
      "url": "https://file.runapi.ai/videos/video1.mp4",
      "resolution": "720p",
      "has_audio": true
    }
  ]
}

Failed callback example:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "failed",
  "error": "Your prompt was flagged as violating content policies."
}

Generate Video (Image to Video)

Create a video from one or two images:

curl -X POST "https://runapi.ai/api/v1/veo_3_1/text_to_video" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "The dog starts running energetically across the field, jumping with joy",
    "first_frame_image_url": "https://cdn.runapi.ai/public/samples/image-to-video.jpg",
    "model": "veo-3.1-fast",
    "input_mode": "first_and_last_frames",
    "aspect_ratio": "16:9",
    "duration_seconds": 8,
    "enable_translation": true,
    "callback_url": "https://your-domain.com/api/callback"
  }'
require 'net/http'
require 'uri'
require 'json'

uri = URI('https://runapi.ai/api/v1/veo_3_1/text_to_video')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
request['Content-Type'] = 'application/json'
request.body = {
  prompt: 'The dog starts running energetically across the field, jumping with joy',
  first_frame_image_url: 'https://cdn.runapi.ai/public/samples/image-to-video.jpg',
  model: 'veo-3.1-fast',
  input_mode: 'first_and_last_frames',
  aspect_ratio: '16:9',
  duration_seconds: 8,
  enable_translation: true,
  callback_url: 'https://your-domain.com/api/callback'
}.to_json

response = http.request(request)
puts response.body
import requests

url = 'https://runapi.ai/api/v1/veo_3_1/text_to_video'
headers = {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
}
data = {
    'prompt': 'The dog starts running energetically across the field, jumping with joy',
    'first_frame_image_url': 'https://cdn.runapi.ai/public/samples/image-to-video.jpg',
    'model': 'veo-3.1-fast',
    'input_mode': 'first_and_last_frames',
    'aspect_ratio': '16:9',
    'duration_seconds': 8,
    'enable_translation': True,
    'callback_url': 'https://your-domain.com/api/callback'
}

response = requests.post(url, headers=headers, json=data)
print(response.json())
const data = {
  prompt: 'The dog starts running energetically across the field, jumping with joy',
  first_frame_image_url: 'https://cdn.runapi.ai/public/samples/image-to-video.jpg',
  model: 'veo-3.1-fast',
  input_mode: 'first_and_last_frames',
  aspect_ratio: '16:9',
  duration_seconds: 8,
  enable_translation: true,
  callback_url: 'https://your-domain.com/api/callback'
};

fetch('https://runapi.ai/api/v1/veo_3_1/text_to_video', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => console.log(data));

HTTP 202 - Task accepted:

{
  "id": "281e5b0*********************f39b9",
  "status": "processing"
}

Generate a video from one or two images.

HTTP Request

POST https://runapi.ai/api/v1/veo_3_1/text_to_video

Request Parameters

Parameter Type Required Description
prompt string Yes Description of how the video should animate
first_frame_image_url string Yes First frame image URL
last_frame_image_url string No Last frame image URL
model string Yes Model to use: veo-3.1 or veo-3.1-fast
input_mode string No first_and_last_frames
aspect_ratio string No Video aspect ratio: 16:9, 9:16, auto (default: 16:9)
duration_seconds integer No Generated video duration: 4, 6, or 8 seconds (default: 8)
seeds integer No Random seed for reproducibility (10000-99999)
enable_translation boolean No Auto-translate prompt to English (default: true)
watermark string No Optional watermark text
callback_url string No URL for completion callback

Frame Images

Callback Format

Same as Text to Video callback format.

Example with 2 Images

{
  "prompt": "Smooth transition from sunrise to sunset",
  "first_frame_image_url": "https://cdn.runapi.ai/public/samples/first-frame.jpg",
  "last_frame_image_url": "https://cdn.runapi.ai/public/samples/last-frame.jpg",
  "model": "veo-3.1-fast",
  "input_mode": "first_and_last_frames",
  "aspect_ratio": "16:9"
}

Generate Video (Reference Images)

Create a video using 1-3 reference images:

curl -X POST "https://runapi.ai/api/v1/veo_3_1/text_to_video" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "A person walking through a modern office space with natural lighting",
    "reference_image_urls": [
      "https://cdn.runapi.ai/public/samples/reference-1.jpg",
      "https://cdn.runapi.ai/public/samples/reference-2.jpg",
      "https://cdn.runapi.ai/public/samples/reference-3.jpg"
    ],
    "model": "veo-3.1-fast",
    "input_mode": "reference",
    "aspect_ratio": "16:9",
    "duration_seconds": 8,
    "enable_translation": true,
    "callback_url": "https://your-domain.com/api/callback"
  }'
require 'net/http'
require 'uri'
require 'json'

uri = URI('https://runapi.ai/api/v1/veo_3_1/text_to_video')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
request['Content-Type'] = 'application/json'
request.body = {
  prompt: 'A person walking through a modern office space with natural lighting',
  reference_image_urls: [
    'https://cdn.runapi.ai/public/samples/reference-1.jpg',
    'https://cdn.runapi.ai/public/samples/reference-2.jpg',
    'https://cdn.runapi.ai/public/samples/reference-3.jpg'
  ],
  model: 'veo-3.1-fast',
  input_mode: 'reference',
  aspect_ratio: '16:9',
  duration_seconds: 8,
  enable_translation: true,
  callback_url: 'https://your-domain.com/api/callback'
}.to_json

response = http.request(request)
puts response.body
import requests

url = 'https://runapi.ai/api/v1/veo_3_1/text_to_video'
headers = {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
}
data = {
    'prompt': 'A person walking through a modern office space with natural lighting',
    'reference_image_urls': [
        'https://cdn.runapi.ai/public/samples/reference-1.jpg',
        'https://cdn.runapi.ai/public/samples/reference-2.jpg',
        'https://cdn.runapi.ai/public/samples/reference-3.jpg'
    ],
    'model': 'veo-3.1-fast',
    'input_mode': 'reference',
    'aspect_ratio': '16:9',
    'duration_seconds': 8,
    'enable_translation': True,
    'callback_url': 'https://your-domain.com/api/callback'
}

response = requests.post(url, headers=headers, json=data)
print(response.json())
const data = {
  prompt: 'A person walking through a modern office space with natural lighting',
  reference_image_urls: [
    'https://cdn.runapi.ai/public/samples/reference-1.jpg',
    'https://cdn.runapi.ai/public/samples/reference-2.jpg',
    'https://cdn.runapi.ai/public/samples/reference-3.jpg'
  ],
  model: 'veo-3.1-fast',
  input_mode: 'reference',
  aspect_ratio: '16:9',
  duration_seconds: 8,
  enable_translation: true,
  callback_url: 'https://your-domain.com/api/callback'
};

fetch('https://runapi.ai/api/v1/veo_3_1/text_to_video', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => console.log(data));

HTTP 202 - Task accepted:

{
  "id": "281e5b0*********************f39b9",
  "status": "processing"
}

Generate a video based on 1-3 reference images.

HTTP Request

POST https://runapi.ai/api/v1/veo_3_1/text_to_video

Request Parameters

Parameter Type Required Description
prompt string Yes Description of the desired video content
reference_image_urls array Yes Array of 1-3 reference image URLs
model string Yes Must be veo-3.1-fast for reference
input_mode string No reference
aspect_ratio string No Must be 16:9 for reference
duration_seconds integer No Generated video duration: 4, 6, or 8 seconds (default: 8)
seeds integer No Random seed for reproducibility (10000-99999)
enable_translation boolean No Auto-translate prompt to English (default: true)
watermark string No Optional watermark text
callback_url string No URL for completion callback

Callback Format

Same as Text to Video callback format.

Get Text-to-Video Status

Poll for generation results:

curl "https://runapi.ai/api/v1/veo_3_1/text_to_video/550e8400-e29b-41d4-a716-446655440000" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
require 'net/http'
require 'uri'

task_id = '550e8400-e29b-41d4-a716-446655440000'
uri = URI("https://runapi.ai/api/v1/veo_3_1/text_to_video/#{task_id}")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'

response = http.request(request)
puts response.body
import requests

task_id = '550e8400-e29b-41d4-a716-446655440000'
url = f'https://runapi.ai/api/v1/veo_3_1/text_to_video/{task_id}'
headers = {
    'Authorization': 'Bearer YOUR_API_TOKEN'
}

response = requests.get(url, headers=headers)
print(response.json())
const taskId = '550e8400-e29b-41d4-a716-446655440000';

fetch(`https://runapi.ai/api/v1/veo_3_1/text_to_video/${taskId}`, {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN'
  }
})
.then(response => response.json())
.then(data => console.log(data));

Processing:

{
  "id": "281e5b0*********************f39b9",
  "status": "processing"
}

Completed:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "videos": [
    {
      "url": "https://file.runapi.ai/videos/video1.mp4",
      "resolution": "1080p",
      "has_audio": true
    }
  ]
}

Failed:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "failed",
  "error": "Video generation failed"
}

Retrieve the status and results of a video generation task.

HTTP Request

GET https://runapi.ai/api/v1/veo_3_1/text_to_video/:id

URL Parameters

Parameter Description
id The ID of the task returned from the create request

Response Fields

Field Type Description
id string Unique task identifier
status string Task status: processing, completed, failed
videos array Array of generated video objects (only when completed)
error string Error message (only when failed)

Video Object

Field Type Description
url string Video download URL
resolution string Video resolution (e.g., "1080p", "720p")
has_audio boolean Whether the video has audio

Extend Video

Extend an existing video with new content:

curl -X POST "https://runapi.ai/api/v1/veo_3_1/extend_video" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "source_task_id": "550e8400-e29b-41d4-a716-446655440000",
    "prompt": "The dog continues running through the park, jumping over obstacles",
    "watermark": "MyBrand",
    "callback_url": "https://your-domain.com/api/callback"
  }'
require 'net/http'
require 'uri'
require 'json'

uri = URI('https://runapi.ai/api/v1/veo_3_1/extend_video')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
request['Content-Type'] = 'application/json'
request.body = {
  source_task_id: '550e8400-e29b-41d4-a716-446655440000',
  prompt: 'The dog continues running through the park, jumping over obstacles',
  watermark: 'MyBrand',
  callback_url: 'https://your-domain.com/api/callback'
}.to_json

response = http.request(request)
puts response.body
import requests

url = 'https://runapi.ai/api/v1/veo_3_1/extend_video'
headers = {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
}
data = {
    'source_task_id': '550e8400-e29b-41d4-a716-446655440000',
    'prompt': 'The dog continues running through the park, jumping over obstacles',
    'watermark': 'MyBrand',
    'callback_url': 'https://your-domain.com/api/callback'
}

response = requests.post(url, headers=headers, json=data)
print(response.json())
const data = {
  source_task_id: '550e8400-e29b-41d4-a716-446655440000',
  prompt: 'The dog continues running through the park, jumping over obstacles',
  watermark: 'MyBrand',
  callback_url: 'https://your-domain.com/api/callback'
};

fetch('https://runapi.ai/api/v1/veo_3_1/extend_video', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => console.log(data));

HTTP 202 - Task accepted:

{
  "id": "281e5b0*********************f39b9",
  "status": "processing"
}

Extend an existing Veo 3.1 video by generating new content based on the original video and a text prompt.

HTTP Request

POST https://runapi.ai/api/v1/veo_3_1/extend_video

Request Parameters

Parameter Type Required Description
source_task_id string Yes Task ID of the original video generation
prompt string Yes Text description of the extension content
seeds integer No Random seed for reproducibility (10000-99999)
watermark string No Optional watermark text to add to the extended video
callback_url string No URL for completion callback

Response

Returns a task ID for checking extension status:

Field Type Description
id string Unique task identifier

Callback Format

Same as Text to Video callback format.

Get Video Extension Status

Poll for extension results:

curl "https://runapi.ai/api/v1/veo_3_1/extend_video/550e8400-e29b-41d4-a716-446655440000" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
task_id = '550e8400-e29b-41d4-a716-446655440000'
uri = URI("https://runapi.ai/api/v1/veo_3_1/extend_video/#{task_id}")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'

response = http.request(request)
puts response.body
task_id = '550e8400-e29b-41d4-a716-446655440000'
url = f'https://runapi.ai/api/v1/veo_3_1/extend_video/{task_id}'
headers = {
    'Authorization': 'Bearer YOUR_API_TOKEN'
}

response = requests.get(url, headers=headers)
print(response.json())
const taskId = '550e8400-e29b-41d4-a716-446655440000';

fetch(`https://runapi.ai/api/v1/veo_3_1/extend_video/${taskId}`, {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN'
  }
})
.then(response => response.json())
.then(data => console.log(data));

Processing:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "processing"
}

Completed:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "videos": [
    {
      "url": "https://file.runapi.ai/videos/extended_video1.mp4",
      "resolution": "720p",
      "has_audio": true
    }
  ],
  "sources": [
    {
      "url": "https://file.runapi.ai/videos/original_video1.mp4"
    }
  ]
}

Failed:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "failed",
  "error": "Video extension failed."
}

Retrieve the status and results of a video extension task.

HTTP Request

GET https://runapi.ai/api/v1/veo_3_1/extend_video/:id

URL Parameters

Parameter Description
id The ID of the extension task returned from the create request

Response Fields

Same as Get Text-to-Video Status response format.

Request 1080P Video

Request high-definition 1080P version:

curl -X POST "https://runapi.ai/api/v1/veo_3_1/upscale_video" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "source_task_id": "550e8400-e29b-41d4-a716-446655440000",
    "output_resolution": "1080p",
    "index": 0,
    "callback_url": "https://your-domain.com/api/callback"
  }'
require 'net/http'
require 'uri'
require 'json'

uri = URI('https://runapi.ai/api/v1/veo_3_1/upscale_video')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
request['Content-Type'] = 'application/json'
request.body = {
  source_task_id: '550e8400-e29b-41d4-a716-446655440000',
  output_resolution: '1080p',
  index: 0,
  callback_url: 'https://your-domain.com/api/callback'
}.to_json

response = http.request(request)
puts response.body
import requests

url = 'https://runapi.ai/api/v1/veo_3_1/upscale_video'
headers = {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
}
data = {
    'source_task_id': '550e8400-e29b-41d4-a716-446655440000',
    'output_resolution': '1080p',
    'index': 0,
    'callback_url': 'https://your-domain.com/api/callback'
}

response = requests.post(url, headers=headers, json=data)
print(response.json())
const data = {
  source_task_id: '550e8400-e29b-41d4-a716-446655440000',
  output_resolution: '1080p',
  index: 0,
  callback_url: 'https://your-domain.com/api/callback'
};

fetch('https://runapi.ai/api/v1/veo_3_1/upscale_video', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => console.log(data));

HTTP 202 - Task accepted:

{
  "id": "281e5b0*********************f39b9",
  "status": "processing"
}

Request a high-definition 1080P version of a completed video generation task.

HTTP Request

POST https://runapi.ai/api/v1/veo_3_1/upscale_video

Request Parameters

Parameter Type Required Description
source_task_id string Yes The task ID from a completed video generation
output_resolution string Yes Output resolution: 1080p
index integer No Video index if multiple videos were generated (default: 0)
callback_url string No URL for completion callback

Response

Returns a task ID for checking 1080P conversion status:

Field Type Description
id string Unique task identifier

Callback Format

When the 1080P video is ready, a POST request will be sent to your callback_url.

Success Response: - Includes status: "completed" - Contains videos array with URL and resolution - References source_task_id

Success:

{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "status": "completed",
  "source_task_id": "550e8400-e29b-41d4-a716-446655440000",
  "videos": [
    {
      "url": "https://tempfile.runapi.ai/example.mp4",
      "resolution": "1080p"
    }
  ]
}

Failed Response: - Includes status: "failed" - Contains error message with failure reason

Failed:

{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "status": "failed",
  "source_task_id": "550e8400-e29b-41d4-a716-446655440000",
  "error": "Video generation failed."
}

Request 4K Video

Request ultra-high-definition 4K version:

curl -X POST "https://runapi.ai/api/v1/veo_3_1/upscale_video" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "source_task_id": "550e8400-e29b-41d4-a716-446655440000",
    "output_resolution": "4k",
    "index": 0,
    "callback_url": "https://your-domain.com/api/callback"
  }'
require 'net/http'
require 'uri'
require 'json'

uri = URI('https://runapi.ai/api/v1/veo_3_1/upscale_video')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
request['Content-Type'] = 'application/json'
request.body = {
  source_task_id: '550e8400-e29b-41d4-a716-446655440000',
  output_resolution: '4k',
  index: 0,
  callback_url: 'https://your-domain.com/api/callback'
}.to_json

response = http.request(request)
puts response.body
import requests

url = 'https://runapi.ai/api/v1/veo_3_1/upscale_video'
headers = {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
}
data = {
    'source_task_id': '550e8400-e29b-41d4-a716-446655440000',
    'output_resolution': '4k',
    'index': 0,
    'callback_url': 'https://your-domain.com/api/callback'
}

response = requests.post(url, headers=headers, json=data)
print(response.json())
const data = {
  source_task_id: '550e8400-e29b-41d4-a716-446655440000',
  output_resolution: '4k',
  index: 0,
  callback_url: 'https://your-domain.com/api/callback'
};

fetch('https://runapi.ai/api/v1/veo_3_1/upscale_video', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => console.log(data));

HTTP 202 - Task accepted:

{
  "id": "281e5b0*********************f39b9",
  "status": "processing"
}

Request an ultra-high-definition 4K version of a completed video generation task.

HTTP Request

POST https://runapi.ai/api/v1/veo_3_1/upscale_video

Request Parameters

Parameter Type Required Description
source_task_id string Yes The task ID from a completed video generation
output_resolution string Yes Output resolution: 4k
index integer No Video index if multiple videos were generated (default: 0)
callback_url string No URL for completion callback

Response

Returns a task ID for checking 4K conversion status:

Field Type Description
id string Unique task identifier

Callback Format

When the 4K video is ready, a POST request will be sent to your callback_url.

Success Response: - Includes status: "completed" - Contains videos array with URL and resolution - References source_task_id

Success:

{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "status": "completed",
  "source_task_id": "550e8400-e29b-41d4-a716-446655440000",
  "videos": [
    {
      "url": "https://tempfile.runapi.ai/example_4k.mp4",
      "resolution": "4k"
    }
  ]
}

Failed Response: - Includes status: "failed" - Contains error message with failure reason

Failed:

{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "status": "failed",
  "source_task_id": "550e8400-e29b-41d4-a716-446655440000",
  "error": "The 4K version of this video is unavailable."
}

Get 4K Video Status

Poll for 4K conversion results:

curl "https://runapi.ai/api/v1/veo_3_1/upscale_video/3fa85f64-5717-4562-b3fc-2c963f66afa6" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
task_id = '3fa85f64-5717-4562-b3fc-2c963f66afa6'
uri = URI("https://runapi.ai/api/v1/veo_3_1/upscale_video/#{task_id}")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'

response = http.request(request)
puts response.body
task_id = '3fa85f64-5717-4562-b3fc-2c963f66afa6'
url = f'https://runapi.ai/api/v1/veo_3_1/upscale_video/{task_id}'
headers = {
    'Authorization': 'Bearer YOUR_API_TOKEN'
}

response = requests.get(url, headers=headers)
print(response.json())
const taskId = '3fa85f64-5717-4562-b3fc-2c963f66afa6';

fetch(`https://runapi.ai/api/v1/veo_3_1/upscale_video/${taskId}`, {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN'
  }
})
.then(response => response.json())
.then(data => console.log(data));

Processing:

{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "status": "processing",
  "source_task_id": "550e8400-e29b-41d4-a716-446655440000"
}

Completed:

{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "status": "completed",
  "source_task_id": "550e8400-e29b-41d4-a716-446655440000",
  "videos": [
    {
      "url": "https://tempfile.runapi.ai/example_4k.mp4",
      "resolution": "4k"
    }
  ]
}

Failed:

{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "status": "failed",
  "source_task_id": "550e8400-e29b-41d4-a716-446655440000",
  "error": "The 4K version of this video is unavailable."
}

Check the status of a 4K video conversion request.

HTTP Request

GET https://runapi.ai/api/v1/veo_3_1/upscale_video/:id

URL Parameters

Parameter Description
id The task ID returned from the create request

Response Fields

Field Type Description
id string Unique task identifier
status string Task status: processing, completed, failed
source_task_id string The source video generation task ID
videos array Array of video objects (only when completed)
error string Error message (only when failed)

Video Object

Field Type Description
url string 4K video download URL
resolution string Video resolution ("4k")

Get 1080P Video Status

Poll for 1080P conversion results:

curl "https://runapi.ai/api/v1/veo_3_1/upscale_video/3fa85f64-5717-4562-b3fc-2c963f66afa6" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
task_id = '3fa85f64-5717-4562-b3fc-2c963f66afa6'
uri = URI("https://runapi.ai/api/v1/veo_3_1/upscale_video/#{task_id}")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'

response = http.request(request)
puts response.body
task_id = '3fa85f64-5717-4562-b3fc-2c963f66afa6'
url = f'https://runapi.ai/api/v1/veo_3_1/upscale_video/{task_id}'
headers = {
    'Authorization': 'Bearer YOUR_API_TOKEN'
}

response = requests.get(url, headers=headers)
print(response.json())
const taskId = '3fa85f64-5717-4562-b3fc-2c963f66afa6';

fetch(`https://runapi.ai/api/v1/veo_3_1/upscale_video/${taskId}`, {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN'
  }
})
.then(response => response.json())
.then(data => console.log(data));

Processing:

{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "status": "processing",
  "source_task_id": "550e8400-e29b-41d4-a716-446655440000"
}

Completed:

{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "status": "completed",
  "source_task_id": "550e8400-e29b-41d4-a716-446655440000",
  "videos": [
    {
      "url": "https://tempfile.runapi.ai/example.mp4",
      "resolution": "1080p"
    }
  ]
}

Failed:

{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "status": "failed",
  "source_task_id": "550e8400-e29b-41d4-a716-446655440000",
  "error": "Video generation failed."
}

Check the status of a 1080P video conversion request.

HTTP Request

GET https://runapi.ai/api/v1/veo_3_1/upscale_video/:id

URL Parameters

Parameter Description
id The task ID returned from the create request

Response Fields

Field Type Description
id string Unique task identifier
status string Task status: processing, completed, failed
source_task_id string The source video generation task ID
videos array Array of video objects (only when completed)
error string Error message (only when failed)

Video Object

Field Type Description
url string 1080P video download URL
resolution string Video resolution ("1080p")

Seedance

Seedance on RunAPI provides video creation models. It spans the stable seedance-1.5-pro, the newer seedance-2.0 / seedance-2.0-fast with frame-based and multimodal reference inputs, and the lightweight seedance-v1-* family for quick 5s / 10s clips.

Model Variants

Model Description Pricing Best For
seedance-1.5-pro Mature model for text-to-video and image-to-video with camera lock support Pricing Stable production usage
seedance-2.0 Newer model with first/last frame and multimodal reference inputs Pricing Richer guided generation
seedance-2.0-fast Faster and cheaper 2.x variant Pricing Rapid iteration
seedance-v1-lite Lightweight text-to-video and image-to-video (with optional end frame) Pricing Quick clips with fine-grained control
seedance-v1-pro Higher-quality v1 text-to-video and image-to-video Pricing Premium v1 generation
seedance-v1-pro-fast Image-to-video only, fastest v1 option Pricing Rapid image animation

Seedance Endpoints

Task Endpoint Models
Create video task Create Seedance Text-to-Video seedance-1.5-pro, seedance-2.0, seedance-2.0-fast, seedance-v1-lite, seedance-v1-pro, seedance-v1-pro-fast
Check video status Get Seedance Text-to-Video Status -

Input Modes

seedance-1.5-pro

seedance-2.0 / seedance-2.0-fast

seedance-v1-lite / seedance-v1-pro

seedance-v1-pro-fast

Create Seedance Text-to-Video

Create a Seedance video task:

curl -X POST "https://runapi.ai/api/v1/seedance/text_to_video" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "seedance-1.5-pro",
    "prompt": "A cinematic drone shot of a mountain lake at sunrise with mist rising from the water",
    "aspect_ratio": "16:9",
    "output_resolution": "720p",
    "duration_seconds": 8,
    "generate_audio": false,
    "callback_url": "https://your-domain.com/api/callback"
  }'
require 'net/http'
require 'uri'
require 'json'

uri = URI('https://runapi.ai/api/v1/seedance/text_to_video')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
request['Content-Type'] = 'application/json'
request.body = {
  model: 'seedance-1.5-pro',
  prompt: 'A cinematic drone shot of a mountain lake at sunrise with mist rising from the water',
  aspect_ratio: '16:9',
  output_resolution: '720p',
  duration_seconds: 8,
  generate_audio: false,
  callback_url: 'https://your-domain.com/api/callback'
}.to_json

response = http.request(request)
puts response.body
import requests

url = 'https://runapi.ai/api/v1/seedance/text_to_video'
headers = {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
}
data = {
    'model': 'seedance-1.5-pro',
    'prompt': 'A cinematic drone shot of a mountain lake at sunrise with mist rising from the water',
    'aspect_ratio': '16:9',
    'output_resolution': '720p',
    'duration_seconds': 8,
    'generate_audio': False,
    'callback_url': 'https://your-domain.com/api/callback'
}

response = requests.post(url, headers=headers, json=data)
print(response.json())
const data = {
  model: 'seedance-1.5-pro',
  prompt: 'A cinematic drone shot of a mountain lake at sunrise with mist rising from the water',
  aspect_ratio: '16:9',
  output_resolution: '720p',
  duration_seconds: 8,
  generate_audio: false,
  callback_url: 'https://your-domain.com/api/callback'
};

fetch('https://runapi.ai/api/v1/seedance/text_to_video', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => console.log(data));

HTTP 202 - Task accepted:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "processing"
}

HTTP Request

POST https://runapi.ai/api/v1/seedance/text_to_video

Request Parameters

Parameter Type Required Description
model string Yes seedance-1.5-pro, seedance-2.0, seedance-2.0-fast, seedance-v1-lite, seedance-v1-pro, or seedance-v1-pro-fast
prompt string Yes Text prompt. seedance-1.5-pro: 3–2500; seedance-2.0 / seedance-2.0-fast: 3–20000; seedance-v1-*: 3–10000 characters
callback_url string No HTTPS callback URL for completion events
aspect_ratio string Conditional Required for seedance-1.5-pro and for seedance-v1-lite / seedance-v1-pro text-to-video. 2.x supports 1:1, 4:3, 3:4, 16:9, 9:16, 21:9, auto. seedance-v1-lite: 1:1, 4:3, 3:4, 16:9, 9:16, 9:21. seedance-v1-pro: 1:1, 4:3, 3:4, 16:9, 9:16, 21:9. Rejected in v1 image-to-video mode (derived from image).
output_resolution string No seedance-1.5-pro, seedance-2.0, seedance-v1-lite, seedance-v1-pro: 480p, 720p, 1080p. seedance-2.0-fast: 480p, 720p. seedance-v1-pro-fast: 720p, 1080p
duration_seconds integer Conditional seedance-1.5-pro required: 4, 8, or 12. 2.x: integer 415. seedance-v1-*: required; must be 5 or 10
generate_audio boolean No 1.5-pro / 2.x only. Whether to generate audio
enable_safety_checker boolean No Content safety check toggle
source_image_urls array No seedance-1.5-pro only. Up to 2 source images for image-to-video
lock_camera boolean No Lock camera movement. Supported by seedance-1.5-pro, seedance-v1-lite, seedance-v1-pro
seed integer No seedance-v1-lite / seedance-v1-pro only. Random seed in [-1, 2147483647]; -1 = random
first_frame_image_url string Conditional 2.x frame mode first frame image URL. Also triggers v1 image-to-video mode and is required for seedance-v1-pro-fast
last_frame_image_url string No 2.x frame mode, or seedance-v1-lite image-to-video end frame image URL
reference_image_urls array No 2.x only. Reference image URLs (reference mode)
reference_video_urls array No 2.x only. Max 3 reference videos, total ≤ 15s (reference mode)
reference_audio_urls array No 2.x only. Reference audio URLs; requires at least one image or video (reference mode)
web_search boolean No 2.x only. Optional web search toggle

Response

Field Type Description
id string Unique task identifier
status string Initial async status, typically processing

Callback Format

If callback_url is provided, a POST request will be sent when the task completes.

Success callback example:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "videos": [
    {
      "url": "https://tempfile.runapi.ai/generated-video.mp4"
    }
  ]
}

Failed callback example:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "failed",
  "error": "Task failed"
}

Get Seedance Text-to-Video Status

Check the status of a Seedance task:

curl "https://runapi.ai/api/v1/seedance/text_to_video/YOUR_TASK_ID" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
task_id = 'YOUR_TASK_ID'
uri = URI("https://runapi.ai/api/v1/seedance/text_to_video/#{task_id}")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'

response = http.request(request)
puts response.body
task_id = 'YOUR_TASK_ID'
response = requests.get(
    f'https://runapi.ai/api/v1/seedance/text_to_video/{task_id}',
    headers={'Authorization': 'Bearer YOUR_API_TOKEN'}
)
print(response.json())
const taskId = 'YOUR_TASK_ID';

fetch(`https://runapi.ai/api/v1/seedance/text_to_video/${taskId}`, {
  headers: { 'Authorization': 'Bearer YOUR_API_TOKEN' }
})
.then(res => res.json())
.then(data => console.log(data));

Completed response example:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "videos": [
    {
      "url": "https://tempfile.runapi.ai/generated-video.mp4"
    }
  ],
  "last_frame_image_url": "https://tempfile.runapi.ai/generated-last-frame.png"
}

HTTP Request

GET https://runapi.ai/api/v1/seedance/text_to_video/:id

Response Fields

Field Type Description
id string Task identifier
status string processing, completed, or failed
videos array Generated video URLs when completed
last_frame_image_url string Present when the request included a last frame image
error string Error message when the task fails

Seedream

Seedream on RunAPI supports text-to-image and image editing workflows.

Models

Model Type Pricing
seedream-4.5-text-to-image Text-to-image Pricing
seedream-4.5-edit Image edit Pricing
seedream-5-lite-text-to-image Text-to-image Pricing
seedream-5-lite-edit Image edit Pricing
seedream-v4-text-to-image Text-to-image Pricing
seedream-v4-edit Image edit Pricing

Seedream Endpoints

Task Endpoint Method
Create image Create Seedream Text-to-Image POST
Edit image Create Seedream Edit Image POST
Check text-to-image status Get Seedream Text-to-Image Status GET
Check edit status Get Seedream Edit Image Status GET

Create Seedream Text-to-Image

curl -X POST "https://runapi.ai/api/v1/seedream/text_to_image" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "seedream-4.5-text-to-image",
    "prompt": "A cinematic portrait of a traveler crossing a rainy neon street",
    "aspect_ratio": "16:9",
    "output_quality": "basic"
  }'

POST https://runapi.ai/api/v1/seedream/text_to_image

Parameter Type Required Description
model string Yes seedream-4.5-text-to-image, seedream-5-lite-text-to-image, or seedream-v4-text-to-image
prompt string Yes 4.5 models accept 1-3000 chars; 5-Lite models accept 3-3000 chars; v4 models accept 1-5000 chars
aspect_ratio string Conditional Required for 4.5 and 5-Lite text models; 1:1, 4:3, 3:4, 16:9, 9:16, 2:3, 3:2, 21:9
output_quality string Conditional Required for 4.5 and 5-Lite text models; basic or high
callback_url string No Webhook URL for completion notification
output_resolution string No v4 only; 1k, 2k, or 4k; default 1k
output_count integer No v4 only; 1-6 images, default 1
seed integer No v4 only; random seed for reproducible output
enable_safety_checker boolean No Optional content safety check toggle; default false

Seedream v4 text-to-image request

curl -X POST "https://runapi.ai/api/v1/seedream/text_to_image" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "seedream-v4-text-to-image",
    "prompt": "A precise product render of a glass teapot on white marble",
    "aspect_ratio": "16:9",
    "output_resolution": "2k",
    "output_count": 3,
    "seed": 12345,
    "enable_safety_checker": true
  }'

Create Seedream Edit Image

curl -X POST "https://runapi.ai/api/v1/seedream/edit_image" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "seedream-v4-edit",
    "prompt": "Place the logo on a blue outdoor cap",
    "source_image_urls": ["https://cdn.runapi.ai/public/samples/image.jpg"],
    "aspect_ratio": "1:1",
    "output_resolution": "4k",
    "output_count": 1,
    "enable_safety_checker": false
  }'

POST https://runapi.ai/api/v1/seedream/edit_image

Parameter Type Required Description
model string Yes seedream-4.5-edit, seedream-5-lite-edit, or seedream-v4-edit
prompt string Yes 4.5 models accept 1-3000 chars; 5-Lite models accept 3-3000 chars; v4 models accept 1-5000 chars
source_image_urls array Yes Source image URLs; v4 edit accepts up to 10 image URLs
aspect_ratio string Conditional Required for 4.5 and 5-Lite edit models; optional for v4; 1:1, 4:3, 3:4, 16:9, 9:16, 2:3, 3:2, 21:9
output_quality string Conditional Required for 4.5 and 5-Lite edit models; basic or high
callback_url string No Webhook URL for completion notification
output_resolution string No v4 only; 1k, 2k, or 4k; default 1k
output_count integer No v4 only; 1-6 images, default 1
seed integer No v4 only; random seed for reproducible output
enable_safety_checker boolean No Optional content safety check toggle; default false

Response

{
  "id": "281e5b0f39b9",
  "status": "processing"
}

Get Seedream Text-to-Image Status

curl "https://runapi.ai/api/v1/seedream/text_to_image/YOUR_TASK_ID" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

GET https://runapi.ai/api/v1/seedream/text_to_image/:id

Get Seedream Edit Image Status

curl "https://runapi.ai/api/v1/seedream/edit_image/YOUR_TASK_ID" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

GET https://runapi.ai/api/v1/seedream/edit_image/:id

Completed response

{
  "id": "281e5b0f39b9",
  "status": "completed",
  "images": [
    {
      "url": "https://file.runapi.ai/seedream/result.png"
    }
  ]
}

Failed response

{
  "id": "281e5b0f39b9",
  "status": "failed",
  "error": "Prompt rejected"
}

Runway

Runway provides text_to_video and extend_video endpoints.

Create Text To Video

curl -X POST "https://runapi.ai/api/v1/runway/text_to_video" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "A camera glide through ocean mist at sunrise",
    "duration_seconds": 5,
    "output_resolution": "720p",
    "aspect_ratio": "16:9"
  }'

Response

{
  "id": "281e5b0f...f39b9",
  "status": "processing"
}

POST https://runapi.ai/api/v1/runway/text_to_video

Pricing: Runway model page.

Parameter Type Required Description
prompt string Yes Video prompt.
duration_seconds integer Yes 5 or 10.
output_resolution string Yes 720p or 1080p.
first_frame_image_url string No First frame image for image-to-video.
aspect_ratio string No Required for text-to-video.
watermark string No Watermark text.
callback_url string No Completion webhook URL.

Get Text To Video

GET https://runapi.ai/api/v1/runway/text_to_video/{id}

Completed response

{
  "id": "281e5b0f...f39b9",
  "status": "completed",
  "videos": [
    { "id": "video-1", "url": "https://file.runapi.ai/video.mp4" }
  ],
  "images": [
    { "url": "https://file.runapi.ai/cover.png" }
  ]
}

Create Extend Video

POST https://runapi.ai/api/v1/runway/extend_video

Pricing: Runway model page.

Parameter Type Required Description
source_task_id string Yes Source task ID.
prompt string Yes How to continue the video.
output_resolution string Yes 720p or 1080p.
watermark string No Watermark text.
callback_url string No Completion webhook URL.

Get Extend Video

GET https://runapi.ai/api/v1/runway/extend_video/{id}

Runway Aleph

Runway Aleph provides the edit_video endpoint.

Create Edit Video

POST https://runapi.ai/api/v1/runway_aleph/edit_video

curl -X POST "https://runapi.ai/api/v1/runway_aleph/edit_video" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Transform the scene into moody dusk lighting",
    "source_video_url": "https://storage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4",
    "reference_image_url": "https://raw.githubusercontent.com/github/explore/main/topics/python/python.png"
  }'
Parameter Type Required Description
prompt string Yes Transformation prompt.
source_video_url string Yes Source video URL.
reference_image_url string No Style reference image URL.
aspect_ratio string No 16:9, 9:16, 4:3, 3:4, 1:1, 21:9.
seed integer No Random seed.
callback_url string No Completion webhook URL.

Get Edit Video

GET https://runapi.ai/api/v1/runway_aleph/edit_video/{id}

Completed response

{
  "id": "281e5b0f...f39b9",
  "status": "completed",
  "videos": [
    { "url": "https://file.runapi.ai/runway-aleph.mp4" }
  ],
  "images": [
    { "url": "https://file.runapi.ai/runway-aleph.png" }
  ]
}

Kling

Kling is a video generation model on RunAPI. The kling-3.0 model supports text-to-video and image-to-video with both single-shot and multi-shot modes, plus element references for reusable subjects and styles.

Model Variants

Model Description Pricing Best For
kling-3.0 Kling 3.0, supports single-shot and multi-shot generation with element references Pricing Cinematic video generation with scene control
kling-ai-avatar-pro Kling AI Avatar Pro, high-quality avatar video driven by audio Pricing Professional-grade talking avatar videos
kling-ai-avatar-standard Kling AI Avatar Standard, efficient avatar video driven by audio Pricing Quick talking avatar videos
kling-ai-avatar-v1-pro Kling AI Avatar v1 Pro, high-quality avatar video driven by audio Pricing V1 Pro talking avatar videos
kling-v1-avatar-standard Kling Avatar v1 Standard, efficient avatar video driven by audio Pricing V1 Standard talking avatar videos
kling-v2.1-pro Kling V2.1 Pro image-to-video with optional final-frame control Pricing Image-anchored clips with start/end framing
kling-v2.1-standard Kling V2.1 Standard image-to-video, efficient image animation Pricing Lower-cost image-to-video drafts
kling-v2.1-master-text-to-video Kling V2.1 Master text-to-video with higher-quality rendering Pricing Premium text-to-video clips
kling-v2.1-master-image-to-video Kling V2.1 Master image-to-video with higher-quality rendering Pricing Premium image-anchored clips
kling-v2.5-turbo-text-to-video-pro Kling V2.5 Turbo text-to-video, fast high-quality generation Pricing Fast text-to-video with turbo speed
kling-v2.5-turbo-image-to-video-pro Kling V2.5 Turbo image-to-video, fast high-quality generation Pricing Fast image-to-video with turbo speed

Kling Endpoints

Task Endpoint Models
Create text-to-video task Create Kling Text-to-Video kling-3.0
Check text-to-video status Get Kling Text-to-Video Status -
Create AI avatar task Create AI Avatar kling-ai-avatar-pro, kling-ai-avatar-standard, kling-ai-avatar-v1-pro, kling-v1-avatar-standard
Check AI avatar status Get AI Avatar Status -
Create V2.1 / V2.5 video task Create V2.1 and V2.5 Video kling-v2.1-pro, kling-v2.1-standard, kling-v2.1-master-text-to-video, kling-v2.1-master-image-to-video, kling-v2.5-turbo-text-to-video-pro, kling-v2.5-turbo-image-to-video-pro
Check V2.1 / V2.5 video status Get V2.1 and V2.5 Video Status -
Create motion control task Create Motion Control kling-3.0
Check motion control status Get Motion Control Status -

Single-shot vs Multi-shot

Kling 3.0 supports two generation modes controlled by the multi_shots flag.

Single-shot mode (default)

Multi-shot mode

Element References

Kling 3.0 supports reusable "elements" — named subjects or styles you can reference inside any prompt using the @element_name syntax. Define each element under kling_elements, then mention it by name in your prompt or multi_prompt[i].prompt.

Reference the element inside a prompt with @element_name, for example: "@alice walks through the neon-lit alley at night".

Example request with element references:

{
  "model": "kling-3.0",
  "prompt": "@alice and @bob stand back to back in the rain",
  "kling_elements": [
    {
      "name": "alice",
      "description": "A young woman in a red jacket with short black hair",
      "element_input_urls": [
        "https://cdn.runapi.ai/public/samples/portrait.jpg",
        "https://cdn.runapi.ai/public/samples/portrait.jpg"
      ]
    },
    {
      "name": "bob",
      "description": "A tall man in a leather coat",
      "element_input_urls": [
        "https://cdn.runapi.ai/public/samples/portrait-2.jpg",
        "https://cdn.runapi.ai/public/samples/portrait-2.jpg"
      ]
    }
  ]
}

Create Kling Text-to-Video

Create a single-shot Kling text-to-video task:

curl -X POST "https://runapi.ai/api/v1/kling/text_to_video" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "kling-3.0",
    "prompt": "A cinematic drone shot of a mountain lake at sunrise with mist rising from the water",
    "aspect_ratio": "16:9",
    "duration_seconds": 8,
    "output_resolution": "1080p",
    "callback_url": "https://your-domain.com/api/callback"
  }'
require 'net/http'
require 'uri'
require 'json'

uri = URI('https://runapi.ai/api/v1/kling/text_to_video')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
request['Content-Type'] = 'application/json'
request.body = {
  model: 'kling-3.0',
  prompt: 'A cinematic drone shot of a mountain lake at sunrise with mist rising from the water',
  aspect_ratio: '16:9',
  duration_seconds: 8,
  output_resolution: '1080p',
  callback_url: 'https://your-domain.com/api/callback'
}.to_json

response = http.request(request)
puts response.body
import requests

url = 'https://runapi.ai/api/v1/kling/text_to_video'
headers = {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
}
data = {
    'model': 'kling-3.0',
    'prompt': 'A cinematic drone shot of a mountain lake at sunrise with mist rising from the water',
    'aspect_ratio': '16:9',
    'duration_seconds': 8,
    'output_resolution': '1080p',
    'callback_url': 'https://your-domain.com/api/callback'
}

response = requests.post(url, headers=headers, json=data)
print(response.json())
const data = {
  model: 'kling-3.0',
  prompt: 'A cinematic drone shot of a mountain lake at sunrise with mist rising from the water',
  aspect_ratio: '16:9',
  duration_seconds: 8,
  output_resolution: '1080p',
  callback_url: 'https://your-domain.com/api/callback'
};

fetch('https://runapi.ai/api/v1/kling/text_to_video', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => console.log(data));

Create a multi-shot Kling text-to-video task:

curl -X POST "https://runapi.ai/api/v1/kling/text_to_video" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "kling-3.0",
    "multi_shots": true,
    "enable_sound": true,
    "aspect_ratio": "16:9",
    "output_resolution": "1080p",
    "multi_prompt": [
      { "prompt": "A lone astronaut steps out of a lunar lander onto the dusty grey surface", "duration_seconds": 4 },
      { "prompt": "Wide shot of the astronaut planting a flag as Earth rises on the horizon", "duration_seconds": 5 },
      { "prompt": "Close-up on the visor reflecting the stars and the Earth", "duration_seconds": 3 }
    ]
  }'
require 'net/http'
require 'uri'
require 'json'

uri = URI('https://runapi.ai/api/v1/kling/text_to_video')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
request['Content-Type'] = 'application/json'
request.body = {
  model: 'kling-3.0',
  multi_shots: true,
  enable_sound: true,
  aspect_ratio: '16:9',
  output_resolution: '1080p',
  multi_prompt: [
    { prompt: 'A lone astronaut steps out of a lunar lander onto the dusty grey surface', duration_seconds: 4 },
    { prompt: 'Wide shot of the astronaut planting a flag as Earth rises on the horizon', duration_seconds: 5 },
    { prompt: 'Close-up on the visor reflecting the stars and the Earth', duration_seconds: 3 }
  ]
}.to_json

response = http.request(request)
puts response.body
import requests

url = 'https://runapi.ai/api/v1/kling/text_to_video'
headers = {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
}
data = {
    'model': 'kling-3.0',
    'multi_shots': True,
    'enable_sound': True,
    'aspect_ratio': '16:9',
    'output_resolution': '1080p',
    'multi_prompt': [
        { 'prompt': 'A lone astronaut steps out of a lunar lander onto the dusty grey surface', 'duration_seconds': 4 },
        { 'prompt': 'Wide shot of the astronaut planting a flag as Earth rises on the horizon', 'duration_seconds': 5 },
        { 'prompt': 'Close-up on the visor reflecting the stars and the Earth', 'duration_seconds': 3 }
    ]
}

response = requests.post(url, headers=headers, json=data)
print(response.json())
const data = {
  model: 'kling-3.0',
  multi_shots: true,
  enable_sound: true,
  aspect_ratio: '16:9',
  output_resolution: '1080p',
  multi_prompt: [
    { prompt: 'A lone astronaut steps out of a lunar lander onto the dusty grey surface', duration_seconds: 4 },
    { prompt: 'Wide shot of the astronaut planting a flag as Earth rises on the horizon', duration_seconds: 5 },
    { prompt: 'Close-up on the visor reflecting the stars and the Earth', duration_seconds: 3 }
  ]
};

fetch('https://runapi.ai/api/v1/kling/text_to_video', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => console.log(data));

HTTP 202 - Task accepted:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "processing"
}

HTTP Request

POST https://runapi.ai/api/v1/kling/text_to_video

Request Parameters

Parameter Type Required Description
model string Yes Must be kling-3.0
prompt string Conditional Required in single-shot mode. Text description of the desired video
enable_sound boolean Conditional Whether to generate sound. Must be true when multi_shots is true
duration_seconds number No Total video duration in seconds, 3 through 15
aspect_ratio string Conditional 16:9, 9:16, or 1:1. Optional when first_frame_image_url is provided (auto-adapts to the image)
output_resolution string No Output resolution: 720p, 1080p, or 4k
multi_shots boolean No Set to true to enable multi-shot mode
multi_prompt array Conditional Required when multi_shots is true. Ordered array of {prompt, duration_seconds} items, one per shot
first_frame_image_url string No First-frame image URL
last_frame_image_url string No Last-frame image URL for single-shot mode
kling_elements array No Element references for reusable subjects or styles (see Element References)
callback_url string No HTTPS callback URL for completion events

multi_prompt item

Parameter Type Required Description
prompt string Yes Text prompt for this shot, max 500 characters
duration_seconds integer Yes Duration of this shot in seconds, integer from 1 to 12

kling_elements item

Parameter Type Required Description
name string Yes Element name, referenced in prompts as @name
description string Yes Human-readable description of the element
element_input_urls array No 2 to 4 JPG or PNG image URLs, at least 300×300 pixels each, max 10 MB per image
element_input_video_urls array No 1 MP4 or MOV video URL, max 50 MB

Response

Field Type Description
id string Unique task identifier
status string Initial async status, typically processing

Callback Format

If callback_url is provided, a POST request will be sent when generation completes.

Success callback example:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "videos": [
    {
      "url": "https://tempfile.runapi.ai/generated-video.mp4"
    }
  ]
}

Failed callback example:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "failed",
  "error": "Generation failed"
}

Get Kling Text-to-Video Status

Check the status of a Kling task:

curl "https://runapi.ai/api/v1/kling/text_to_video/YOUR_TASK_ID" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
task_id = 'YOUR_TASK_ID'
uri = URI("https://runapi.ai/api/v1/kling/text_to_video/#{task_id}")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'

response = http.request(request)
puts response.body
task_id = 'YOUR_TASK_ID'
response = requests.get(
    f'https://runapi.ai/api/v1/kling/text_to_video/{task_id}',
    headers={'Authorization': 'Bearer YOUR_API_TOKEN'}
)
print(response.json())
const taskId = 'YOUR_TASK_ID';

fetch(`https://runapi.ai/api/v1/kling/text_to_video/${taskId}`, {
  headers: { 'Authorization': 'Bearer YOUR_API_TOKEN' }
})
.then(res => res.json())
.then(data => console.log(data));

Completed response example:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "videos": [
    {
      "url": "https://tempfile.runapi.ai/generated-video.mp4"
    }
  ]
}

Failed response example:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "failed",
  "error": "Generation failed"
}

HTTP Request

GET https://runapi.ai/api/v1/kling/text_to_video/:id

Response Fields

Field Type Description
id string Task identifier
status string processing, completed, or failed
videos array Generated video URLs when completed
error string Error message when generation fails

Create AI Avatar

Generate a talking avatar video from a portrait image and an audio file. The AI Avatar feature animates a face to match spoken audio, producing natural lip-sync and head movements.

Create an AI Avatar task:

curl -X POST "https://runapi.ai/api/v1/kling/ai_avatar" \
  -H "Authorization: Bearer {{API_KEY}}" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "kling-ai-avatar-pro",
    "source_image_url": "https://cdn.runapi.ai/public/samples/portrait.jpg",
    "source_audio_url": "https://cdn.runapi.ai/public/samples/voice.mp3",
    "prompt": "A professional presenter speaking confidently",
    "callback_url": "https://your-domain.com/api/callback"
  }'
require 'net/http'
require 'uri'
require 'json'

uri = URI('https://runapi.ai/api/v1/kling/ai_avatar')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer {{API_KEY}}'
request['Content-Type'] = 'application/json'
request.body = {
  model: 'kling-ai-avatar-pro',
  source_image_url: 'https://cdn.runapi.ai/public/samples/portrait.jpg',
  source_audio_url: 'https://cdn.runapi.ai/public/samples/voice.mp3',
  prompt: 'A professional presenter speaking confidently',
  callback_url: 'https://your-domain.com/api/callback'
}.to_json

response = http.request(request)
puts response.body
import requests

url = 'https://runapi.ai/api/v1/kling/ai_avatar'
headers = {
    'Authorization': 'Bearer {{API_KEY}}',
    'Content-Type': 'application/json'
}
data = {
    'model': 'kling-ai-avatar-pro',
    'source_image_url': 'https://cdn.runapi.ai/public/samples/portrait.jpg',
    'source_audio_url': 'https://cdn.runapi.ai/public/samples/voice.mp3',
    'prompt': 'A professional presenter speaking confidently',
    'callback_url': 'https://your-domain.com/api/callback'
}

response = requests.post(url, headers=headers, json=data)
print(response.json())
const data = {
  model: 'kling-ai-avatar-pro',
  source_image_url: 'https://cdn.runapi.ai/public/samples/portrait.jpg',
  source_audio_url: 'https://cdn.runapi.ai/public/samples/voice.mp3',
  prompt: 'A professional presenter speaking confidently',
  callback_url: 'https://your-domain.com/api/callback'
};

fetch('https://runapi.ai/api/v1/kling/ai_avatar', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer {{API_KEY}}',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => console.log(data));

HTTP 202 - Task accepted:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "processing"
}

HTTP Request

POST https://runapi.ai/api/v1/kling/ai_avatar

Request Parameters

Parameter Type Required Description
model string Yes kling-ai-avatar-pro, kling-ai-avatar-standard, kling-ai-avatar-v1-pro, or kling-v1-avatar-standard
source_image_url string Yes Portrait image URL. Supported formats: JPEG or PNG. Max 10 MB
source_audio_url string Yes Audio file URL. Supported formats: MP3, WAV, AAC, MP4, OGG. Max 10 MB
prompt string Yes Text prompt to guide the avatar animation. Can be empty. Max 5000 characters
callback_url string No HTTPS callback URL for completion events

Response

Field Type Description
id string Unique task identifier
status string Initial async status, typically processing

Callback Format

If callback_url is provided, a POST request will be sent when generation completes.

Success callback example:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "videos": [
    {
      "url": "https://tempfile.runapi.ai/avatar-video.mp4"
    }
  ]
}

Failed callback example:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "failed",
  "error": "Generation failed"
}

Get AI Avatar Status

Check the status of an AI Avatar task:

curl "https://runapi.ai/api/v1/kling/ai_avatar/YOUR_TASK_ID" \
  -H "Authorization: Bearer {{API_KEY}}"
task_id = 'YOUR_TASK_ID'
uri = URI("https://runapi.ai/api/v1/kling/ai_avatar/#{task_id}")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request['Authorization'] = 'Bearer {{API_KEY}}'

response = http.request(request)
puts response.body
task_id = 'YOUR_TASK_ID'
response = requests.get(
    f'https://runapi.ai/api/v1/kling/ai_avatar/{task_id}',
    headers={'Authorization': 'Bearer {{API_KEY}}'}
)
print(response.json())
const taskId = 'YOUR_TASK_ID';

fetch(`https://runapi.ai/api/v1/kling/ai_avatar/${taskId}`, {
  headers: { 'Authorization': 'Bearer {{API_KEY}}' }
})
.then(res => res.json())
.then(data => console.log(data));

Completed response example:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "videos": [
    {
      "url": "https://tempfile.runapi.ai/avatar-video.mp4"
    }
  ]
}

Failed response example:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "failed",
  "error": "Generation failed"
}

HTTP Request

GET https://runapi.ai/api/v1/kling/ai_avatar/:id

Response Fields

Field Type Description
id string Task identifier
status string processing, completed, or failed
videos array Generated video URLs when completed
error string Error message when generation fails

Create V2.1 and V2.5 Video

Generate videos with Kling V2.1 and V2.5 models. V2.1 Master supports text-to-video and image-to-video, V2.1 Pro/Standard support image-to-video, and V2.5 Turbo provides fast text-to-video and image-to-video generation.

Create a V2.1 Master text-to-video task:

curl -X POST "https://runapi.ai/api/v1/kling/text_to_video" \
  -H "Authorization: Bearer {{API_KEY}}" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "kling-v2.1-master-text-to-video",
    "prompt": "A cinematic paratrooper scene above a glowing city at sunset",
    "duration_seconds": 5,
    "aspect_ratio": "16:9",
    "negative_prompt": "blur, distorted hands",
    "cfg_scale": 0.5,
    "callback_url": "https://your-domain.com/api/callback"
  }'

Create a V2.1 Pro image-to-video task with final-frame control:

curl -X POST "https://runapi.ai/api/v1/kling/image_to_video" \
  -H "Authorization: Bearer {{API_KEY}}" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "kling-v2.1-pro",
    "prompt": "The camera glides forward as the subject turns toward warm sunlight",
    "first_frame_image_url": "https://cdn.runapi.ai/public/samples/first-frame.jpg",
    "last_frame_image_url": "https://cdn.runapi.ai/public/samples/last-frame.jpg",
    "duration_seconds": 5,
    "cfg_scale": 0.5,
    "callback_url": "https://your-domain.com/api/callback"
  }'

Create a V2.1 Master image-to-video task:

curl -X POST "https://runapi.ai/api/v1/kling/image_to_video" \
  -H "Authorization: Bearer {{API_KEY}}" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "kling-v2.1-master-image-to-video",
    "prompt": "A quiet landscape comes alive with flowing water and drifting clouds",
    "first_frame_image_url": "https://cdn.runapi.ai/public/samples/image-to-video.jpg",
    "duration_seconds": 5,
    "cfg_scale": 0.5,
    "callback_url": "https://your-domain.com/api/callback"
  }'

Create a V2.5 Turbo text-to-video task:

curl -X POST "https://runapi.ai/api/v1/kling/text_to_video" \
  -H "Authorization: Bearer {{API_KEY}}" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "kling-v2.5-turbo-text-to-video-pro",
    "prompt": "A golden retriever running through a field of wildflowers in slow motion",
    "duration_seconds": 5,
    "aspect_ratio": "16:9",
    "cfg_scale": 0.5,
    "callback_url": "https://your-domain.com/api/callback"
  }'
require 'net/http'
require 'uri'
require 'json'

uri = URI('https://runapi.ai/api/v1/kling/text_to_video')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer {{API_KEY}}'
request['Content-Type'] = 'application/json'
request.body = {
  model: 'kling-v2.5-turbo-text-to-video-pro',
  prompt: 'A golden retriever running through a field of wildflowers in slow motion',
  duration_seconds: 5,
  aspect_ratio: '16:9',
  cfg_scale: 0.5,
  callback_url: 'https://your-domain.com/api/callback'
}.to_json

response = http.request(request)
puts response.body
import requests

url = 'https://runapi.ai/api/v1/kling/text_to_video'
headers = {
    'Authorization': 'Bearer {{API_KEY}}',
    'Content-Type': 'application/json'
}
data = {
    'model': 'kling-v2.5-turbo-text-to-video-pro',
    'prompt': 'A golden retriever running through a field of wildflowers in slow motion',
    'duration_seconds': 5,
    'aspect_ratio': '16:9',
    'cfg_scale': 0.5,
    'callback_url': 'https://your-domain.com/api/callback'
}

response = requests.post(url, headers=headers, json=data)
print(response.json())
const data = {
  model: 'kling-v2.5-turbo-text-to-video-pro',
  prompt: 'A golden retriever running through a field of wildflowers in slow motion',
  duration_seconds: 5,
  aspect_ratio: '16:9',
  cfg_scale: 0.5,
  callback_url: 'https://your-domain.com/api/callback'
};

fetch('https://runapi.ai/api/v1/kling/text_to_video', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer {{API_KEY}}',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => console.log(data));

Create a V2.5 Turbo image-to-video task:

curl -X POST "https://runapi.ai/api/v1/kling/image_to_video" \
  -H "Authorization: Bearer {{API_KEY}}" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "kling-v2.5-turbo-image-to-video-pro",
    "prompt": "The scene comes to life with gentle wind and swaying trees",
    "first_frame_image_url": "https://cdn.runapi.ai/public/samples/image-to-video.jpg",
    "duration_seconds": 5,
    "aspect_ratio": "16:9",
    "cfg_scale": 0.5,
    "callback_url": "https://your-domain.com/api/callback"
  }'
require 'net/http'
require 'uri'
require 'json'

uri = URI('https://runapi.ai/api/v1/kling/image_to_video')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer {{API_KEY}}'
request['Content-Type'] = 'application/json'
request.body = {
  model: 'kling-v2.5-turbo-image-to-video-pro',
  prompt: 'The scene comes to life with gentle wind and swaying trees',
  first_frame_image_url: 'https://cdn.runapi.ai/public/samples/image-to-video.jpg',
  duration_seconds: 5,
  aspect_ratio: '16:9',
  cfg_scale: 0.5,
  callback_url: 'https://your-domain.com/api/callback'
}.to_json

response = http.request(request)
puts response.body
import requests

url = 'https://runapi.ai/api/v1/kling/image_to_video'
headers = {
    'Authorization': 'Bearer {{API_KEY}}',
    'Content-Type': 'application/json'
}
data = {
    'model': 'kling-v2.5-turbo-image-to-video-pro',
    'prompt': 'The scene comes to life with gentle wind and swaying trees',
    'first_frame_image_url': 'https://cdn.runapi.ai/public/samples/image-to-video.jpg',
    'duration_seconds': 5,
    'aspect_ratio': '16:9',
    'cfg_scale': 0.5,
    'callback_url': 'https://your-domain.com/api/callback'
}

response = requests.post(url, headers=headers, json=data)
print(response.json())
const data = {
  model: 'kling-v2.5-turbo-image-to-video-pro',
  prompt: 'The scene comes to life with gentle wind and swaying trees',
  first_frame_image_url: 'https://cdn.runapi.ai/public/samples/image-to-video.jpg',
  duration_seconds: 5,
  aspect_ratio: '16:9',
  cfg_scale: 0.5,
  callback_url: 'https://your-domain.com/api/callback'
};

fetch('https://runapi.ai/api/v1/kling/image_to_video', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer {{API_KEY}}',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => console.log(data));

HTTP 202 - Task accepted:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "processing"
}

HTTP Request

POST https://runapi.ai/api/v1/kling/image_to_video

Request Parameters (Text-to-Video)

Parameter Type Required Description
model string Yes kling-v2.1-master-text-to-video or kling-v2.5-turbo-text-to-video-pro
prompt string Yes Text description of the desired video. Max 5000 characters for V2.1 Master and 2500 for V2.5 Turbo
duration_seconds number No Video duration in seconds: 5 or 10. Default 5
aspect_ratio string No 16:9, 9:16, or 1:1
negative_prompt string No What to avoid in the generated video. Max 500 characters for V2.1 Master and 2500 for V2.5 Turbo
cfg_scale number No Creativity vs prompt adherence, 0 to 1
callback_url string No HTTPS callback URL for completion events

Request Parameters (Image-to-Video)

Parameter Type Required Description
model string Yes kling-v2.1-pro, kling-v2.1-standard, kling-v2.1-master-image-to-video, or kling-v2.5-turbo-image-to-video-pro
prompt string Yes Text description of the desired video. Max 5000 characters for V2.1 and 2500 for V2.5 Turbo
first_frame_image_url string Yes Source image URL to animate
last_frame_image_url string No Final-frame image URL supported by kling-v2.5-turbo-image-to-video-pro and kling-v2.1-pro
duration_seconds number No Video duration in seconds: 5 or 10. Default 5
aspect_ratio string No 16:9, 9:16, or 1:1
negative_prompt string No What to avoid in the generated video. Max 500 characters
cfg_scale number No Creativity vs prompt adherence, 0 to 1
callback_url string No HTTPS callback URL for completion events

Response

Field Type Description
id string Unique task identifier
status string Initial async status, typically processing

Callback Format

If callback_url is provided, a POST request will be sent when generation completes.

Success callback example:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "videos": [
    {
      "url": "https://tempfile.runapi.ai/turbo-video.mp4"
    }
  ]
}

Failed callback example:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "failed",
  "error": "Generation failed"
}

Get V2.1 and V2.5 Video Status

Check the status of a V2.1 or V2.5 task:

curl "https://runapi.ai/api/v1/kling/image_to_video/YOUR_TASK_ID" \
  -H "Authorization: Bearer {{API_KEY}}"
task_id = 'YOUR_TASK_ID'
uri = URI("https://runapi.ai/api/v1/kling/image_to_video/#{task_id}")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request['Authorization'] = 'Bearer {{API_KEY}}'

response = http.request(request)
puts response.body
task_id = 'YOUR_TASK_ID'
response = requests.get(
    f'https://runapi.ai/api/v1/kling/image_to_video/{task_id}',
    headers={'Authorization': 'Bearer {{API_KEY}}'}
)
print(response.json())
const taskId = 'YOUR_TASK_ID';

fetch(`https://runapi.ai/api/v1/kling/image_to_video/${taskId}`, {
  headers: { 'Authorization': 'Bearer {{API_KEY}}' }
})
.then(res => res.json())
.then(data => console.log(data));

Completed response example:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "videos": [
    {
      "url": "https://tempfile.runapi.ai/turbo-video.mp4"
    }
  ]
}

Failed response example:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "failed",
  "error": "Generation failed"
}

HTTP Request

GET https://runapi.ai/api/v1/kling/image_to_video/:id

Response Fields

Field Type Description
id string Task identifier
status string processing, completed, or failed
videos array Generated video URLs when completed
error string Error message when generation fails

Create Motion Control

Transfer motion from a reference video onto a subject image. The Motion Control feature extracts movement patterns from a video and applies them to a static image, producing a new video where the subject in the image performs the movements from the reference video.

Create a Motion Control task:

curl -X POST "https://runapi.ai/api/v1/kling/motion_control" \
  -H "Authorization: Bearer {{API_KEY}}" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "kling-3.0",
    "source_first_frame_image_url": "https://cdn.runapi.ai/public/samples/image.jpg",
    "reference_video_url": "https://cdn.runapi.ai/public/samples/video.mp4",
    "prompt": "A person dancing gracefully in a studio",
    "output_resolution": "1080p",
    "character_orientation": "video",
    "background_source": "video",
    "callback_url": "https://your-domain.com/api/callback"
  }'
require 'net/http'
require 'uri'
require 'json'

uri = URI('https://runapi.ai/api/v1/kling/motion_control')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer {{API_KEY}}'
request['Content-Type'] = 'application/json'
request.body = {
  model: 'kling-3.0',
  source_first_frame_image_url: 'https://cdn.runapi.ai/public/samples/image.jpg',
  reference_video_url: 'https://cdn.runapi.ai/public/samples/video.mp4',
  prompt: 'A person dancing gracefully in a studio',
  output_resolution: '1080p',
  character_orientation: 'video',
  background_source: 'video',
  callback_url: 'https://your-domain.com/api/callback'
}.to_json

response = http.request(request)
puts response.body
import requests

url = 'https://runapi.ai/api/v1/kling/motion_control'
headers = {
    'Authorization': 'Bearer {{API_KEY}}',
    'Content-Type': 'application/json'
}
data = {
    'model': 'kling-3.0',
    'source_first_frame_image_url': 'https://cdn.runapi.ai/public/samples/image.jpg',
    'reference_video_url': 'https://cdn.runapi.ai/public/samples/video.mp4',
    'prompt': 'A person dancing gracefully in a studio',
    'output_resolution': '1080p',
    'character_orientation': 'video',
    'background_source': 'video',
    'callback_url': 'https://your-domain.com/api/callback'
}

response = requests.post(url, headers=headers, json=data)
print(response.json())
const data = {
  model: 'kling-3.0',
  source_first_frame_image_url: 'https://cdn.runapi.ai/public/samples/image.jpg',
  reference_video_url: 'https://cdn.runapi.ai/public/samples/video.mp4',
  prompt: 'A person dancing gracefully in a studio',
  output_resolution: '1080p',
  character_orientation: 'video',
  background_source: 'video',
  callback_url: 'https://your-domain.com/api/callback'
};

fetch('https://runapi.ai/api/v1/kling/motion_control', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer {{API_KEY}}',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => console.log(data));

HTTP 202 - Task accepted:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "processing"
}

HTTP Request

POST https://runapi.ai/api/v1/kling/motion_control

Request Parameters

Parameter Type Required Description
model string Yes Must be kling-3.0
source_first_frame_image_url string Yes Subject image URL
reference_video_url string Yes Reference motion video URL
prompt string No Text prompt to guide the generation. Max 2500 characters
output_resolution string No Output resolution: 720p or 1080p
character_orientation string No Which source determines the character's orientation: video or image
background_source string No Which source provides the background: video or image
callback_url string No HTTPS callback URL for completion events

Response

Field Type Description
id string Unique task identifier
status string Initial async status, typically processing

Callback Format

If callback_url is provided, a POST request will be sent when generation completes.

Success callback example:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "videos": [
    {
      "url": "https://tempfile.runapi.ai/motion-control-video.mp4"
    }
  ]
}

Failed callback example:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "failed",
  "error": "Generation failed"
}

Get Motion Control Status

Check the status of a Motion Control task:

curl "https://runapi.ai/api/v1/kling/motion_control/YOUR_TASK_ID" \
  -H "Authorization: Bearer {{API_KEY}}"
task_id = 'YOUR_TASK_ID'
uri = URI("https://runapi.ai/api/v1/kling/motion_control/#{task_id}")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request['Authorization'] = 'Bearer {{API_KEY}}'

response = http.request(request)
puts response.body
task_id = 'YOUR_TASK_ID'
response = requests.get(
    f'https://runapi.ai/api/v1/kling/motion_control/{task_id}',
    headers={'Authorization': 'Bearer {{API_KEY}}'}
)
print(response.json())
const taskId = 'YOUR_TASK_ID';

fetch(`https://runapi.ai/api/v1/kling/motion_control/${taskId}`, {
  headers: { 'Authorization': 'Bearer {{API_KEY}}' }
})
.then(res => res.json())
.then(data => console.log(data));

Completed response example:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "videos": [
    {
      "url": "https://tempfile.runapi.ai/motion-control-video.mp4"
    }
  ]
}

Failed response example:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "failed",
  "error": "Generation failed"
}

HTTP Request

GET https://runapi.ai/api/v1/kling/motion_control/:id

Response Fields

Field Type Description
id string Task identifier
status string processing, completed, or failed
videos array Generated video URLs when completed
error string Error message when generation fails

Suno

The Suno API provides comprehensive music generation and processing capabilities.

Base Endpoint: https://runapi.ai/api/v1/suno

Suno Endpoints

Category Endpoints Use Case
Core Generate Music, Generate Lyrics Create new music or lyrics from scratch
Extend & Edit Extend Music, Replace Section Modify existing tracks
Audio Layers Add Vocals, Add Instrumental Layer vocals or instruments
Audio Separation Vocal Separation, MIDI Generation Split audio into components
Visual Music Cover, Music Video Generate cover art or videos
Audio Transformation Upload and Covers, Upload and Extensions, Mashup Process your own audio files
Sound Design Generate Sound Ambient, loops, sound effects
Voice Voice Validation Phrase, Regenerate Validation Phrase, Generate Voice, Check Voice Prepare verification phrases and reusable custom voices

Model Versions

Model Description
suno-v5.5 Custom models tailored to your taste
suno-v5 Superior musical expression, faster generation, max 8 min
suno-v4.5-plus Richer sound with new creative tools, max 8 min
suno-v4.5-all Smarter prompts, faster generations, max 8 min
suno-v4.5 Smarter prompts, faster generations, max 8 min
suno-v4 Improved vocal quality, max 4 min

Common Parameters

These parameters appear across most generation endpoints:

Parameter Type Description
model string Model version (suno-v5, suno-v4.5-plus, suno-v4.5-all, suno-v4.5, suno-v4)
callback_url string URL for completion notifications
style_weight number Style adherence (0-1, higher = stricter)
weirdness_constraint number Creativity level (0-1, higher = more experimental)
audio_weight number Audio consistency (0-1, higher = more consistent)
vocal_gender string Preferred voice: male or female. Increases probability only.

Common Error Codes

Status Code Error Message Description
400 SENSITIVE_WORD_ERROR Prompt contains sensitive words. Please modify the prompt and try again.
402 INSUFFICIENT_QUOTA Insufficient account balance. Please recharge.
408 TIMEOUT Task timed out. Please try again later.
429 RATE_LIMIT_EXCEEDED Rate limit exceeded. Please try again later.
500 SERVER_ERROR Internal server error. Please try again later.
531 REFUNDED Task failed and has been automatically refunded. Please try again.

Generate Music

Create a music generation task:

curl -X POST "https://runapi.ai/api/v1/suno/text_to_music" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "vocal_mode": "auto_lyrics",
    "prompt": "A chill lo-fi beat with soft vocals",
    "model": "suno-v5",
    "callback_url": "https://your-app.com/callbacks/suno"
  }'
require 'net/http'
require 'json'

uri = URI('https://runapi.ai/api/v1/suno/text_to_music')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
request['Content-Type'] = 'application/json'
request.body = {
  vocal_mode: "auto_lyrics",
  prompt: "A chill lo-fi beat with soft vocals",
  model: "suno-v5",
  callback_url: "https://your-app.com/callbacks/suno"
}.to_json

response = http.request(request)
import requests

url = "https://runapi.ai/api/v1/suno/text_to_music"
headers = {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "Content-Type": "application/json"
}
data = {
    "vocal_mode": "auto_lyrics",
    "prompt": "A chill lo-fi beat with soft vocals",
    "model": "suno-v5",
    "callback_url": "https://your-app.com/callbacks/suno"
}

response = requests.post(url, headers=headers, json=data)
fetch('https://runapi.ai/api/v1/suno/text_to_music', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    vocal_mode: "auto_lyrics",
    prompt: "A chill lo-fi beat with soft vocals",
    model: "suno-v5",
    callback_url: "https://your-app.com/callbacks/suno"
  })
});

Generate original music from text descriptions.

HTTP Request

POST https://runapi.ai/api/v1/suno/text_to_music

Request Body Parameters

Request Shapes

Choose vocal_mode. Add model and optional callback_url to each request.

Parameter Type Required Description
vocal_mode string Yes auto_lyrics, exact_lyrics, or instrumental.
prompt string No Song brief for automatic lyrics.
lyrics string No Exact sung lyrics.
style string No Music style.
title string No Music title.
model string Yes Model version: suno-v5, suno-v4.5-plus, suno-v4.5-all, suno-v4.5, suno-v4
callback_url string No URL to receive completion notifications
persona_id string No Persona ID to apply. Create one via Generate Persona.
persona_type string No Persona type, used with persona_id. Values: style for style characteristics, voice for voice characteristics (suno-v5 only). Ignored without persona_id.
negative_tags string No Music styles to exclude
vocal_gender string No Preferred vocal gender: male or female. Increases probability only.
style_weight number No Style adherence weight (0-1, two decimals)
weirdness_constraint number No Creativity/novelty constraint (0-1, two decimals)
audio_weight number No Audio consistency weight (0-1, two decimals)

Response

Returns the task ID for tracking generation status.

HTTP 202 - Task accepted:

{
  "id": "281e5b0*********************f39b9",
  "status": "processing"
}

Callback Format

If callback_url is provided, a POST request will be sent at multiple stages during generation: - text_generated: All text content ready (title, lyrics, tags, etc.) - first_audio_ready: First audio track completed - all_audios_ready: All audios completed - failed: Generation failed

Success Response: - Includes audios array with generated music details - Contains track details like title, tags, duration - Each track includes audio_url, stream_audio_url, and image_url

Failed Response: - Contains error message describing the failure reason

Success callback example:

{
  "id": "task-id",
  "status": "completed",
  "generation_stage": "all_audios_ready",
  "audios": [
    {
      "id": "audio-id-1",
      "audio_url": "https://file.runapi.ai/audio1.mp3",
      "stream_audio_url": "https://file.runapi.ai/stream1",
      "image_url": "https://file.runapi.ai/cover1.jpg",
      "lyrics": "[Verse] Lyrics...",
      "model_name": "chirp-v3-5",
      "title": "Song Title",
      "tags": ["genre1", "genre2"],
      "duration": 198.44
    }
  ]
}

Failed callback example:

{
  "id": "task-id",
  "status": "failed",
  "generation_stage": "failed",
  "error": "Error message"
}

Get Music Generation Details

Query music generation status:

curl "https://runapi.ai/api/v1/suno/text_to_music/:id" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
uri = URI('https://runapi.ai/api/v1/suno/text_to_music/TASK_ID')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'

response = http.request(request)
url = "https://runapi.ai/api/v1/suno/text_to_music/TASK_ID"
headers = {"Authorization": "Bearer YOUR_API_TOKEN"}

response = requests.get(url, headers=headers)
fetch('https://runapi.ai/api/v1/suno/text_to_music/TASK_ID', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN'
  }
});

Get detailed information about a music generation task.

HTTP Request

GET https://runapi.ai/api/v1/suno/text_to_music/:id

URL Parameters

Parameter Description
id The task ID returned from the generate endpoint

Response

Processing:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "processing",
  "generation_stage": "text_generated"
}

Completed:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "completed",
  "generation_stage": "all_audios_ready",
  "audios": [
    {
      "id": "8551****662c",
      "audio_url": "https://file.runapi.ai/****.mp3",
      "stream_audio_url": "https://file.runapi.ai/****",
      "image_url": "https://file.runapi.ai/****.jpeg",
      "lyrics": "[Verse] 夜晚城市 灯火辉煌",
      "model_name": "chirp-v3-5",
      "title": "钢铁侠",
      "tags": ["electrifying", "rock"],
      "duration": 198.44
    }
  ]
}

Failed:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "failed",
  "generation_stage": "failed",
  "error": "Generation failed"
}

Extend Music

Extend an existing music track:

curl -X POST "https://runapi.ai/api/v1/suno/extend_music" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "parameter_mode": "custom",
    "audio_id": "2902e564-9001-427c-a6fa-585b86a864fe",
    "prompt": "Extend the music with more relaxing notes",
    "style": "Classical",
    "title": "Peaceful Piano Extended",
    "continue_at": 60,
    "model": "suno-v4",
    "callback_url": "https://your-app.com/callbacks/suno"
  }'
request.body = {
  parameter_mode: "custom",
  audio_id: "2902e564-9001-427c-a6fa-585b86a864fe",
  prompt: "Extend the music with more relaxing notes",
  style: "Classical",
  title: "Peaceful Piano Extended",
  continue_at: 60,
  model: "suno-v4",
  callback_url: "https://your-app.com/callbacks/suno"
}.to_json
data = {
    "parameter_mode": "custom",
    "audio_id": "2902e564-9001-427c-a6fa-585b86a864fe",
    "prompt": "Extend the music with more relaxing notes",
    "style": "Classical",
    "title": "Peaceful Piano Extended",
    "continue_at": 60,
    "model": "suno-v4",
    "callback_url": "https://your-app.com/callbacks/suno"
}
body: JSON.stringify({
  parameter_mode: "custom",
  audio_id: "2902e564-9001-427c-a6fa-585b86a864fe",
  prompt: "Extend the music with more relaxing notes",
  style: "Classical",
  title: "Peaceful Piano Extended",
  continue_at: 60,
  model: "suno-v4",
  callback_url: "https://your-app.com/callbacks/suno"
})

Extend or modify existing music audios while maintaining the original style.

HTTP Request

POST https://runapi.ai/api/v1/suno/extend_music

Request Body Parameters

Parameter Type Required Description
parameter_mode string Yes source to inherit source parameters, or custom to provide parameters in this request
audio_id string Yes Audio ID of the track to extend
callback_url string No URL to receive task completion notifications
model string Yes Model version: suno-v5, suno-v4.5-plus, suno-v4.5-all, suno-v4.5, suno-v4
prompt string Conditional Description of how to extend (required when parameter_mode is custom)
style string Conditional Music style (required when parameter_mode is custom)
title string Conditional Music title (required when parameter_mode is custom)
continue_at number Conditional Start time in seconds (required when parameter_mode is custom)
persona_id string No Persona ID to apply when parameter_mode is custom. Create one via Generate Persona.
persona_type string No Persona type, used with persona_id. Values: style for style characteristics, voice for voice characteristics (suno-v5 only). Ignored without persona_id.
negative_tags string No Music styles to exclude
vocal_gender string No Preferred vocal gender: male or female. Only works with parameter_mode: "custom". Increases probability only.
style_weight number No Style adherence weight (0-1)
weirdness_constraint number No Creativity constraint (0-1)
audio_weight number No Audio consistency weight (0-1)

Response

HTTP 202 - Task accepted:

{
  "id": "281e5b0*********************f39b9",
  "status": "processing"
}

Callback Format

If callback_url is provided, a POST request will be sent at multiple stages.

Success Response: - Includes extended track URLs - Contains metadata like title, tags, duration - Extended audios maintain style consistency with source

Success callback example:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "completed",
  "generation_stage": "all_audios_ready",
  "audios": [
    {
      "id": "8551****662c",
      "audio_url": "https://file.runapi.ai/****.mp3",
      "stream_audio_url": "https://file.runapi.ai/****",
      "image_url": "https://file.runapi.ai/****.jpeg",
      "lyrics": "[Verse] Night city lights shining bright",
      "model_name": "chirp-v3-5",
      "title": "Iron Man Extended",
      "tags": ["electrifying", "rock"],
      "duration": 278.44
    }
  ]
}

Failed callback example:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "failed",
  "generation_stage": "failed",
  "error": "Failed to extend music, invalid audio source"
}

Get Music Extension Details

Query extension status:

curl "https://runapi.ai/api/v1/suno/extend_music/:id" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
uri = URI('https://runapi.ai/api/v1/suno/extend_music/TASK_ID')
request = Net::HTTP::Get.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
url = "https://runapi.ai/api/v1/suno/extend_music/TASK_ID"
headers = {"Authorization": "Bearer YOUR_API_TOKEN"}
response = requests.get(url, headers=headers)
fetch('https://runapi.ai/api/v1/suno/extend_music/TASK_ID', {
  method: 'GET',
  headers: {'Authorization': 'Bearer YOUR_API_TOKEN'}
});

Query the status and details of a music extension task.

HTTP Request

GET https://runapi.ai/api/v1/suno/extend_music/:id

URL Parameters

Parameter Description
id The task ID returned when you submitted the extension request

Response

Processing:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "processing"
}

Completed:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "completed",
  "generation_stage": "all_audios_ready",
  "audios": [
    {
      "id": "8551****662c",
      "audio_url": "https://file.runapi.ai/****.mp3",
      "stream_audio_url": "https://file.runapi.ai/****",
      "image_url": "https://file.runapi.ai/****.jpeg",
      "lyrics": "[Verse] Night city lights shining bright",
      "model_name": "chirp-v3-5",
      "title": "Iron Man Extended",
      "tags": ["electrifying", "rock"],
      "duration": 278.44
    }
  ]
}

Failed:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "failed",
  "error": "Extension generation failed."
}

Generate Lyrics

Create a lyrics generation task:

curl -X POST "https://runapi.ai/api/v1/suno/generate_lyrics" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "A song about peaceful night in the city",
    "callback_url": "https://your-app.com/callbacks/suno-lyrics"
  }'
request.body = {
  prompt: "A song about peaceful night in the city",
  callback_url: "https://your-app.com/callbacks/suno-lyrics"
}.to_json
data = {
    "prompt": "A song about peaceful night in the city",
    "callback_url": "https://your-app.com/callbacks/suno-lyrics"
}
body: JSON.stringify({
  prompt: "A song about peaceful night in the city",
  callback_url: "https://your-app.com/callbacks/suno-lyrics"
})

Generate creative lyrics content based on a text prompt.

HTTP Request

POST https://runapi.ai/api/v1/suno/generate_lyrics

Request Body Parameters

Parameter Type Required Description
prompt string Yes Theme, style, or subject of the desired lyrics. Max 200 characters
callback_url string No Publicly accessible URL to receive completion callback

Response

HTTP 202 - Task accepted:

{
  "id": "281e5b0*********************f39b9",
  "status": "processing"
}

Callback Format

When the lyrics generation task finishes, the system will POST to your callback_url.

Success Response: - Contains lyrics array with generated content - Includes title and structured text - Returns one or more lyric entries with verse/chorus sections

Success callback example:

{
  "id": "277a0b89-cd57-455e-ba43-7c6532ca99ed",
  "status": "completed",
  "lyrics": [
    {
      "title": "Starry Night Dreams",
      "text": "[Verse]\nMoonlight spreads across the windowsill..."
    }
  ]
}

Failed callback example:

{
  "id": "277a0b89-cd57-455e-ba43-7c6532ca99ed",
  "status": "failed",
  "error": "Song Description flagged for moderation"
}

Get Lyrics Generation Details

Query lyrics generation status:

curl "https://runapi.ai/api/v1/suno/generate_lyrics/:id" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
uri = URI('https://runapi.ai/api/v1/suno/generate_lyrics/TASK_ID')
request = Net::HTTP::Get.new(uri)
url = "https://runapi.ai/api/v1/suno/generate_lyrics/TASK_ID"
response = requests.get(url, headers=headers)
fetch('https://runapi.ai/api/v1/suno/generate_lyrics/TASK_ID', {
  method: 'GET',
  headers: {'Authorization': 'Bearer YOUR_API_TOKEN'}
});

Retrieve the status of a lyrics generation task.

HTTP Request

GET https://runapi.ai/api/v1/suno/generate_lyrics/:id

URL Parameters

Parameter Description
id Task ID returned from POST /lyrics

Response

Processing:

{
  "id": "277a0b89-cd57-455e-ba43-7c6532ca99ed",
  "status": "processing",
  "lyrics": []
}

Completed:

{
  "id": "277a0b89-cd57-455e-ba43-7c6532ca99ed",
  "status": "completed",
  "lyrics": [
    {
      "title": "Starry Night Dreams",
      "text": "[Verse]\nMoonlight spreads across the windowsill..."
    }
  ]
}

Failed:

{
  "id": "277a0b89-cd57-455e-ba43-7c6532ca99ed",
  "status": "failed",
  "error": "Lyrics generation failed.",
  "lyrics": []
}

Add Vocals

Add vocals to an instrumental track:

curl -X POST "https://runapi.ai/api/v1/suno/add_vocals" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "upload_url": "https://cdn.runapi.ai/public/samples/music.mp3",
    "lyrics": "[Verse]\nA calm and relaxing piano track with soothing vocals",
    "title": "Relaxing Piano with Vocals",
    "style": "Jazz",
    "model": "suno-v4.5-plus",
    "callback_url": "https://your-app.com/callbacks/suno"
  }'
request.body = {
  upload_url: "https://cdn.runapi.ai/public/samples/music.mp3",
  lyrics: "[Verse]\nA calm and relaxing piano track with soothing vocals",
  title: "Relaxing Piano with Vocals",
  style: "Jazz",
  model: "suno-v4.5-plus",
  callback_url: "https://your-app.com/callbacks/suno"
}.to_json
data = {
    "upload_url": "https://cdn.runapi.ai/public/samples/music.mp3",
    "lyrics": "[Verse]\nA calm and relaxing piano track with soothing vocals",
    "title": "Relaxing Piano with Vocals",
    "style": "Jazz",
    "model": "suno-v4.5-plus",
    "callback_url": "https://your-app.com/callbacks/suno"
}
body: JSON.stringify({
  upload_url: "https://cdn.runapi.ai/public/samples/music.mp3",
  lyrics: "[Verse]\nA calm and relaxing piano track with soothing vocals",
  title: "Relaxing Piano with Vocals",
  style: "Jazz",
  model: "suno-v4.5-plus",
  callback_url: "https://your-app.com/callbacks/suno"
})

Add vocals to an uploaded audio file.

HTTP Request

POST https://runapi.ai/api/v1/suno/add_vocals

Request Body Parameters

Parameter Type Required Description
upload_url string Yes URL of the uploaded music file. You can use the download_url returned by POST /files/from_url; that temporary link expires after 24 hours.
lyrics string Yes Exact vocal lyrics
title string Yes Title of the music track
style string Yes Music style/genre
model string Yes Model version: suno-v5, suno-v4.5-plus, suno-v4.5-all, suno-v4.5, suno-v4
callback_url string No URL to receive completion notifications
negative_tags string No Styles to exclude
vocal_gender string No Preferred vocal gender: male or female. Increases probability only.
style_weight number No Style adherence weight (0-1)
weirdness_constraint number No Creativity constraint (0-1)
audio_weight number No Audio consistency weight (0-1)

Response

HTTP 202 - Task accepted:

{
  "id": "281e5b0*********************f39b9",
  "status": "processing"
}

Callback Format

The system will POST to your callback_url at multiple stages.

Success callback example:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "completed",
  "generation_stage": "all_audios_ready",
  "audios": [
    {
      "id": "8551****662c",
      "audio_url": "https://file.runapi.ai/audio.mp3",
      "stream_audio_url": "https://file.runapi.ai/stream",
      "image_url": "https://file.runapi.ai/cover.jpg",
      "lyrics": "[Verse] Soothing melody with calm vocals",
      "model_name": "chirp-v4-5",
      "title": "Relaxing Piano with Vocals",
      "tags": ["jazz", "calm", "soothing"],
      "duration": 182.32
    }
  ]
}

Failed callback example:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "failed",
  "generation_stage": "failed",
  "error": "Vocal generation failed."
}

Get Add Vocals Details

Query vocals task status:

curl "https://runapi.ai/api/v1/suno/add_vocals/:id" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
uri = URI('https://runapi.ai/api/v1/suno/add_vocals/TASK_ID')
request = Net::HTTP::Get.new(uri)
url = "https://runapi.ai/api/v1/suno/add_vocals/TASK_ID"
response = requests.get(url, headers=headers)
fetch('https://runapi.ai/api/v1/suno/add_vocals/TASK_ID', {
  method: 'GET',
  headers: {'Authorization': 'Bearer YOUR_API_TOKEN'}
});

Get detailed information about an add vocals task.

HTTP Request

GET https://runapi.ai/api/v1/suno/add_vocals/:id

URL Parameters

Parameter Description
id The task ID returned from the add vocals endpoint

Response

Processing:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "processing"
}

Completed:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "completed",
  "generation_stage": "all_audios_ready",
  "audios": [
    {
      "id": "8551****662c",
      "audio_url": "https://file.runapi.ai/****.mp3",
      "stream_audio_url": "https://file.runapi.ai/****",
      "image_url": "https://file.runapi.ai/****.jpeg",
      "lyrics": "[Verse] Soothing melody with calm vocals",
      "model_name": "chirp-v4-5",
      "title": "Relaxing Piano with Vocals",
      "tags": ["jazz", "calm", "soothing"],
      "duration": 182.32
    }
  ]
}

Failed:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "failed",
  "error": "Vocal generation failed."
}

Add Instrumental

Add instrumental to a track:

curl -X POST "https://runapi.ai/api/v1/suno/add_instrumental" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "upload_url": "https://cdn.runapi.ai/public/samples/music.mp3",
    "title": "Relaxing Piano",
    "tags": "Relaxing Piano, Ambient, Peaceful",
    "negative_tags": "Heavy Metal, Aggressive Drums",
    "model": "suno-v4.5-plus",
    "callback_url": "https://your-app.com/callbacks/suno"
  }'
request.body = {
  upload_url: "https://cdn.runapi.ai/public/samples/music.mp3",
  title: "Relaxing Piano",
  tags: "Relaxing Piano, Ambient, Peaceful",
  negative_tags: "Heavy Metal, Aggressive Drums",
  model: "suno-v4.5-plus",
  callback_url: "https://your-app.com/callbacks/suno"
}.to_json
data = {
    "upload_url": "https://cdn.runapi.ai/public/samples/music.mp3",
    "title": "Relaxing Piano",
    "tags": "Relaxing Piano, Ambient, Peaceful",
    "negative_tags": "Heavy Metal, Aggressive Drums",
    "model": "suno-v4.5-plus",
    "callback_url": "https://your-app.com/callbacks/suno"
}
body: JSON.stringify({
  upload_url: "https://cdn.runapi.ai/public/samples/music.mp3",
  title: "Relaxing Piano",
  tags: "Relaxing Piano, Ambient, Peaceful",
  negative_tags: "Heavy Metal, Aggressive Drums",
  model: "suno-v4.5-plus",
  callback_url: "https://your-app.com/callbacks/suno"
})

Generate musical accompaniment tailored to an uploaded audio file.

HTTP Request

POST https://runapi.ai/api/v1/suno/add_instrumental

Request Body Parameters

Parameter Type Required Description
upload_url string Yes URL of the uploaded music file. You can use the download_url returned by POST /files/from_url; that temporary link expires after 24 hours.
title string Yes Title of the music track
tags string Yes Music style and characteristics
negative_tags string Yes Music styles to exclude
model string Yes Model version: suno-v5, suno-v4.5-plus, suno-v4.5-all, suno-v4.5, suno-v4
callback_url string No URL to receive completion notifications
vocal_gender string No Preferred vocal gender: male or female. Increases probability only.
style_weight number No Style adherence weight (0-1)
weirdness_constraint number No Creativity constraint (0-1)
audio_weight number No Audio consistency weight (0-1)

Response

HTTP 202 - Task accepted:

{
  "id": "281e5b0*********************f39b9",
  "status": "processing"
}

Callback Format

Success callback example:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "completed",
  "generation_stage": "all_audios_ready",
  "audios": [
    {
      "id": "8551****662c",
      "audio_url": "https://file.runapi.ai/****.mp3",
      "stream_audio_url": "https://file.runapi.ai/****",
      "image_url": "https://file.runapi.ai/****.jpeg",
      "lyrics": "[Verse] Relaxing piano melody flows",
      "model_name": "chirp-v4-5-plus",
      "title": "Relaxing Piano",
      "tags": ["Relaxing Piano", "Ambient", "Peaceful"],
      "duration": 182.32
    }
  ]
}

Failed callback example:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "failed",
  "generation_stage": "failed",
  "error": "Instrumental generation failed."
}

Get Add Instrumental Details

Query instrumental task status:

curl "https://runapi.ai/api/v1/suno/add_instrumental/:id" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
uri = URI('https://runapi.ai/api/v1/suno/add_instrumental/TASK_ID')
request = Net::HTTP::Get.new(uri)
url = "https://runapi.ai/api/v1/suno/add_instrumental/TASK_ID"
response = requests.get(url, headers=headers)
fetch('https://runapi.ai/api/v1/suno/add_instrumental/TASK_ID', {
  method: 'GET',
  headers: {'Authorization': 'Bearer YOUR_API_TOKEN'}
});

Query the status and details of an add instrumental task.

HTTP Request

GET https://runapi.ai/api/v1/suno/add_instrumental/:id

URL Parameters

Parameter Description
id The task ID returned when you submitted the request

Response

Processing:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "processing"
}

Completed:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "completed",
  "generation_stage": "all_audios_ready",
  "audios": [
    {
      "id": "8551****662c",
      "audio_url": "https://file.runapi.ai/****.mp3",
      "stream_audio_url": "https://file.runapi.ai/****",
      "image_url": "https://file.runapi.ai/****.jpeg",
      "lyrics": "[Verse] Relaxing piano melody flows",
      "model_name": "chirp-v4-5-plus",
      "title": "Relaxing Piano",
      "tags": ["Relaxing Piano", "Ambient", "Peaceful"],
      "duration": 182.32
    }
  ]
}

Failed:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "failed",
  "error": "Instrumental generation failed."
}

Vocal & Instrument Separation

Separate vocals and instruments:

curl -X POST "https://runapi.ai/api/v1/suno/separate_audio_stems" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "task_id": "03fe3e68-2dec-487c-a810-885667aed19c",
    "audio_id": "6949072e-5cdb-43a3-b093-56d16e582aeb",
    "type": "separate_vocal",
    "callback_url": "https://your-app.com/callbacks/suno"
  }'
request.body = {
  task_id: "03fe3e68-2dec-487c-a810-885667aed19c",
  audio_id: "6949072e-5cdb-43a3-b093-56d16e582aeb",
  type: "separate_vocal",
  callback_url: "https://your-app.com/callbacks/suno"
}.to_json
data = {
    "task_id": "03fe3e68-2dec-487c-a810-885667aed19c",
    "audio_id": "6949072e-5cdb-43a3-b093-56d16e582aeb",
    "type": "separate_vocal",
    "callback_url": "https://your-app.com/callbacks/suno"
}
body: JSON.stringify({
  task_id: "03fe3e68-2dec-487c-a810-885667aed19c",
  audio_id: "6949072e-5cdb-43a3-b093-56d16e582aeb",
  type: "separate_vocal",
  callback_url: "https://your-app.com/callbacks/suno"
})

Separate music into vocal, instrumental, and individual instrument tracks.

HTTP Request

POST https://runapi.ai/api/v1/suno/separate_audio_stems

Request Body Parameters

Parameter Type Required Description
task_id string Yes The task ID of the music generation task
audio_id string Yes The audio ID of the specific track to separate
type string No Separation type: separate_vocal (default) or split_stem. See Suno pricing.
callback_url string No URL to receive completion notification

Separation Types: - separate_vocal: Separates vocals and accompaniment (generates 2 tracks) - split_stem: Separates individual instruments (generates 12+ tracks)

Response

HTTP 202 - Task accepted:

{
  "id": "281e5b0*********************f39b9",
  "status": "processing"
}

Callback Format

The system will POST to your callback_url when separation completes.

Success Response (separate_vocal): - Contains instrumental_url and vocal_url - Clean separation between vocals and backing music

Success Response (split_stem): - Contains individual instrument URLs - Includes backing_vocals, bass, brass, drums, fx, guitar, keyboard, percussion, strings, synth, vocal, woodwinds

Success callback (separate_vocal):

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "completed",
  "separated_audios": {
    "instrumental_url": "https://file.runapi.ai/s/d92a****5528_Instrumental.mp3",
    "vocal_url": "https://file.runapi.ai/s/3d70****b172_Vocals.mp3"
  }
}

Success callback (split_stem):

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "completed",
  "separated_audios": {
    "backing_vocals_url": "https://file.runapi.ai/s/aadc****673d_Backing_Vocals.mp3",
    "bass_url": "https://file.runapi.ai/s/a3c2****26d33_Bass.mp3",
    "brass_url": "https://file.runapi.ai/s/334b****fdd44_Brass.mp3",
    "drums_url": "https://file.runapi.ai/s/ac75****78e44_Drums.mp3",
    "fx_url": "https://file.runapi.ai/s/a882****007d_FX.mp3",
    "guitar_url": "https://file.runapi.ai/s/064d****95b4_Guitar.mp3",
    "keyboard_url": "https://file.runapi.ai/s/adc9****d74e0_Keyboard.mp3",
    "piano_url": "https://file.runapi.ai/s/b1c2****3d4e_Piano.mp3",
    "percussion_url": "https://file.runapi.ai/s/0f70****618b7dc6_Percussion.mp3",
    "strings_url": "https://file.runapi.ai/s/4982****6b_Strings.mp3",
    "synth_url": "https://file.runapi.ai/s/56b2****8348_Synth.mp3",
    "vocal_url": "https://file.runapi.ai/s/0742****90ccb_Vocals.mp3",
    "woodwinds_url": "https://file.runapi.ai/s/d815****abb02_Woodwinds.mp3"
  }
}

Failed callback:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "failed",
  "error": "Vocal separation failed."
}

Get Vocal Separation Details

Query vocal separation status:

curl "https://runapi.ai/api/v1/suno/separate_audio_stems/:id" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
uri = URI('https://runapi.ai/api/v1/suno/separate_audio_stems/TASK_ID')
request = Net::HTTP::Get.new(uri)
url = "https://runapi.ai/api/v1/suno/separate_audio_stems/TASK_ID"
response = requests.get(url, headers=headers)
fetch('https://runapi.ai/api/v1/suno/separate_audio_stems/TASK_ID', {
  method: 'GET',
  headers: {'Authorization': 'Bearer YOUR_API_TOKEN'}
});

Query the status and details of a vocal separation task.

HTTP Request

GET https://runapi.ai/api/v1/suno/separate_audio_stems/:id

URL Parameters

Parameter Description
id The task ID returned from the vocal removal endpoint

Response

Processing:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "processing"
}

Completed (separate_vocal):

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "completed",
  "separated_audios": {
    "instrumental_url": "https://file.runapi.ai/s/d92a****5528_Instrumental.mp3",
    "vocal_url": "https://file.runapi.ai/s/3d70****b172_Vocals.mp3"
  }
}

Failed:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "failed",
  "error": "Vocal separation failed."
}

Convert to WAV Format

Convert audio to WAV format:

curl -X POST "https://runapi.ai/api/v1/suno/convert_audio" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "task_id": "03fe3e68-2dec-487c-a810-885667aed19c",
    "audio_id": "6949072e-5cdb-43a3-b093-56d16e582aeb",
    "callback_url": "https://your-app.com/callbacks/suno"
  }'
request.body = {
  task_id: "03fe3e68-2dec-487c-a810-885667aed19c",
  audio_id: "6949072e-5cdb-43a3-b093-56d16e582aeb",
  callback_url: "https://your-app.com/callbacks/suno"
}.to_json
data = {
    "task_id": "03fe3e68-2dec-487c-a810-885667aed19c",
    "audio_id": "6949072e-5cdb-43a3-b093-56d16e582aeb",
    "callback_url": "https://your-app.com/callbacks/suno"
}
body: JSON.stringify({
  task_id: "03fe3e68-2dec-487c-a810-885667aed19c",
  audio_id: "6949072e-5cdb-43a3-b093-56d16e582aeb",
  callback_url: "https://your-app.com/callbacks/suno"
})

Convert existing music audios to high-quality WAV format.

HTTP Request

POST https://runapi.ai/api/v1/suno/convert_audio

Request Body Parameters

Parameter Type Required Description
task_id string Yes The task ID of the music generation task
audio_id string Yes The audio ID of the track to convert
callback_url string No URL to receive completion notification

Response

HTTP 202 - Task accepted:

{
  "id": "281e5b0*********************f39b9",
  "status": "processing"
}

Callback Format

Success callback:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "completed",
  "wav_url": "https://file.runapi.ai/s/04e6****e727.wav"
}

Failed callback:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "failed",
  "error": "WAV conversion failed."
}

Get WAV Conversion Details

Query WAV conversion status:

curl "https://runapi.ai/api/v1/suno/convert_audio/:id" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
uri = URI('https://runapi.ai/api/v1/suno/convert_audio/TASK_ID')
request = Net::HTTP::Get.new(uri)
url = "https://runapi.ai/api/v1/suno/convert_audio/TASK_ID"
response = requests.get(url, headers=headers)
fetch('https://runapi.ai/api/v1/suno/convert_audio/TASK_ID', {
  method: 'GET',
  headers: {'Authorization': 'Bearer YOUR_API_TOKEN'}
});

Query the status and details of a WAV conversion task.

HTTP Request

GET https://runapi.ai/api/v1/suno/convert_audio/:id

URL Parameters

Parameter Description
id The task ID returned from the WAV generate endpoint

Response

Processing:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "processing"
}

Completed:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "completed",
  "wav_url": "https://file.runapi.ai/s/04e6****e727.wav"
}

Failed:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "failed",
  "error": "WAV conversion failed."
}

Generate MIDI from Audio

Generate MIDI from an audio file:

curl -X POST "https://runapi.ai/api/v1/suno/generate_midi" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "task_id": "03fe3e68-2dec-487c-a810-885667aed19c",
    "callback_url": "https://your-app.com/callbacks/suno"
  }'
request.body = {
  task_id: "03fe3e68-2dec-487c-a810-885667aed19c",
  callback_url: "https://your-app.com/callbacks/suno"
}.to_json
data = {
    "task_id": "03fe3e68-2dec-487c-a810-885667aed19c",
    "callback_url": "https://your-app.com/callbacks/suno"
}
body: JSON.stringify({
  task_id: "03fe3e68-2dec-487c-a810-885667aed19c",
  callback_url: "https://your-app.com/callbacks/suno"
})

Convert a separated audio track into MIDI format with detailed note information. Requires a task ID from a previous split_stem vocal separation task.

HTTP Request

POST https://runapi.ai/api/v1/suno/generate_midi

Request Body Parameters

Parameter Type Required Description
task_id string Yes The task ID of a completed stem separation task
callback_url string No URL to receive completion notification

Response

HTTP 202 - Task accepted:

{
  "id": "281e5b0*********************f39b9",
  "status": "processing"
}

Callback Format

Success Response: - Contains instruments array with detected instruments - Each instrument includes note sequence data - Notes include pitch (MIDI 0-127), start/end times, velocity

Success callback:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "completed",
  "instruments": [
    {
      "name": "Drums",
      "notes": [
        {
          "pitch": 73,
          "start_time": 0.036458333333333336,
          "end_time": 0.18229166666666666,
          "velocity": 1
        }
      ]
    },
    {
      "name": "Electric Bass (finger)",
      "notes": [
        {
          "pitch": 44,
          "start_time": 7.6875,
          "end_time": 7.911458333333333,
          "velocity": 1
        }
      ]
    }
  ]
}

Failed callback:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "failed",
  "error": "MIDI generation failed."
}

Get MIDI Details

Query MIDI status:

curl "https://runapi.ai/api/v1/suno/generate_midi/:id" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
uri = URI('https://runapi.ai/api/v1/suno/generate_midi/TASK_ID')
request = Net::HTTP::Get.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
url = "https://runapi.ai/api/v1/suno/generate_midi/TASK_ID"
response = requests.get(url, headers=headers)
fetch('https://runapi.ai/api/v1/suno/generate_midi/TASK_ID', {
  method: 'GET',
  headers: {'Authorization': 'Bearer YOUR_API_TOKEN'}
});

Query the status and details of a MIDI task.

HTTP Request

GET https://runapi.ai/api/v1/suno/generate_midi/:id

URL Parameters

Parameter Description
id The task ID returned from the MIDI endpoint

Response

Processing:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "processing",
  "instruments": []
}

Completed:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "completed",
  "instruments": [
    {
      "name": "Drums",
      "notes": [
        {
          "pitch": 73,
          "start_time": 0.036458333333333336,
          "end_time": 0.18229166666666666,
          "velocity": 1
        }
      ]
    }
  ]
}

Failed:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "failed",
  "error": "MIDI generation failed.",
  "instruments": []
}

Voice Validation Phrase

Generate a validation phrase from a source voice segment:

curl -X POST "https://runapi.ai/api/v1/suno/voice_to_validation_phrase" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "voice_url": "https://file.runapi.ai/source-vocal.mp3",
    "vocal_start_seconds": 2,
    "vocal_end_seconds": 12,
    "language": "en",
    "callback_url": "https://your-app.com/callbacks/suno-voice"
  }'

Create a phrase the user can read for a later voice verification step. The vocal window must be an integer second range where vocal_end_seconds is greater than vocal_start_seconds.

HTTP Request

POST https://runapi.ai/api/v1/suno/voice_to_validation_phrase

Request Body Parameters

Parameter Type Required Description
voice_url string Yes Public URL of the source voice recording
vocal_start_seconds integer Yes Start time of the vocal segment in seconds
vocal_end_seconds integer Yes End time of the vocal segment in seconds; must be greater than vocal_start_seconds
language string No Phrase language: en, zh, es, fr, pt, de, ja, ko, hi, or ru
callback_url string No HTTPS callback URL

Response

HTTP 202 - Task accepted:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "processing"
}

Callback Format

Phrase ready:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "completed",
  "provider_status": "wait_validating",
  "validation_phrase": "Harmonies fill the air with joyful melodies tonight"
}

Failed:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "failed",
  "provider_status": "processing_validate_fail",
  "error": "Validation phrase generation failed."
}

Get Voice Validation Phrase Details

Query validation phrase status:

curl "https://runapi.ai/api/v1/suno/voice_to_validation_phrase/:id" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Query the status and phrase returned by a validation phrase task.

HTTP Request

GET https://runapi.ai/api/v1/suno/voice_to_validation_phrase/:id

URL Parameters

Parameter Description
id The task ID returned from the voice validation phrase endpoint

Response

Completed:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "completed",
  "provider_status": "wait_validating",
  "validation_phrase": "Harmonies fill the air with joyful melodies tonight"
}

Regenerate Validation Phrase

Generate a new validation phrase for a previous validation phrase task:

curl -X POST "https://runapi.ai/api/v1/suno/regenerate_validation_phrase" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "task_id": "03fe3e68-2dec-487c-a810-885667aed19c",
    "callback_url": "https://your-app.com/callbacks/suno-voice"
  }'

Use this endpoint when the previous phrase expired, was hard to read, or needs to be replaced before the user records verification audio. task_id must reference a prior Suno validation phrase task owned by the same account.

HTTP Request

POST https://runapi.ai/api/v1/suno/regenerate_validation_phrase

Request Body Parameters

Parameter Type Required Description
task_id string Yes Task ID from Voice Validation Phrase or an earlier regeneration
callback_url string No HTTPS callback URL

Response

HTTP 202 - Task accepted:

{
  "id": "04ab2c8d-15b4-4b77-833f-9a462ce02ef6",
  "status": "processing"
}

Callback Format

Phrase ready:

{
  "id": "04ab2c8d-15b4-4b77-833f-9a462ce02ef6",
  "status": "completed",
  "provider_status": "wait_validating",
  "validation_phrase": "Silver echoes drift across the midnight ocean"
}

Get Regenerated Validation Phrase Details

Query regenerated validation phrase status:

curl "https://runapi.ai/api/v1/suno/regenerate_validation_phrase/:id" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

HTTP Request

GET https://runapi.ai/api/v1/suno/regenerate_validation_phrase/:id

URL Parameters

Parameter Description
id The task ID returned from the regenerate validation phrase endpoint

Response

Completed:

{
  "id": "04ab2c8d-15b4-4b77-833f-9a462ce02ef6",
  "status": "completed",
  "provider_status": "wait_validating",
  "validation_phrase": "Silver echoes drift across the midnight ocean"
}

Generate Voice

Create a reusable custom voice from a validation phrase task:

curl -X POST "https://runapi.ai/api/v1/suno/generate_voice" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "task_id": "03fe3e68-2dec-487c-a810-885667aed19c",
    "verify_url": "https://file.runapi.ai/verify-read.mp3",
    "voice_name": "Warm Test Voice",
    "description": "Warm vocal identity",
    "style": "Pop, Female Vocal",
    "singer_skill_level": "advanced",
    "callback_url": "https://your-app.com/callbacks/suno-voice"
  }'

Create a custom voice from a prior validation phrase task and a recording of the user reading that phrase. A completed response includes voice_id; use it as persona_id with persona_type: "voice" on supported Suno v5 music generation endpoints.

HTTP Request

POST https://runapi.ai/api/v1/suno/generate_voice

Request Body Parameters

Parameter Type Required Description
task_id string Yes Task ID from Voice Validation Phrase or Regenerate Validation Phrase
verify_url string Yes Public URL of the user's recording of the validation phrase
voice_name string No Custom voice display name
description string No Custom voice description
style string No Voice style tags
singer_skill_level string No Singer skill level: beginner, intermediate, advanced, or professional
callback_url string No HTTPS callback URL

Response

HTTP 202 - Task accepted:

{
  "id": "05bd3d12-92e6-4e8d-98f4-90ae86dfe6f1",
  "status": "processing"
}

Callback Format

Voice ready:

{
  "id": "05bd3d12-92e6-4e8d-98f4-90ae86dfe6f1",
  "status": "completed",
  "provider_status": "success",
  "voice_id": "voice_custom_123"
}

Failed:

{
  "id": "05bd3d12-92e6-4e8d-98f4-90ae86dfe6f1",
  "status": "failed",
  "provider_status": "fail",
  "error": "Custom voice generation failed."
}

Get Generate Voice Details

Query custom voice generation status:

curl "https://runapi.ai/api/v1/suno/generate_voice/:id" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Query the status and voice_id returned by a custom voice task.

HTTP Request

GET https://runapi.ai/api/v1/suno/generate_voice/:id

URL Parameters

Parameter Description
id The task ID returned by Generate Voice

Response

Completed:

{
  "id": "05bd3d12-92e6-4e8d-98f4-90ae86dfe6f1",
  "status": "completed",
  "provider_status": "success",
  "voice_id": "voice_custom_123"
}

Check Voice

Confirm that a generated custom voice is available:

curl -X POST "https://runapi.ai/api/v1/suno/check_voice" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "task_id": "05bd3d12-92e6-4e8d-98f4-90ae86dfe6f1"
  }'

Check whether a completed Generate Voice task is available before using its voice_id as persona_id with persona_type: "voice".

HTTP Request

POST https://runapi.ai/api/v1/suno/check_voice

Request Body Parameters

Parameter Type Required Description
task_id string Yes Task ID from Generate Voice

Response

Available:

{
  "is_available": true
}

Generate Music Cover

Create a music cover image:

curl -X POST "https://runapi.ai/api/v1/suno/generate_artwork" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "task_id": "03fe3e68-2dec-487c-a810-885667aed19c",
    "callback_url": "https://your-app.com/callbacks/suno"
  }'
request.body = {
  task_id: "03fe3e68-2dec-487c-a810-885667aed19c",
  callback_url: "https://your-app.com/callbacks/suno"
}.to_json
data = {
    "task_id": "03fe3e68-2dec-487c-a810-885667aed19c",
    "callback_url": "https://your-app.com/callbacks/suno"
}
body: JSON.stringify({
  task_id: "03fe3e68-2dec-487c-a810-885667aed19c",
  callback_url: "https://your-app.com/callbacks/suno"
})

Create personalized cover images for generated music.

HTTP Request

POST https://runapi.ai/api/v1/suno/generate_artwork

Request Body Parameters

Parameter Type Required Description
task_id string Yes Original music task ID from music generation endpoint
callback_url string No URL to receive completion notifications

Response

HTTP 202 - Task accepted:

{
  "id": "281e5b0*********************f39b9",
  "status": "processing"
}

Callback Format

Success Response: - Contains covers array with generated cover images - Usually generates 2 different style cover images - Cover URLs are retained for 14 days

Success callback:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "completed",
  "covers": [
    {
      "url": "https://tempfile.runapi.ai/s/1753958521_6c1b3015141849d1a9bf17b738ce9347.png"
    },
    {
      "url": "https://tempfile.runapi.ai/s/1753958524_c153143acc6340908431cf0e90cbce9e.png"
    }
  ]
}

Failed callback:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "failed",
  "error": "Cover generation failed.",
  "covers": []
}

Get Music Cover

Query music cover status:

curl "https://runapi.ai/api/v1/suno/generate_artwork/:id" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
uri = URI('https://runapi.ai/api/v1/suno/generate_artwork/TASK_ID')
request = Net::HTTP::Get.new(uri)
url = "https://runapi.ai/api/v1/suno/generate_artwork/TASK_ID"
response = requests.get(url, headers=headers)
fetch('https://runapi.ai/api/v1/suno/generate_artwork/TASK_ID', {
  method: 'GET',
  headers: {'Authorization': 'Bearer YOUR_API_TOKEN'}
});

Query the status and results of a music cover generation task.

HTTP Request

GET https://runapi.ai/api/v1/suno/generate_artwork/:id

URL Parameters

Parameter Description
id Task ID returned from the Generate Music Cover endpoint

Response

Processing:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "processing",
  "covers": []
}

Completed:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "completed",
  "covers": [
    {
      "url": "https://tempfile.runapi.ai/s/1753958521_6c1b3015141849d1a9bf17b738ce9347.png"
    },
    {
      "url": "https://tempfile.runapi.ai/s/1753958524_c153143acc6340908431cf0e90cbce9e.png"
    }
  ]
}

Failed:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "failed",
  "error": "Cover generation failed.",
  "covers": []
}

Create Music Video

Create a music video:

curl -X POST "https://runapi.ai/api/v1/suno/visualize_music" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "task_id": "03fe3e68-2dec-487c-a810-885667aed19c",
    "audio_id": "6949072e-5cdb-43a3-b093-56d16e582aeb",
    "callback_url": "https://your-app.com/callbacks/suno",
    "author": "Suno Artist",
    "domain_name": "music.example.com"
  }'
request.body = {
  task_id: "03fe3e68-2dec-487c-a810-885667aed19c",
  audio_id: "6949072e-5cdb-43a3-b093-56d16e582aeb",
  callback_url: "https://your-app.com/callbacks/suno",
  author: "Suno Artist",
  domain_name: "music.example.com"
}.to_json
data = {
    "task_id": "03fe3e68-2dec-487c-a810-885667aed19c",
    "audio_id": "6949072e-5cdb-43a3-b093-56d16e582aeb",
    "callback_url": "https://your-app.com/callbacks/suno",
    "author": "Suno Artist",
    "domain_name": "music.example.com"
}
body: JSON.stringify({
  task_id: "03fe3e68-2dec-487c-a810-885667aed19c",
  audio_id: "6949072e-5cdb-43a3-b093-56d16e582aeb",
  callback_url: "https://your-app.com/callbacks/suno",
  author: "Suno Artist",
  domain_name: "music.example.com"
})

Generate an MP4 video with visualizations for a music track.

HTTP Request

POST https://runapi.ai/api/v1/suno/visualize_music

Request Body Parameters

Parameter Type Required Description
task_id string Yes The task ID of the music generation task
audio_id string Yes The ID of the specific track to convert to video
callback_url string No URL to receive completion notification
author string No Artist/creator name to display on video (max 50 chars)
domain_name string No Website/brand to display as watermark (max 50 chars)

Response

HTTP 202 - Task accepted:

{
  "id": "281e5b0*********************f39b9",
  "status": "processing"
}

Callback Format

Success callback:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "completed",
  "video_url": "https://file.runapi.ai/videos/video_847715e66259.mp4"
}

Failed callback:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "failed",
  "error": "Video generation failed."
}

Get Music Video Details

Query music video status:

curl "https://runapi.ai/api/v1/suno/visualize_music/:id" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
uri = URI('https://runapi.ai/api/v1/suno/visualize_music/TASK_ID')
request = Net::HTTP::Get.new(uri)
url = "https://runapi.ai/api/v1/suno/visualize_music/TASK_ID"
response = requests.get(url, headers=headers)
fetch('https://runapi.ai/api/v1/suno/visualize_music/TASK_ID', {
  method: 'GET',
  headers: {'Authorization': 'Bearer YOUR_API_TOKEN'}
});

Query the status and details of a music video generation task.

HTTP Request

GET https://runapi.ai/api/v1/suno/visualize_music/:id

URL Parameters

Parameter Description
id The task ID returned from the music video generation endpoint

Response

Processing:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "processing"
}

Completed:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "completed",
  "video_url": "https://file.runapi.ai/videos/video_847715e66259.mp4"
}

Failed:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "failed",
  "error": "Video generation failed."
}

Boost Music Style

Enhance music style description:

curl -X POST "https://runapi.ai/api/v1/suno/boost_style" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "description": "Pop, Mysterious"
  }'
request.body = {
  description: "Pop, Mysterious"
}.to_json
data = {"description": "Pop, Mysterious"}
body: JSON.stringify({description: "Pop, Mysterious"})

Generate enhanced music style descriptions for more detailed prompts.

HTTP Request

POST https://runapi.ai/api/v1/suno/boost_style

Request Body Parameters

Parameter Type Required Description
description string Yes Concise style keywords or brief description

Response

Returns the enhanced style description immediately (synchronous response).

{
  "style": "Pop, Mysterious, Upbeat, Electronic, Synth-driven, Catchy hooks"
}

Get Timestamped Lyrics

Get timestamped lyrics:

curl -X POST "https://runapi.ai/api/v1/suno/get_timestamped_lyrics" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "task_id": "b7e7c624-c244-4ba7-a9f7-7d85da73cf03",
    "audio_id": "0aac6db8-cbe9-4af2-aea6-d7aa7d3a2355"
  }'
request.body = {
  task_id: "b7e7c624-c244-4ba7-a9f7-7d85da73cf03",
  audio_id: "0aac6db8-cbe9-4af2-aea6-d7aa7d3a2355"
}.to_json
data = {
    "task_id": "b7e7c624-c244-4ba7-a9f7-7d85da73cf03",
    "audio_id": "0aac6db8-cbe9-4af2-aea6-d7aa7d3a2355"
}
body: JSON.stringify({
  task_id: "b7e7c624-c244-4ba7-a9f7-7d85da73cf03",
  audio_id: "0aac6db8-cbe9-4af2-aea6-d7aa7d3a2355"
})

Retrieve timestamped lyrics for synchronized display during audio playback.

HTTP Request

POST https://runapi.ai/api/v1/suno/get_timestamped_lyrics

Request Body Parameters

Parameter Type Required Description
task_id string Yes The task ID of the music generation task
audio_id string Yes The specific audio ID to retrieve lyrics for

Response

Returns timestamped lyrics data immediately (synchronous response). This endpoint does not return a processing status.

{
  "aligned_words": [
    {
      "word": "[Verse]\nWaggin'",
      "success": true,
      "start_time": 1.36,
      "end_time": 1.79,
      "palign": 0
    },
    {
      "word": "my",
      "success": true,
      "start_time": 1.79,
      "end_time": 1.95,
      "palign": 0
    }
  ],
  "waveform_data": [0, 1, 0.5, 0.75],
  "hoot_cer": 0.3803191489361702,
  "is_streamed": false
}

Failed:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "failed",
  "error": "Timestamped lyrics generation failed."
}

Generate Persona

Create a music persona:

curl -X POST "https://runapi.ai/api/v1/suno/generate_persona" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "task_id": "03fe3e68-2dec-487c-a810-885667aed19c",
    "audio_id": "6949072e-5cdb-43a3-b093-56d16e582aeb",
    "name": "Electronic Pop Singer",
    "description": "A modern electronic music style pop singer, skilled in dynamic rhythms and synthesizer tones"
  }'
request.body = {
  task_id: "03fe3e68-2dec-487c-a810-885667aed19c",
  audio_id: "6949072e-5cdb-43a3-b093-56d16e582aeb",
  name: "Electronic Pop Singer",
  description: "A modern electronic music style pop singer"
}.to_json
data = {
    "task_id": "03fe3e68-2dec-487c-a810-885667aed19c",
    "audio_id": "6949072e-5cdb-43a3-b093-56d16e582aeb",
    "name": "Electronic Pop Singer",
    "description": "A modern electronic music style pop singer"
}
body: JSON.stringify({
  task_id: "03fe3e68-2dec-487c-a810-885667aed19c",
  audio_id: "6949072e-5cdb-43a3-b093-56d16e582aeb",
  name: "Electronic Pop Singer",
  description: "A modern electronic music style pop singer"
})

Create a personalized music Persona based on generated music.

HTTP Request

POST https://runapi.ai/api/v1/suno/generate_persona

Request Body Parameters

Parameter Type Required Description
task_id string Yes Task ID from music generation endpoints
audio_id string Yes Specific audio ID to create Persona for
name string Yes Easily recognizable name for the Persona
description string Yes Persona's musical characteristics and style

Response

Returns the generated persona immediately (synchronous response).

{
  "persona": {
    "id": "abc123def456",
    "name": "Electronic Pop Singer",
    "description": "A modern electronic music style pop singer, skilled in dynamic rhythms and synthesizer tones"
  }
}

Replace Music Section

Replace a music section:

curl -X POST "https://runapi.ai/api/v1/suno/replace_section" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "task_id": "03fe3e68-2dec-487c-a810-885667aed19c",
    "audio_id": "6949072e-5cdb-43a3-b093-56d16e582aeb",
    "lyrics": "[Verse]\nA calm and relaxing piano track.",
    "tags": "Jazz",
    "title": "Relaxing Piano",
    "infill_start_time": 10.5,
    "infill_end_time": 20.75,
    "callback_url": "https://your-app.com/callbacks/suno"
  }'
request.body = {
  task_id: "03fe3e68-2dec-487c-a810-885667aed19c",
  audio_id: "6949072e-5cdb-43a3-b093-56d16e582aeb",
  lyrics: "[Verse]\nA calm and relaxing piano track.",
  tags: "Jazz",
  title: "Relaxing Piano",
  infill_start_time: 10.5,
  infill_end_time: 20.75,
  callback_url: "https://your-app.com/callbacks/suno"
}.to_json
data = {
    "task_id": "03fe3e68-2dec-487c-a810-885667aed19c",
    "audio_id": "6949072e-5cdb-43a3-b093-56d16e582aeb",
    "lyrics": "[Verse]\nA calm and relaxing piano track.",
    "tags": "Jazz",
    "title": "Relaxing Piano",
    "infill_start_time": 10.5,
    "infill_end_time": 20.75,
    "callback_url": "https://your-app.com/callbacks/suno"
}
body: JSON.stringify({
  task_id: "03fe3e68-2dec-487c-a810-885667aed19c",
  audio_id: "6949072e-5cdb-43a3-b093-56d16e582aeb",
  lyrics: "[Verse]\nA calm and relaxing piano track.",
  tags: "Jazz",
  title: "Relaxing Piano",
  infill_start_time: 10.5,
  infill_end_time: 20.75,
  callback_url: "https://your-app.com/callbacks/suno"
})

Replace a specific time segment within existing music.

HTTP Request

POST https://runapi.ai/api/v1/suno/replace_section

Request Body Parameters

Parameter Type Required Description
task_id string Yes Original task ID that identifies the source music
audio_id string Yes Unique identifier of the audio track to replace
lyrics string Yes Exact lyrics for the replacement segment
tags string Yes Music style tags
title string Yes Music title
infill_start_time number Yes Start time in seconds (2 decimals)
infill_end_time number Yes End time in seconds (2 decimals)
callback_url string No URL to receive completion notifications
negative_tags string No Excluded music styles
full_lyrics string No Complete lyrics after modification

Response

HTTP 202 - Task accepted:

{
  "id": "281e5b0*********************f39b9",
  "status": "processing"
}

Callback Format

Success callback:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "completed",
  "track": {
    "id": "6949072e-5cdb-43a3-b093-56d16e582aeb",
    "audio_url": "https://file.runapi.ai/****.mp3",
    "stream_audio_url": "https://file.runapi.ai/****",
    "image_url": "https://file.runapi.ai/****.jpeg",
    "lyrics": "[Verse]\nA calm and relaxing piano track.",
    "model_name": "chirp-v3-5",
    "title": "Relaxing Piano",
    "tags": ["Jazz"],
    "duration": 198.44
  }
}

Failed callback:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "failed",
  "error": "Audio generation failed."
}

Get Replace Section Details

Query section replacement status:

curl "https://runapi.ai/api/v1/suno/replace_section/:id" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
uri = URI('https://runapi.ai/api/v1/suno/replace_section/TASK_ID')
request = Net::HTTP::Get.new(uri)
url = "https://runapi.ai/api/v1/suno/replace_section/TASK_ID"
response = requests.get(url, headers=headers)
fetch('https://runapi.ai/api/v1/suno/replace_section/TASK_ID', {
  method: 'GET',
  headers: {'Authorization': 'Bearer YOUR_API_TOKEN'}
});

Query the status and results of a replace section task.

HTTP Request

GET https://runapi.ai/api/v1/suno/replace_section/:id

URL Parameters

Parameter Description
id Task ID returned from the Replace Music Section endpoint

Response

Processing:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "processing"
}

Completed:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "completed",
  "track": {
    "id": "6949072e-5cdb-43a3-b093-56d16e582aeb",
    "audio_url": "https://file.runapi.ai/****.mp3",
    "stream_audio_url": "https://file.runapi.ai/****",
    "image_url": "https://file.runapi.ai/****.jpeg",
    "lyrics": "[Verse]\nA calm and relaxing piano track.",
    "model_name": "chirp-v3-5",
    "title": "Relaxing Piano",
    "tags": ["Jazz"],
    "duration": 198.44
  }
}

Failed:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "failed",
  "error": "Audio generation failed."
}

Upload and Covers

Upload and cover an audio file:

curl -X POST "https://runapi.ai/api/v1/suno/cover_audio" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "upload_url": "https://cdn.runapi.ai/public/samples/music.mp3",
    "vocal_mode": "instrumental",
    "style": "Classical",
    "title": "Peaceful Piano Meditation",
    "model": "suno-v5",
    "callback_url": "https://your-app.com/callbacks/suno"
  }'
request.body = {
  upload_url: "https://cdn.runapi.ai/public/samples/music.mp3",
  vocal_mode: "instrumental",
  style: "Classical",
  title: "Peaceful Piano Meditation",
  model: "suno-v5",
  callback_url: "https://your-app.com/callbacks/suno"
}.to_json
data = {
    "upload_url": "https://cdn.runapi.ai/public/samples/music.mp3",
    "vocal_mode": "instrumental",
    "style": "Classical",
    "title": "Peaceful Piano Meditation",
    "model": "suno-v5",
    "callback_url": "https://your-app.com/callbacks/suno"
}
body: JSON.stringify({
  upload_url: "https://cdn.runapi.ai/public/samples/music.mp3",
  vocal_mode: "instrumental",
  style: "Classical",
  title: "Peaceful Piano Meditation",
  model: "suno-v5",
  callback_url: "https://your-app.com/callbacks/suno"
})

Transform uploaded audio into a new style while retaining its core melody.

HTTP Request

POST https://runapi.ai/api/v1/suno/cover_audio

Request Body Parameters

Request Shapes

Choose vocal_mode. Add upload_url, model, and optional callback_url to each request.

Parameter Type Required Description
upload_url string Yes URL of the audio file to process (max 8 minutes). You can use the download_url returned by POST /files/from_url; that temporary link expires after 24 hours.
model string Yes Model version: suno-v5, suno-v4.5-plus, suno-v4.5-all, suno-v4.5, suno-v4
callback_url string No URL to receive completion notifications
vocal_mode string Yes auto_lyrics, exact_lyrics, or instrumental.
prompt string No Cover brief for automatic lyrics.
lyrics string No Exact cover lyrics.
style string No Music style.
title string No Music title.
persona_id string No Persona ID to apply. Create one via Generate Persona.
persona_type string No Persona type, used with persona_id. Values: style for style characteristics, voice for voice characteristics (suno-v5 only). Ignored without persona_id.
negative_tags string No Styles to exclude
vocal_gender string No Preferred vocal gender: male or female. Increases probability only.
style_weight number No Style adherence weight (0-1)
weirdness_constraint number No Creativity constraint (0-1)
audio_weight number No Audio consistency weight (0-1)

Response

Returns the task ID for tracking generation status.

HTTP 202 - Task accepted:

{
  "id": "281e5b0*********************f39b9",
  "status": "processing"
}

Callback Format

Success callback:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "completed",
  "generation_stage": "all_audios_ready",
  "audios": [
    {
      "id": "8551****662c",
      "audio_url": "https://file.runapi.ai/****.mp3",
      "stream_audio_url": "https://file.runapi.ai/****",
      "image_url": "https://file.runapi.ai/****.jpeg",
      "lyrics": "[Verse] Calm piano melodies flow gently",
      "model_name": "chirp-v3-5",
      "title": "Peaceful Piano Meditation (Cover)",
      "tags": ["classical", "relaxing"],
      "duration": 198.44
    }
  ]
}

Failed callback:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "failed",
  "generation_stage": "failed",
  "error": "Cover generation failed."
}

Get Upload and Covers Details

Query upload and covers status:

curl "https://runapi.ai/api/v1/suno/cover_audio/:id" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
uri = URI('https://runapi.ai/api/v1/suno/cover_audio/TASK_ID')
request = Net::HTTP::Get.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
url = "https://runapi.ai/api/v1/suno/cover_audio/TASK_ID"
response = requests.get(url, headers=headers)
fetch('https://runapi.ai/api/v1/suno/cover_audio/TASK_ID', {
  method: 'GET',
  headers: {'Authorization': 'Bearer YOUR_API_TOKEN'}
});

Query the status and details of an upload and covers task.

HTTP Request

GET https://runapi.ai/api/v1/suno/cover_audio/:id

URL Parameters

Parameter Description
id The task ID returned when you submitted the upload and covers request

Response

Processing:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "processing"
}

Completed:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "completed",
  "generation_stage": "all_audios_ready",
  "audios": [
    {
      "id": "8551****662c",
      "audio_url": "https://file.runapi.ai/****.mp3",
      "stream_audio_url": "https://file.runapi.ai/****",
      "image_url": "https://file.runapi.ai/****.jpeg",
      "lyrics": "[Verse] Calm piano melodies flow gently",
      "model_name": "chirp-v3-5",
      "title": "Peaceful Piano Meditation (Cover)",
      "tags": ["classical", "relaxing"],
      "duration": 198.44
    }
  ]
}

Failed:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "failed",
  "error": "Cover generation failed."
}

Upload and Extensions

Extend an audio file:

curl -X POST "https://runapi.ai/api/v1/suno/extend_music" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "upload_url": "https://cdn.runapi.ai/public/samples/music.mp3",
    "parameter_mode": "custom",
    "prompt": "Extend the music with more relaxing piano notes",
    "style": "Classical",
    "title": "Peaceful Piano Extended",
    "continue_at": 60,
    "model": "suno-v5",
    "callback_url": "https://your-app.com/callbacks/suno"
  }'
request.body = {
  upload_url: "https://cdn.runapi.ai/public/samples/music.mp3",
  parameter_mode: "custom",
  prompt: "Extend the music with more relaxing piano notes",
  style: "Classical",
  title: "Peaceful Piano Extended",
  continue_at: 60,
  model: "suno-v5",
  callback_url: "https://your-app.com/callbacks/suno"
}.to_json
data = {
    "upload_url": "https://cdn.runapi.ai/public/samples/music.mp3",
    "parameter_mode": "custom",
    "prompt": "Extend the music with more relaxing piano notes",
    "style": "Classical",
    "title": "Peaceful Piano Extended",
    "continue_at": 60,
    "model": "suno-v5",
    "callback_url": "https://your-app.com/callbacks/suno"
}
body: JSON.stringify({
  upload_url: "https://cdn.runapi.ai/public/samples/music.mp3",
  parameter_mode: "custom",
  prompt: "Extend the music with more relaxing piano notes",
  style: "Classical",
  title: "Peaceful Piano Extended",
  continue_at: 60,
  model: "suno-v5",
  callback_url: "https://your-app.com/callbacks/suno"
})

Extend uploaded audios while preserving the original style.

HTTP Request

POST https://runapi.ai/api/v1/suno/extend_music

Request Body Parameters

Parameter Type Required Description
upload_url string Yes URL of the audio file to process (max 8 minutes). You can use the download_url returned by POST /files/from_url; that temporary link expires after 24 hours.
parameter_mode string Yes source to inherit source parameters, or custom to provide parameters in this request
model string Yes Model version: suno-v5, suno-v4.5-plus, suno-v4.5-all, suno-v4.5, suno-v4
callback_url string No URL to receive completion notifications
continue_at number Conditional Start time in seconds (required when parameter_mode is custom)
prompt string Conditional Extension description (required when parameter_mode is source or when instrumental is false)
style string Conditional Music style (required when parameter_mode is custom)
title string Conditional Music title (required when parameter_mode is custom)
instrumental boolean Conditional Whether audio is instrumental (required when parameter_mode is custom)
persona_id string No Persona ID to apply when parameter_mode is custom. Create one via Generate Persona.
persona_type string No Persona type, used with persona_id. Values: style for style characteristics, voice for voice characteristics (suno-v5 only). Ignored without persona_id.
negative_tags string No Styles to exclude
vocal_gender string No Preferred vocal gender: male or female. Only works with parameter_mode: "custom". Increases probability only.
style_weight number No Style adherence weight (0-1)
weirdness_constraint number No Creativity constraint (0-1)
audio_weight number No Audio consistency weight (0-1)

Response

HTTP 202 - Task accepted:

{
  "id": "281e5b0*********************f39b9",
  "status": "processing"
}

Callback Format

Success callback:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "completed",
  "generation_stage": "all_audios_ready",
  "audios": [
    {
      "id": "8551****662c",
      "audio_url": "https://file.runapi.ai/****.mp3",
      "stream_audio_url": "https://file.runapi.ai/****",
      "image_url": "https://file.runapi.ai/****.jpeg",
      "lyrics": "[Verse] Continue the beautiful melody",
      "model_name": "chirp-v3-5",
      "title": "Peaceful Piano Extended",
      "tags": ["classical", "relaxing"],
      "duration": 298.44
    }
  ]
}

Failed callback:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "failed",
  "generation_stage": "failed",
  "error": "Extension generation failed."
}

Get Upload and Extension Details

Query upload extension status:

curl "https://runapi.ai/api/v1/suno/extend_music/:id" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
uri = URI('https://runapi.ai/api/v1/suno/extend_music/TASK_ID')
request = Net::HTTP::Get.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
url = "https://runapi.ai/api/v1/suno/extend_music/TASK_ID"
response = requests.get(url, headers=headers)
fetch('https://runapi.ai/api/v1/suno/extend_music/TASK_ID', {
  method: 'GET',
  headers: {'Authorization': 'Bearer YOUR_API_TOKEN'}
});

Query the status and details of an upload extension task.

HTTP Request

GET https://runapi.ai/api/v1/suno/extend_music/:id

URL Parameters

Parameter Description
id The task ID returned when you submitted the upload extension request

Response

Processing:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "processing"
}

Completed:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "completed",
  "generation_stage": "all_audios_ready",
  "audios": [
    {
      "id": "8551****662c",
      "audio_url": "https://file.runapi.ai/****.mp3",
      "stream_audio_url": "https://file.runapi.ai/****",
      "image_url": "https://file.runapi.ai/****.jpeg",
      "lyrics": "[Verse] Continue the beautiful melody",
      "model_name": "chirp-v3-5",
      "title": "Peaceful Piano Extended",
      "tags": ["classical", "relaxing"],
      "duration": 298.44
    }
  ]
}

Failed:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "failed",
  "error": "Extension generation failed."
}

Mashup

Create a mashup from two audio files:

curl -X POST "https://runapi.ai/api/v1/suno/create_mashup" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "upload_url_list": ["https://cdn.runapi.ai/public/samples/music.mp3", "https://cdn.runapi.ai/public/samples/music.mp3"],
    "vocal_mode": "exact_lyrics",
    "lyrics": "[Verse]\nA calm and relaxing piano track with soft melodies",
    "style": "Jazz",
    "title": "Relaxing Piano",
    "model": "suno-v4",
    "callback_url": "https://your-app.com/callbacks/suno"
  }'
request.body = {
  upload_url_list: ["https://cdn.runapi.ai/public/samples/music.mp3", "https://cdn.runapi.ai/public/samples/music.mp3"],
  vocal_mode: "exact_lyrics",
  lyrics: "[Verse]\nA calm and relaxing piano track with soft melodies",
  style: "Jazz",
  title: "Relaxing Piano",
  model: "suno-v4",
  callback_url: "https://your-app.com/callbacks/suno"
}.to_json
data = {
    "upload_url_list": ["https://cdn.runapi.ai/public/samples/music.mp3", "https://cdn.runapi.ai/public/samples/music.mp3"],
    "vocal_mode": "exact_lyrics",
    "lyrics": "[Verse]\nA calm and relaxing piano track with soft melodies",
    "style": "Jazz",
    "title": "Relaxing Piano",
    "model": "suno-v4",
    "callback_url": "https://your-app.com/callbacks/suno"
}
body: JSON.stringify({
  upload_url_list: ["https://cdn.runapi.ai/public/samples/music.mp3", "https://cdn.runapi.ai/public/samples/music.mp3"],
  vocal_mode: "exact_lyrics",
  lyrics: "[Verse]\nA calm and relaxing piano track with soft melodies",
  style: "Jazz",
  title: "Relaxing Piano",
  model: "suno-v4",
  callback_url: "https://your-app.com/callbacks/suno"
})

Combine two uploaded audio files into a cohesive new composition using AI mashup generation.

HTTP Request

POST https://runapi.ai/api/v1/suno/create_mashup

Request Body Parameters

Request Shapes

Choose vocal_mode. Add upload_url_list, model, and optional callback_url to each request.

Parameter Type Required Description
upload_url_list array Yes Two publicly accessible audio file URLs to mashup (exactly 2 required)
model string Yes Model version: suno-v5, suno-v4.5-plus, suno-v4.5-all, suno-v4.5, suno-v4
callback_url string No URL to receive completion notifications
vocal_mode string Yes auto_lyrics, exact_lyrics, or instrumental.
prompt string No Mashup brief for automatic lyrics.
lyrics string No Exact mashup lyrics.
style string No Music style.
title string No Music title.
persona_id string No Persona ID to apply. Create one via Generate Persona.
persona_type string No Persona type, used with persona_id. Values: style for style characteristics, voice for voice characteristics (suno-v5 only). Ignored without persona_id.
vocal_gender string No Preferred vocal gender: male or female. Increases probability only.
style_weight number No Style adherence weight (0-1)
weirdness_constraint number No Creativity constraint (0-1)
audio_weight number No Audio consistency weight (0-1)

Response

Returns the task ID for tracking generation status.

HTTP 202 - Task accepted:

{
  "id": "281e5b0*********************f39b9",
  "status": "processing"
}

Callback Format

Success callback:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "completed",
  "generation_stage": "all_audios_ready",
  "audios": [
    {
      "id": "8551****662c",
      "audio_url": "https://file.runapi.ai/****.mp3",
      "stream_audio_url": "https://file.runapi.ai/****",
      "image_url": "https://file.runapi.ai/****.jpeg",
      "lyrics": "[Verse] Night city lights shining bright",
      "model_name": "chirp-v4",
      "title": "Relaxing Piano",
      "tags": ["jazz", "piano"],
      "duration": 198.44
    }
  ]
}

Failed callback:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "failed",
  "generation_stage": "failed",
  "error": "Mashup generation failed."
}

Get Mashup Details

Query mashup status:

curl "https://runapi.ai/api/v1/suno/create_mashup/:id" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
uri = URI('https://runapi.ai/api/v1/suno/create_mashup/TASK_ID')
request = Net::HTTP::Get.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
url = "https://runapi.ai/api/v1/suno/create_mashup/TASK_ID"
response = requests.get(url, headers=headers)
fetch('https://runapi.ai/api/v1/suno/create_mashup/TASK_ID', {
  method: 'GET',
  headers: {'Authorization': 'Bearer YOUR_API_TOKEN'}
});

Query the status and details of a mashup task.

HTTP Request

GET https://runapi.ai/api/v1/suno/create_mashup/:id

URL Parameters

Parameter Description
id The task ID returned when you submitted the mashup request

Response

Processing:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "processing"
}

Completed:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "completed",
  "generation_stage": "all_audios_ready",
  "audios": [
    {
      "id": "8551****662c",
      "audio_url": "https://file.runapi.ai/****.mp3",
      "stream_audio_url": "https://file.runapi.ai/****",
      "image_url": "https://file.runapi.ai/****.jpeg",
      "lyrics": "[Verse] Night city lights shining bright",
      "model_name": "chirp-v4",
      "title": "Relaxing Piano",
      "tags": ["jazz", "piano"],
      "duration": 198.44
    }
  ]
}

Failed:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "failed",
  "generation_stage": "failed",
  "error": "Mashup generation failed."
}

Generate Sound

Create ambient or loopable sound effects from a prompt:

curl -X POST "https://runapi.ai/api/v1/suno/text_to_sound" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Rain on a tin roof, distant thunder, cozy atmosphere",
    "model": "suno-v5",
    "sound_loop": true,
    "sound_tempo": 90,
    "sound_key": "Cm",
    "grab_lyrics": false,
    "callback_url": "https://your-app.com/callbacks/suno"
  }'
request.body = {
  prompt: "Rain on a tin roof, distant thunder, cozy atmosphere",
  model: "suno-v5",
  sound_loop: true,
  sound_tempo: 90,
  sound_key: "Cm",
  grab_lyrics: false,
  callback_url: "https://your-app.com/callbacks/suno"
}.to_json
data = {
    "prompt": "Rain on a tin roof, distant thunder, cozy atmosphere",
    "model": "suno-v5",
    "sound_loop": True,
    "sound_tempo": 90,
    "sound_key": "Cm",
    "grab_lyrics": False,
    "callback_url": "https://your-app.com/callbacks/suno"
}
body: JSON.stringify({
  prompt: "Rain on a tin roof, distant thunder, cozy atmosphere",
  model: "suno-v5",
  sound_loop: true,
  sound_tempo: 90,
  sound_key: "Cm",
  grab_lyrics: false,
  callback_url: "https://your-app.com/callbacks/suno"
})

Create ambient audio, sound effects, or loopable tracks from a text prompt. Supports BPM and musical key control for precise stylistic direction.

HTTP Request

POST https://runapi.ai/api/v1/suno/text_to_sound

Request Body Parameters

Parameter Type Required Description
prompt string Yes Sound description, max 500 characters
model string Yes Model version: suno-v5, suno-v5.5
sound_loop boolean No Generate looping audio. Default false
sound_tempo integer No Beats per minute, 1–300
sound_key string No Musical key: Cm, C#m, Dm, D#m, Em, Fm, F#m, Gm, G#m, Am, A#m, Bm, C, C#, D, D#, E, F, F#, G, G#, A, A#, B. Default Any
grab_lyrics boolean No Capture lyric subtitles for later retrieval. Default false
callback_url string No URL to receive completion notifications

Response

Returns the task ID for tracking generation status.

HTTP 202 - Task accepted:

{
  "id": "281e5b0*********************f39b9",
  "status": "processing"
}

Callback Format

Success callback:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "completed",
  "generation_stage": "all_audios_ready",
  "audios": [
    {
      "id": "8551****662c",
      "audio_url": "https://file.runapi.ai/****.mp3",
      "stream_audio_url": "https://file.runapi.ai/****",
      "image_url": "https://file.runapi.ai/****.jpeg",
      "prompt": "Rain on a tin roof, distant thunder",
      "model_name": "chirp-v5",
      "title": "Rainy Night",
      "tags": ["ambient", "rain", "loopable"],
      "duration": 32.5
    }
  ]
}

Failed callback:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "failed",
  "generation_stage": "failed",
  "error": "Generation failed, please retry."
}

Get Sound Details

Query sound task status:

curl "https://runapi.ai/api/v1/suno/text_to_sound/:id" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
uri = URI('https://runapi.ai/api/v1/suno/text_to_sound/TASK_ID')
request = Net::HTTP::Get.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
url = "https://runapi.ai/api/v1/suno/text_to_sound/TASK_ID"
response = requests.get(url, headers=headers)
fetch('https://runapi.ai/api/v1/suno/text_to_sound/TASK_ID', {
  method: 'GET',
  headers: {'Authorization': 'Bearer YOUR_API_TOKEN'}
});

Query the status and details of a sound generation task.

HTTP Request

GET https://runapi.ai/api/v1/suno/text_to_sound/:id

URL Parameters

Parameter Description
id The task ID returned when you submitted the sound generation request

Response

Processing:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "processing"
}

Completed:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "completed",
  "generation_stage": "all_audios_ready",
  "audios": [
    {
      "id": "8551****662c",
      "audio_url": "https://file.runapi.ai/****.mp3",
      "stream_audio_url": "https://file.runapi.ai/****",
      "image_url": "https://file.runapi.ai/****.jpeg",
      "prompt": "Rain on a tin roof, distant thunder",
      "model_name": "chirp-v5",
      "title": "Rainy Night",
      "tags": ["ambient", "rain", "loopable"],
      "duration": 32.5
    }
  ]
}

Failed:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "failed",
  "generation_stage": "failed",
  "error": "Generation failed, please retry."
}

Generate MIDI from an audio file:

curl -X POST "https://runapi.ai/api/v1/suno/generate_midi" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "task_id": "03fe3e68-2dec-487c-a810-885667aed19c",
    "callback_url": "https://your-app.com/callbacks/suno"
  }'
request.body = {
  task_id: "03fe3e68-2dec-487c-a810-885667aed19c",
  callback_url: "https://your-app.com/callbacks/suno"
}.to_json
data = {
    "task_id": "03fe3e68-2dec-487c-a810-885667aed19c",
    "callback_url": "https://your-app.com/callbacks/suno"
}
body: JSON.stringify({
  task_id: "03fe3e68-2dec-487c-a810-885667aed19c",
  callback_url: "https://your-app.com/callbacks/suno"
})

Convert a separated audio track into MIDI format with detailed note information. Requires a task ID from a previous split_stem vocal separation task.

HTTP Request

POST https://runapi.ai/api/v1/suno/generate_midi

Request Body Parameters

Parameter Type Required Description
task_id string Yes The task ID of a completed stem separation task
callback_url string No URL to receive completion notification

Response

HTTP 202 - Task accepted:

{
  "id": "281e5b0*********************f39b9",
  "status": "processing"
}

Callback Format

Success Response: - Contains instruments array with detected instruments - Each instrument includes note sequence data - Notes include pitch (MIDI 0-127), start/end times, velocity

Success callback:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "completed",
  "instruments": [
    {
      "name": "Drums",
      "notes": [
        {
          "pitch": 73,
          "start_time": 0.036458333333333336,
          "end_time": 0.18229166666666666,
          "velocity": 1
        }
      ]
    },
    {
      "name": "Electric Bass (finger)",
      "notes": [
        {
          "pitch": 44,
          "start_time": 7.6875,
          "end_time": 7.911458333333333,
          "velocity": 1
        }
      ]
    }
  ]
}

Failed callback:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "failed",
  "error": "MIDI generation failed."
}

Get MIDI Details

Query MIDI status:

curl "https://runapi.ai/api/v1/suno/generate_midi/:id" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
uri = URI('https://runapi.ai/api/v1/suno/generate_midi/TASK_ID')
request = Net::HTTP::Get.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
url = "https://runapi.ai/api/v1/suno/generate_midi/TASK_ID"
response = requests.get(url, headers=headers)
fetch('https://runapi.ai/api/v1/suno/generate_midi/TASK_ID', {
  method: 'GET',
  headers: {'Authorization': 'Bearer YOUR_API_TOKEN'}
});

Query the status and details of a MIDI task.

HTTP Request

GET https://runapi.ai/api/v1/suno/generate_midi/:id

URL Parameters

Parameter Description
id The task ID returned from the MIDI endpoint

Response

Processing:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "processing",
  "instruments": []
}

Completed:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "completed",
  "instruments": [
    {
      "name": "Drums",
      "notes": [
        {
          "pitch": 73,
          "start_time": 0.036458333333333336,
          "end_time": 0.18229166666666666,
          "velocity": 1
        }
      ]
    }
  ]
}

Failed:

{
  "id": "03fe3e68-2dec-487c-a810-885667aed19c",
  "status": "failed",
  "error": "MIDI generation failed.",
  "instruments": []
}

Nano Banana

Nano Banana on RunAPI creates high-quality images from text prompts.

Version Comparison

Feature Base (nano-banana) Pro (nano-banana-pro) V2 (nano-banana-2)
Max Resolution 1024px 4K 4K
Size Control aspect_ratio (11 presets) aspect_ratio + output_resolution aspect_ratio (15 presets) + output_resolution
Max Prompt 5,000 chars 5,000 chars 20,000 chars
Max Images 8 per request 8 per request 14 per request
Best For Quick prototypes Production quality Complex multi-panel prompts

Nano Banana Endpoints

Task Endpoint Model
Create images (standard) Create Text-to-Image (Base) nano-banana
Create images (high quality) Create Text-to-Image (Pro) nano-banana-pro
Create images (V2) Create Text-to-Image (V2) nano-banana-2
Edit/modify existing images Edit Image nano-banana-edit
Check text-to-image status Get Text-to-Image Status -
Check edit status Get Edit Status -

Create Text-to-Image (Base)

Create an text-to-image task using the base model:

curl -X POST "https://runapi.ai/api/v1/nano_banana/text_to_image" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "nano-banana",
    "callback_url": "https://your-domain.com/api/callback",
    "prompt": "A surreal painting of a giant banana floating in space, stars and galaxies in the background, vibrant colors, digital art",
    "output_format": "png",
    "aspect_ratio": "1:1",
    "reference_image_urls": []
  }'
require 'net/http'
require 'uri'
require 'json'

uri = URI('https://runapi.ai/api/v1/nano_banana/text_to_image')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
request['Content-Type'] = 'application/json'
request.body = {
  model: 'nano-banana',
  callback_url: 'https://your-domain.com/api/callback',
  prompt: 'A surreal painting of a giant banana floating in space, stars and galaxies in the background, vibrant colors, digital art',
  output_format: 'png',
  aspect_ratio: '1:1',
  reference_image_urls: []
}.to_json

response = http.request(request)
puts response.body
import requests

url = 'https://runapi.ai/api/v1/nano_banana/text_to_image'
headers = {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
}
data = {
    'model': 'nano-banana',
    'callback_url': 'https://your-domain.com/api/callback',
    'prompt': 'A surreal painting of a giant banana floating in space, stars and galaxies in the background, vibrant colors, digital art',
    'output_format': 'png',
    'aspect_ratio': '1:1',
    'reference_image_urls': []
}

response = requests.post(url, headers=headers, json=data)
print(response.json())
const data = {
  model: 'nano-banana',
  callback_url: 'https://your-domain.com/api/callback',
  prompt: 'A surreal painting of a giant banana floating in space, stars and galaxies in the background, vibrant colors, digital art',
  output_format: 'png',
  aspect_ratio: '1:1',
  reference_image_urls: []
};

fetch('https://runapi.ai/api/v1/nano_banana/text_to_image', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => console.log(data));

HTTP 202 - Task accepted:

{
  "id": "281e5b0*********************f39b9",
  "status": "processing"
}

Create a new text-to-image task using the base Nano Banana model. The request is processed asynchronously.

HTTP Request

POST https://runapi.ai/api/v1/nano_banana/text_to_image

Request Parameters

Parameter Type Required Description
model string Yes Model to use: nano-banana for base version
prompt string Yes Text description of the desired image (max 5000 characters)
callback_url string No URL for completion callback
output_format string No Output format: png, jpg (default: png)
aspect_ratio string No Output aspect ratio: 1:1, 9:16, 16:9, 3:4, 4:3, 3:2, 2:3, 5:4, 4:5, 21:9, auto (default: 1:1)
reference_image_urls array No Array of reference image URLs (max 8 images, 30MB each)

Response

Returns a task ID for checking text-to-image status:

Field Type Description
id string Unique task identifier

Callback Format

If callback_url is provided, a POST request will be sent when generation completes.

Success Response: - Includes status: "completed" - Contains images array with generated image objects

Failed Response: - Includes status: "failed" - Contains error message describing the failure reason

Success callback example:

{
  "id": "281e5b0*********************f39b9",
  "status": "completed",
  "images": [
    {
      "url": "https://file.runapi.ai/generated/image1.png"
    }
  ]
}

Failed callback example:

{
  "id": "281e5b0*********************f39b9",
  "status": "failed",
  "error": "Generation failed due to content policy violation"
}

Create Text-to-Image (Pro)

Create an text-to-image task using the Pro model:

curl -X POST "https://runapi.ai/api/v1/nano_banana/text_to_image" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "nano-banana-pro",
    "callback_url": "https://your-domain.com/api/callback",
    "prompt": "A serene mountain landscape at sunset with vibrant orange and purple skies",
    "aspect_ratio": "16:9",
    "output_resolution": "4k",
    "output_format": "png",
    "reference_image_urls": []
  }'
require 'net/http'
require 'uri'
require 'json'

uri = URI('https://runapi.ai/api/v1/nano_banana/text_to_image')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
request['Content-Type'] = 'application/json'
request.body = {
  model: 'nano-banana-pro',
  callback_url: 'https://your-domain.com/api/callback',
  prompt: 'A serene mountain landscape at sunset with vibrant orange and purple skies',
  aspect_ratio: '16:9',
  output_resolution: '4k',
  output_format: 'png',
  reference_image_urls: []
}.to_json

response = http.request(request)
puts response.body
import requests

url = 'https://runapi.ai/api/v1/nano_banana/text_to_image'
headers = {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
}
data = {
    'model': 'nano-banana-pro',
    'callback_url': 'https://your-domain.com/api/callback',
    'prompt': 'A serene mountain landscape at sunset with vibrant orange and purple skies',
    'aspect_ratio': '16:9',
    'output_resolution': '4k',
    'output_format': 'png',
    'reference_image_urls': []
}

response = requests.post(url, headers=headers, json=data)
print(response.json())
const data = {
  model: 'nano-banana-pro',
  callback_url: 'https://your-domain.com/api/callback',
  prompt: 'A serene mountain landscape at sunset with vibrant orange and purple skies',
  aspect_ratio: '16:9',
  output_resolution: '4k',
  output_format: 'png',
  reference_image_urls: []
};

fetch('https://runapi.ai/api/v1/nano_banana/text_to_image', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => console.log(data));

HTTP 202 - Task accepted:

{
  "id": "281e5b0*********************f39b9",
  "status": "processing"
}

Create a new text-to-image task using the Pro Nano Banana model with higher quality and more features.

HTTP Request

POST https://runapi.ai/api/v1/nano_banana/text_to_image

Request Parameters

Parameter Type Required Description
model string Yes Model to use: nano-banana-pro for Pro version
prompt string Yes Text description of the desired image (max 5000 characters)
callback_url string No URL for completion callback
aspect_ratio string No Image aspect ratio: 1:1, 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:9, auto (default: 1:1)
output_resolution string No Image output resolution: 1k, 2k, 4k (default: 1k)
output_format string No Output format: png, jpg (default: png)
reference_image_urls array No Array of reference image URLs (max 8 images, 30MB each)

Response

Returns a task ID for checking text-to-image status:

Field Type Description
id string Unique task identifier

Callback Format

If callback_url is provided, a POST request will be sent when generation completes.

Success Response: - Includes status: "completed" - Contains images array with generated image objects

Failed Response: - Includes status: "failed" - Contains error message describing the failure reason

Success callback example:

{
  "id": "281e5b0*********************f39b9",
  "status": "completed",
  "images": [
    {
      "url": "https://file.runapi.ai/generated/image1.png"
    }
  ]
}

Failed callback example:

{
  "id": "281e5b0*********************f39b9",
  "status": "failed",
  "error": "Generation failed due to content policy violation"
}

Create Text-to-Image (V2)

Create an text-to-image task using the V2 model:

curl -X POST "https://runapi.ai/api/v1/nano_banana/text_to_image" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "nano-banana-2",
    "callback_url": "https://your-domain.com/api/callback",
    "prompt": "Comic poster: cool banana hero in shades leaps from sci-fi pad. Six panels showcasing 4K landscapes, multilingual text, holograms, camera controls, frame ratios, and consistent banana poses.",
    "aspect_ratio": "auto",
    "output_resolution": "2k",
    "output_format": "jpg",
    "reference_image_urls": []
  }'
require 'net/http'
require 'uri'
require 'json'

uri = URI('https://runapi.ai/api/v1/nano_banana/text_to_image')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
request['Content-Type'] = 'application/json'
request.body = {
  model: 'nano-banana-2',
  callback_url: 'https://your-domain.com/api/callback',
  prompt: 'Comic poster: cool banana hero in shades leaps from sci-fi pad.',
  aspect_ratio: 'auto',
  output_resolution: '2k',
  output_format: 'jpg',
  reference_image_urls: []
}.to_json

response = http.request(request)
puts response.body
import requests

url = 'https://runapi.ai/api/v1/nano_banana/text_to_image'
headers = {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
}
data = {
    'model': 'nano-banana-2',
    'callback_url': 'https://your-domain.com/api/callback',
    'prompt': 'Comic poster: cool banana hero in shades leaps from sci-fi pad.',
    'aspect_ratio': 'auto',
    'output_resolution': '2k',
    'output_format': 'jpg',
    'reference_image_urls': []
}

response = requests.post(url, headers=headers, json=data)
print(response.json())
const data = {
  model: 'nano-banana-2',
  callback_url: 'https://your-domain.com/api/callback',
  prompt: 'Comic poster: cool banana hero in shades leaps from sci-fi pad.',
  aspect_ratio: 'auto',
  output_resolution: '2k',
  output_format: 'jpg',
  reference_image_urls: []
};

fetch('https://runapi.ai/api/v1/nano_banana/text_to_image', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => console.log(data));

HTTP 202 - Task accepted:

{
  "id": "281e5b0*********************f39b9",
  "status": "processing"
}

Create a new text-to-image task using the Nano Banana V2 model. V2 accepts longer prompts, more reference images, and a wider range of aspect ratios than the Base and Pro variants.

HTTP Request

POST https://runapi.ai/api/v1/nano_banana/text_to_image

Request Parameters

Parameter Type Required Description
model string Yes Model to use: nano-banana-2
prompt string Yes Text description of the desired image (max 20,000 characters)
callback_url string No URL for completion callback
aspect_ratio string No Aspect ratio: 1:1, 1:4, 1:8, 2:3, 3:2, 3:4, 4:1, 4:3, 4:5, 5:4, 8:1, 9:16, 16:9, 21:9, auto (default: auto)
output_resolution string No Image output resolution: 1k, 2k, 4k (default: 1k)
output_format string No Output format: png, jpg (default: jpg)
reference_image_urls array No Array of reference image URLs (max 14 images, jpeg/png/webp, 30MB each)

Pricing

Nano Banana 2 pricing

Imagen 4

Imagen 4 creates images from text prompts and supports pro remix image tasks.

Model Mode Pricing
imagen-4 Text-to-image Pricing
imagen-4-fast Text-to-image Pricing
imagen-4-ultra Text-to-image Pricing
imagen-4-pro-remix-image Pro remix image Pricing

Create Imagen 4 Text-to-Image

curl -X POST "https://runapi.ai/api/v1/imagen_4/text_to_image" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"model":"imagen-4-fast","prompt":"A warm editorial photo of a glass studio","aspect_ratio":"16:9"}'
const response = await fetch('https://runapi.ai/api/v1/imagen_4/text_to_image', {
  method: 'POST',
  headers: { Authorization: 'Bearer YOUR_API_TOKEN', 'Content-Type': 'application/json' },
  body: JSON.stringify({ model: 'imagen-4-fast', prompt: 'A warm editorial photo of a glass studio', aspect_ratio: '16:9' })
});
client = RunApi::Imagen4::Client.new(api_key: 'YOUR_API_TOKEN')
task = client.text_to_image.create(model: 'imagen-4-fast', prompt: 'A warm editorial photo of a glass studio', aspect_ratio: '16:9')

Response:

{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "processing"
}

Create a new Imagen 4 text-to-image task.

Parameters

Parameter Type Required Description
model string Yes imagen-4, imagen-4-fast, or imagen-4-ultra
prompt string Yes Text prompt; up to 5000 characters
negative_prompt string No Content to discourage for Imagen 4 text-to-image models
aspect_ratio string No Output aspect ratio; 1:1, 16:9, 9:16, 3:4, or 4:3
output_count number No imagen-4-fast image count: 1, 2, 3, or 4
seed number No Reproducible image seed
callback_url string No Webhook URL notified when the task finishes

Create Pro Remix Image

curl -X POST "https://runapi.ai/api/v1/imagen_4/remix_image" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"model":"imagen-4-pro-remix-image","prompt":"Restyle the reference image as a clean editorial poster","source_image_urls":["https://upload.wikimedia.org/wikipedia/commons/a/a9/Example.jpg"],"aspect_ratio":"auto","output_resolution":"2k","output_format":"png"}'

Create a prompt-guided remix image task.

Parameters

Parameter Type Required Description
model string Yes imagen-4-pro-remix-image
prompt string Yes Text prompt; up to 10000 characters
source_image_urls array Yes Public image URLs, up to 8 images
aspect_ratio string No Output aspect ratio; 1:1, 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:9, or auto
output_resolution string No Output resolution: 1k, 2k, or 4k
output_format string No Output format: png or jpg
callback_url string No Webhook URL notified when the task finishes

Get Imagen 4 Text-to-Image

curl "https://runapi.ai/api/v1/imagen_4/text_to_image/TASK_ID" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Completed response:

{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "completed",
  "images": [
    {
      "url": "https://file.runapi.ai/generated/image.png"
    }
  ]
}

Flux Kontext

Flux Kontext is an advanced image generation and editing model from Black Forest Labs. It supports prompt-only generation and source-image editing through one text-to-image endpoint.

Models

Model Type Pricing
flux-kontext-pro Standard quality Pricing
flux-kontext-max Enhanced quality Pricing

Flux Kontext Endpoints

Task Endpoint Method
Create text-to-image Create Text-to-Image POST
Check status Get Text-to-Image Status GET

Create Text-to-Image

Text-to-image generation:

curl -X POST "https://runapi.ai/api/v1/flux_kontext/text_to_image" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "flux-kontext-pro",
    "prompt": "A futuristic cityscape at sunset with flying cars and neon lights",
    "aspect_ratio": "16:9",
    "output_format": "png"
  }'
require 'net/http'
require 'uri'
require 'json'

uri = URI('https://runapi.ai/api/v1/flux_kontext/text_to_image')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
request['Content-Type'] = 'application/json'
request.body = {
  model: 'flux-kontext-pro',
  prompt: 'A futuristic cityscape at sunset with flying cars and neon lights',
  aspect_ratio: '16:9',
  output_format: 'png'
}.to_json

response = http.request(request)
puts response.body
import requests

url = 'https://runapi.ai/api/v1/flux_kontext/text_to_image'
headers = {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
}
data = {
    'model': 'flux-kontext-pro',
    'prompt': 'A futuristic cityscape at sunset with flying cars and neon lights',
    'aspect_ratio': '16:9',
    'output_format': 'png'
}

response = requests.post(url, headers=headers, json=data)
print(response.json())
const data = {
  model: 'flux-kontext-pro',
  prompt: 'A futuristic cityscape at sunset with flying cars and neon lights',
  aspect_ratio: '16:9',
  output_format: 'png'
};

fetch('https://runapi.ai/api/v1/flux_kontext/text_to_image', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => console.log(data));

Source-image editing:

curl -X POST "https://runapi.ai/api/v1/flux_kontext/text_to_image" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "flux-kontext-pro",
    "prompt": "Change the background to a tropical beach",
    "source_image_url": "https://cdn.runapi.ai/public/samples/image.jpg",
    "safety_tolerance": 2
  }'
require 'net/http'
require 'uri'
require 'json'

uri = URI('https://runapi.ai/api/v1/flux_kontext/text_to_image')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
request['Content-Type'] = 'application/json'
request.body = {
  model: 'flux-kontext-pro',
  prompt: 'Change the background to a tropical beach',
  source_image_url: 'https://cdn.runapi.ai/public/samples/image.jpg',
  safety_tolerance: 2
}.to_json

response = http.request(request)
puts response.body
import requests

url = 'https://runapi.ai/api/v1/flux_kontext/text_to_image'
headers = {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
}
data = {
    'model': 'flux-kontext-pro',
    'prompt': 'Change the background to a tropical beach',
    'source_image_url': 'https://cdn.runapi.ai/public/samples/image.jpg',
    'safety_tolerance': 2
}

response = requests.post(url, headers=headers, json=data)
print(response.json())
const data = {
  model: 'flux-kontext-pro',
  prompt: 'Change the background to a tropical beach',
  source_image_url: 'https://cdn.runapi.ai/public/samples/image.jpg',
  safety_tolerance: 2
};

fetch('https://runapi.ai/api/v1/flux_kontext/text_to_image', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => console.log(data));

HTTP 202 - Task accepted:

{
  "id": "281e5b0*********************f39b9",
  "status": "processing"
}

Create a new image generation or editing task. When source_image_url is provided, the model edits that source image; otherwise it generates from text.

HTTP Request

POST https://runapi.ai/api/v1/flux_kontext/text_to_image

Request Parameters

Parameter Type Required Description
model string Yes Model to use: flux-kontext-pro or flux-kontext-max
prompt string Yes Text description of the desired image or edit
aspect_ratio string No Output aspect ratio: 21:9, 16:9, 4:3, 1:1, 3:4, 9:16 (default: 1:1)
output_format string No Output format: jpeg, png (default: jpeg)
source_image_url string No Source image URL for editing mode
enable_translation boolean No Auto-translate non-English prompts
enable_prompt_expansion boolean No Expand prompt with more detail
safety_tolerance integer No Content safety level: 0-6 for generation, 0-2 for editing (lower is stricter)
callback_url string No URL for completion callback
watermark string No Watermark identifier for the generated image

Response

Returns a task ID for checking text-to-image status:

Field Type Description
id string Unique task identifier
status string Initial status: processing

Callback Format

If callback_url is provided, a POST request will be sent when generation completes.

Success Response: - Includes status: "completed" - Contains images array with generated image URLs

Failed Response: - Includes status: "failed" - Contains error message describing the failure reason

Success callback example:

{
  "id": "281e5b0*********************f39b9",
  "status": "completed",
  "images": [
    {
      "url": "https://file.runapi.ai/generated/image1.png",
      "origin_url": "https://file.runapi.ai/origin/image1.png"
    }
  ]
}

Failed callback example:

{
  "id": "281e5b0*********************f39b9",
  "status": "failed",
  "error": "Generation failed due to content policy violation"
}

Get Text-to-Image Status

Poll for generation results:

curl "https://runapi.ai/api/v1/flux_kontext/text_to_image/281e5b0f39b9" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
require 'net/http'
require 'uri'

task_id = '281e5b0f39b9'
uri = URI("https://runapi.ai/api/v1/flux_kontext/text_to_image/#{task_id}")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'

response = http.request(request)
puts response.body
import requests

task_id = '281e5b0f39b9'
url = f'https://runapi.ai/api/v1/flux_kontext/text_to_image/{task_id}'
headers = {
    'Authorization': 'Bearer YOUR_API_TOKEN'
}

response = requests.get(url, headers=headers)
print(response.json())
const taskId = '281e5b0f39b9';

fetch(`https://runapi.ai/api/v1/flux_kontext/text_to_image/${taskId}`, {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN'
  }
})
.then(response => response.json())
.then(data => console.log(data));

Processing:

{
  "id": "281e5b0*********************f39b9",
  "status": "processing"
}

Completed:

{
  "id": "281e5b0*********************f39b9",
  "status": "completed",
  "images": [
    {
      "url": "https://file.runapi.ai/generated/image1.png",
      "origin_url": "https://file.runapi.ai/origin/image1.png"
    }
  ]
}

Failed:

{
  "id": "281e5b0*********************f39b9",
  "status": "failed",
  "error": "Generation failed due to content policy violation"
}

Retrieve the status and results of an text-to-image task.

HTTP Request

GET https://runapi.ai/api/v1/flux_kontext/text_to_image/:id

URL Parameters

Parameter Description
id The ID of the task returned from the create request

Response Fields

Field Type Description
id string Unique task identifier
status string Task status: processing, completed, failed
images array Array of image objects (only present when status is completed)
images[].url string CDN URL of the generated image
images[].origin_url string Original high-resolution URL (valid for 10 minutes)
error string Error message (only present when status is failed)

Status Values

Flux 2

Flux 2 provides Black Forest Labs image generation through separate text-to-image and remix-image endpoints. Use text-to-image for prompt-only generation, and remix-image when one or more source images should guide the result.

Models

Model Endpoint
flux-2-pro-text-to-image Text-to-image
flux-2-flex-text-to-image Text-to-image
flux-2-pro-remix-image Remix image
flux-2-flex-remix-image Remix image

Flux 2 Endpoints

Task Endpoint Method
Create text-to-image task Create Text-to-Image POST
Check text-to-image task status Get Text-to-Image Status GET
Create remix-image task Create Remix Image POST
Check remix-image task status Get Remix Image Status GET

Create Text-to-Image

Text-to-image request:

curl -X POST "https://runapi.ai/api/v1/flux_2/text_to_image" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "flux-2-pro-text-to-image",
    "prompt": "A photorealistic portrait of an astronaut floating in space with Earth in the background",
    "aspect_ratio": "16:9",
    "output_resolution": "2k"
  }'
require 'net/http'
require 'uri'
require 'json'

uri = URI('https://runapi.ai/api/v1/flux_2/text_to_image')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
request['Content-Type'] = 'application/json'
request.body = {
  model: 'flux-2-pro-text-to-image',
  prompt: 'A photorealistic portrait of an astronaut floating in space with Earth in the background',
  aspect_ratio: '16:9',
  output_resolution: '2k'
}.to_json

response = http.request(request)
puts response.body
import requests

url = 'https://runapi.ai/api/v1/flux_2/text_to_image'
headers = {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
}
data = {
    'model': 'flux-2-pro-text-to-image',
    'prompt': 'A photorealistic portrait of an astronaut floating in space with Earth in the background',
    'aspect_ratio': '16:9',
    'output_resolution': '2k'
}

response = requests.post(url, headers=headers, json=data)
print(response.json())
const data = {
  model: 'flux-2-pro-text-to-image',
  prompt: 'A photorealistic portrait of an astronaut floating in space with Earth in the background',
  aspect_ratio: '16:9',
  output_resolution: '2k'
};

fetch('https://runapi.ai/api/v1/flux_2/text_to_image', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => console.log(data));

HTTP 202 - Task accepted:

{
  "id": "281e5b0*********************f39b9",
  "status": "processing"
}

Create a new text-to-image task from a prompt.

HTTP Request

POST https://runapi.ai/api/v1/flux_2/text_to_image

Request Parameters

Parameter Type Required Description
model string Yes flux-2-pro-text-to-image or flux-2-flex-text-to-image
prompt string Yes Text description of the desired image (3-5000 characters)
aspect_ratio string No 1:1, 4:3, 3:4, 16:9, 9:16, 3:2, or 2:3
output_resolution string No Output image resolution: 1k or 2k
enable_safety_checker boolean No Content safety check toggle
callback_url string No URL for completion callback

Response

Returns a task ID for checking task status:

Field Type Description
id string Unique task identifier
status string Initial status: processing

Get Text-to-Image Status

Poll for task results:

curl "https://runapi.ai/api/v1/flux_2/text_to_image/281e5b0f39b9" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
require 'net/http'
require 'uri'

task_id = '281e5b0f39b9'
uri = URI("https://runapi.ai/api/v1/flux_2/text_to_image/#{task_id}")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'

response = http.request(request)
puts response.body
import requests

task_id = '281e5b0f39b9'
url = f'https://runapi.ai/api/v1/flux_2/text_to_image/{task_id}'
headers = {
    'Authorization': 'Bearer YOUR_API_TOKEN'
}

response = requests.get(url, headers=headers)
print(response.json())
const taskId = '281e5b0f39b9';

fetch(`https://runapi.ai/api/v1/flux_2/text_to_image/${taskId}`, {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN'
  }
})
.then(response => response.json())
.then(data => console.log(data));

Retrieve the status and results of a text-to-image task.

HTTP Request

GET https://runapi.ai/api/v1/flux_2/text_to_image/:id

Create Remix Image

Remix-image request:

curl -X POST "https://runapi.ai/api/v1/flux_2/remix_image" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "flux-2-pro-remix-image",
    "prompt": "Transform this photo into an oil painting style with warm tones",
    "source_image_urls": [
      "https://cdn.runapi.ai/public/samples/image.jpg"
    ],
    "aspect_ratio": "auto"
  }'
require 'net/http'
require 'uri'
require 'json'

uri = URI('https://runapi.ai/api/v1/flux_2/remix_image')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
request['Content-Type'] = 'application/json'
request.body = {
  model: 'flux-2-pro-remix-image',
  prompt: 'Transform this photo into an oil painting style with warm tones',
  source_image_urls: [
    'https://cdn.runapi.ai/public/samples/image.jpg'
  ],
  aspect_ratio: 'auto'
}.to_json

response = http.request(request)
puts response.body
import requests

url = 'https://runapi.ai/api/v1/flux_2/remix_image'
headers = {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
}
data = {
    'model': 'flux-2-pro-remix-image',
    'prompt': 'Transform this photo into an oil painting style with warm tones',
    'source_image_urls': [
        'https://cdn.runapi.ai/public/samples/image.jpg'
    ],
    'aspect_ratio': 'auto'
}

response = requests.post(url, headers=headers, json=data)
print(response.json())
const data = {
  model: 'flux-2-pro-remix-image',
  prompt: 'Transform this photo into an oil painting style with warm tones',
  source_image_urls: [
    'https://cdn.runapi.ai/public/samples/image.jpg'
  ],
  aspect_ratio: 'auto'
};

fetch('https://runapi.ai/api/v1/flux_2/remix_image', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => console.log(data));

Create a prompt-guided remix task from source images.

HTTP Request

POST https://runapi.ai/api/v1/flux_2/remix_image

Request Parameters

Parameter Type Required Description
model string Yes flux-2-pro-remix-image or flux-2-flex-remix-image
prompt string Yes Text instructions for the remix (3-5000 characters)
source_image_urls array Yes Source image URLs (1-8 images)
aspect_ratio string No 1:1, 4:3, 3:4, 16:9, 9:16, 3:2, 2:3, or auto
output_resolution string No Output image resolution: 1k or 2k
enable_safety_checker boolean No Content safety check toggle
callback_url string No URL for completion callback

Get Remix Image Status

Poll for remix results:

curl "https://runapi.ai/api/v1/flux_2/remix_image/281e5b0f39b9" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
require 'net/http'
require 'uri'

task_id = '281e5b0f39b9'
uri = URI("https://runapi.ai/api/v1/flux_2/remix_image/#{task_id}")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'

response = http.request(request)
puts response.body
import requests

task_id = '281e5b0f39b9'
url = f'https://runapi.ai/api/v1/flux_2/remix_image/{task_id}'
headers = {
    'Authorization': 'Bearer YOUR_API_TOKEN'
}

response = requests.get(url, headers=headers)
print(response.json())
const taskId = '281e5b0f39b9';

fetch(`https://runapi.ai/api/v1/flux_2/remix_image/${taskId}`, {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN'
  }
})
.then(response => response.json())
.then(data => console.log(data));

Retrieve the status and results of a remix-image task.

HTTP Request

GET https://runapi.ai/api/v1/flux_2/remix_image/:id

Response Fields

Field Type Description
id string Unique task identifier
status string Task status: processing, completed, failed
images array Array of image objects (only present when status is completed)
images[].url string CDN URL of the generated image
error string Error message (only present when status is failed)

Qwen 2

Qwen 2 supports text-to-image creation, prompt-guided image remixing, and prompt-guided image editing. All tasks are asynchronous and return a task ID that can be polled or delivered by webhook.

Models

Model Capability Pricing
qwen-2-text-to-image Text-to-image Pricing
qwen-2-remix-image Image remix Pricing
qwen-2-edit-image Edit image Pricing

Qwen 2 Endpoints

Operation Endpoint
Create text-to-image task POST /api/v1/qwen_2/text_to_image
Get text-to-image task GET /api/v1/qwen_2/text_to_image/:id
Create remix-image task POST /api/v1/qwen_2/remix_image
Get remix-image task GET /api/v1/qwen_2/remix_image/:id
Create edit-image task POST /api/v1/qwen_2/edit_image
Get edit-image task GET /api/v1/qwen_2/edit_image/:id

Create Text-to-Image

curl -X POST "https://runapi.ai/api/v1/qwen_2/text_to_image" \
  -H "Authorization: Bearer $RUNAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen-2-text-to-image",
    "prompt": "A cinematic glass city at sunrise, high detail",
    "aspect_ratio": "16:9",
    "output_format": "png"
  }'

POST https://runapi.ai/api/v1/qwen_2/text_to_image

Parameter Type Required Description
model string Yes Must be qwen-2-text-to-image
prompt string Yes Text prompt, up to 800 characters
aspect_ratio string No 1:1, 3:4, 4:3, 9:16, or 16:9; default 16:9
seed integer No Seed for reproducible results
output_format string No png or jpeg; default png
enable_safety_checker boolean No Content safety check toggle
callback_url string No Webhook URL for completion notification

Create Remix Image

curl -X POST "https://runapi.ai/api/v1/qwen_2/remix_image" \
  -H "Authorization: Bearer $RUNAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen-2-remix-image",
    "prompt": "Turn this scene into a soft watercolor illustration",
    "source_image_url": "https://cdn.runapi.ai/public/samples/image.jpg",
    "strength": 0.8,
    "output_format": "png"
  }'

POST https://runapi.ai/api/v1/qwen_2/remix_image

Parameter Type Required Description
model string Yes Must be qwen-2-remix-image
prompt string Yes Remix prompt, up to 5000 characters
source_image_url string Yes Source image URL; accepts JPEG, PNG, and WebP up to 10 MB
strength number No Denoising strength from 0 to 1; default 0.8
output_format string No png or jpeg; default png
acceleration string No none, regular, or high; default none
negative_prompt string No Negative prompt, up to 500 characters
seed integer No Seed for reproducible results
num_inference_steps integer No Number of inference steps from 2 to 250; default 30
guidance_scale number No Prompt adherence from 0 to 20; default 2.5
enable_safety_checker boolean No Content safety check toggle
callback_url string No Webhook URL for completion notification

Create Edit Image

curl -X POST "https://runapi.ai/api/v1/qwen_2/edit_image" \
  -H "Authorization: Bearer $RUNAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen-2-edit-image",
    "prompt": "Replace the background with a neon-lit city skyline",
    "source_image_url": "https://cdn.runapi.ai/public/samples/image.jpg",
    "aspect_ratio": "16:9",
    "output_format": "png"
  }'

POST https://runapi.ai/api/v1/qwen_2/edit_image

Parameter Type Required Description
model string Yes Must be qwen-2-edit-image
prompt string Yes Edit instruction, up to 800 characters
source_image_url string Yes Source image URL; accepts JPEG, PNG, and WebP up to 10 MB
aspect_ratio string No 1:1, 2:3, 3:2, 3:4, 4:3, 9:16, 16:9, or 21:9
output_format string No jpeg or png; default png
seed integer No Seed for reproducible results
enable_safety_checker boolean No Content safety check toggle
callback_url string No Webhook URL for completion notification

Response

Create endpoints return 202 Accepted:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "processing"
}

Polling and webhook responses use the same shape:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "images": [
    {
      "url": "https://file.runapi.ai/tools/example/result.png"
    }
  ]
}

Recraft

Recraft on RunAPI provides two image post-processing endpoints: image upscale and background removal.

Models

Model Type Credits
recraft-crisp-upscale Image upscale 1
recraft-remove-background Background removal 1

Recraft Endpoints

Task Endpoint Method
Upscale image Upscale Image POST
Remove background Remove Background POST
Check task status Get Recraft Task Status GET

Upscale Recraft Image

Upscale an image:

curl -X POST "https://runapi.ai/api/v1/recraft/upscale_image" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "recraft-crisp-upscale",
    "source_image_url": "https://cdn.runapi.ai/public/samples/upscale.jpg"
  }'
require 'net/http'
require 'uri'
require 'json'

uri = URI('https://runapi.ai/api/v1/recraft/upscale_image')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
request['Content-Type'] = 'application/json'
request.body = {
  model: 'recraft-crisp-upscale',
  source_image_url: 'https://cdn.runapi.ai/public/samples/upscale.jpg'
}.to_json

response = http.request(request)
puts response.body
import requests

response = requests.post(
    'https://runapi.ai/api/v1/recraft/upscale_image',
    headers={'Authorization': 'Bearer YOUR_API_TOKEN'},
    json={
        'model': 'recraft-crisp-upscale',
        'source_image_url': 'https://cdn.runapi.ai/public/samples/upscale.jpg'
    }
)
print(response.json())
fetch('https://runapi.ai/api/v1/recraft/upscale_image', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    model: 'recraft-crisp-upscale',
    source_image_url: 'https://cdn.runapi.ai/public/samples/upscale.jpg'
  })
})
.then(res => res.json())
.then(data => console.log(data));

HTTP 202 - Task accepted:

{
  "id": "281e5b0*********************f39b9",
  "status": "processing"
}

HTTP Request

POST https://runapi.ai/api/v1/recraft/upscale_image

Request Parameters

Parameter Type Required Description
model string Yes Must be recraft-crisp-upscale
source_image_url string Yes Source image URL
callback_url string No URL for completion callback

Remove Recraft Background

Remove an image background:

curl -X POST "https://runapi.ai/api/v1/recraft/remove_background" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "recraft-remove-background",
    "source_image_url": "https://cdn.runapi.ai/public/samples/remove-bg.jpg"
  }'
require 'net/http'
require 'uri'
require 'json'

uri = URI('https://runapi.ai/api/v1/recraft/remove_background')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
request['Content-Type'] = 'application/json'
request.body = {
  model: 'recraft-remove-background',
  source_image_url: 'https://cdn.runapi.ai/public/samples/remove-bg.jpg'
}.to_json

response = http.request(request)
puts response.body
import requests

response = requests.post(
    'https://runapi.ai/api/v1/recraft/remove_background',
    headers={'Authorization': 'Bearer YOUR_API_TOKEN'},
    json={
        'model': 'recraft-remove-background',
        'source_image_url': 'https://cdn.runapi.ai/public/samples/remove-bg.jpg'
    }
)
print(response.json())
fetch('https://runapi.ai/api/v1/recraft/remove_background', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    model: 'recraft-remove-background',
    source_image_url: 'https://cdn.runapi.ai/public/samples/remove-bg.jpg'
  })
})
.then(res => res.json())
.then(data => console.log(data));

HTTP 202 - Task accepted:

{
  "id": "281e5b0*********************f39b9",
  "status": "processing"
}

HTTP Request

POST https://runapi.ai/api/v1/recraft/remove_background

Request Parameters

Parameter Type Required Description
model string Yes Must be recraft-remove-background
source_image_url string Yes Source image URL
callback_url string No URL for completion callback

Get Recraft Task Status

Use the matching GET endpoint for the task you created:

Create Endpoint Status Endpoint
POST /api/v1/recraft/upscale_image GET /api/v1/recraft/upscale_image/:id
POST /api/v1/recraft/remove_background GET /api/v1/recraft/remove_background/:id

Poll an upscale task:

curl "https://runapi.ai/api/v1/recraft/upscale_image/281e5b0f39b9" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
{
  "id": "281e5b0*********************f39b9",
  "status": "completed",
  "images": [
    {
      "url": "https://file.runapi.ai/recraft/result.png"
    }
  ]
}

Response Fields

Field Type Description
id string Unique task identifier
status string Task status: processing, completed, failed
images array Result image objects when the task is completed
images[].url string CDN URL of the processed image
error string Error message when the task fails

Z-Image

Z-Image generates images from text prompts. It supports five aspect ratios and asynchronous callbacks.

Models

Model Type Credits
z-image Text-to-image 1

Z-Image Endpoints

Task Endpoint Method
Create text-to-image Create Text-to-Image POST
Check status Get Text-to-Image Status GET

Create Text-to-Image

Create a text-to-image task:

curl -X POST "https://runapi.ai/api/v1/z_image/text_to_image" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "z-image",
    "prompt": "Generate a photorealistic image of a cafe terrace in Paris on a crisp spring morning",
    "aspect_ratio": "1:1",
    "enable_safety_checker": true
  }'
require 'net/http'
require 'uri'
require 'json'

uri = URI('https://runapi.ai/api/v1/z_image/text_to_image')
request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
request['Content-Type'] = 'application/json'
request.body = {
  model: 'z-image',
  prompt: 'Generate a photorealistic image of a cafe terrace in Paris on a crisp spring morning',
  aspect_ratio: '1:1',
  enable_safety_checker: true
}.to_json

response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(request) }
puts response.body
import requests

response = requests.post(
    'https://runapi.ai/api/v1/z_image/text_to_image',
    headers={'Authorization': 'Bearer YOUR_API_TOKEN'},
    json={
        'model': 'z-image',
        'prompt': 'Generate a photorealistic image of a cafe terrace in Paris on a crisp spring morning',
        'aspect_ratio': '1:1',
        'enable_safety_checker': True
    }
)
print(response.json())
fetch('https://runapi.ai/api/v1/z_image/text_to_image', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    model: 'z-image',
    prompt: 'Generate a photorealistic image of a cafe terrace in Paris on a crisp spring morning',
    aspect_ratio: '1:1',
    enable_safety_checker: true
  })
})
.then(response => response.json())
.then(data => console.log(data));

HTTP 202 - Task accepted:

{
  "id": "281e5b0*********************f39b9",
  "status": "processing"
}

HTTP Request

POST https://runapi.ai/api/v1/z_image/text_to_image

Request Parameters

Parameter Type Required Description
model string Yes Must be z-image
prompt string Yes Image description, up to 1000 characters
aspect_ratio string Yes Output aspect ratio: 1:1, 4:3, 3:4, 16:9, 9:16
enable_safety_checker boolean No Content safety check toggle
callback_url string No URL for completion callback

Response

Field Type Description
id string Unique task identifier
status string Initial status: processing

Get Text-to-Image Status

Poll for generation results:

curl "https://runapi.ai/api/v1/z_image/text_to_image/281e5b0f39b9" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

HTTP Request

GET https://runapi.ai/api/v1/z_image/text_to_image/{id}

Response

Completed tasks include generated image URLs:

{
  "id": "281e5b0*********************f39b9",
  "status": "completed",
  "images": [
    {
      "url": "https://file.runapi.ai/generated/image1.png"
    }
  ]
}

Ideogram V3

Ideogram V3 is RunAPI's Ideogram-powered image family covering text-to-image, character-guided generation, inpainting edits, remixes, and reframing.

Models

Model Type Pricing
ideogram-v3-text-to-image Text-to-image Pricing
ideogram-v3-edit Image inpaint Pricing
ideogram-v3-remix Image remix Pricing
ideogram-v3-character Character-guided text-to-image Pricing
ideogram-v3-character-edit Character-guided inpaint Pricing
ideogram-v3-character-remix Character-guided remix Pricing
ideogram-v3-reframe Image reframe Pricing

Ideogram V3 Endpoints

Task Endpoint Method
Generate image from text Create Text-to-Image POST
Get text-to-image status Get Text-to-Image Status GET
Inpaint an image Create Edit POST
Get edit status Get Edit Status GET
Remix an image Create Remix POST
Get remix status Get Remix Status GET
Reframe an image Create Reframe POST
Get reframe status Get Reframe Status GET

Create Ideogram V3 Text-to-Image

curl -X POST "https://runapi.ai/api/v1/ideogram_v3/text_to_image" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "ideogram-v3-text-to-image",
    "prompt": "A cinematic lakeside at twilight with neon reeds",
    "rendering_speed": "balanced",
    "style": "realistic",
    "aspect_ratio": "1:1"
  }'

POST https://runapi.ai/api/v1/ideogram_v3/text_to_image

Parameter Type Required Description
model string Yes Must be ideogram-v3-text-to-image
prompt string Yes Up to 5000 characters
reference_image_urls array Yes for ideogram-v3-character Character reference image URLs; only the first image is used, JPEG/PNG/WEBP, max 10 MB total
callback_url string No Webhook URL for completion notification
rendering_speed string No turbo, balanced (default), quality
style string No auto, general, realistic, design; ideogram-v3-character supports auto, realistic, fiction
enable_prompt_expansion boolean No Use MagicPrompt to expand the prompt
aspect_ratio string No 1:1, 3:4, 9:16, 4:3, 16:9
output_count number No 1, 2, 3, 4
seed integer No Seed for the random number generator
negative_prompt string No Up to 5000 characters. Exclusions

Use model: "ideogram-v3-character" on this endpoint for character-guided generation. Character requests require reference_image_urls and may use style: "fiction" plus output_count.

Response

{
  "id": "281e5b0f39b9",
  "status": "processing"
}

Get Ideogram V3 Text-to-Image Status

curl "https://runapi.ai/api/v1/ideogram_v3/text_to_image/YOUR_TASK_ID" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

GET https://runapi.ai/api/v1/ideogram_v3/text_to_image/:id

Completed response

{
  "id": "281e5b0f39b9",
  "status": "completed",
  "images": [
    { "url": "https://file.runapi.ai/ideogram/result.png" }
  ]
}

Failed response

{
  "id": "281e5b0f39b9",
  "status": "failed",
  "error": "Prompt rejected"
}

Create Ideogram V3 Edit

curl -X POST "https://runapi.ai/api/v1/ideogram_v3/edit_image" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "ideogram-v3-edit",
    "prompt": "A dog wearing a cowboy hat",
    "source_image_url": "https://cdn.runapi.ai/public/samples/image.jpg",
    "mask_url": "https://cdn.runapi.ai/public/samples/mask.png",
    "rendering_speed": "balanced"
  }'

POST https://runapi.ai/api/v1/ideogram_v3/edit_image

Parameter Type Required Description
model string Yes Must be ideogram-v3-edit
prompt string Yes Fill text for the masked area. Up to 5000 characters
source_image_url string Yes URL of the source image. JPEG/PNG/WEBP, max 10 MB
mask_url string Yes URL of the inpaint mask. Must match source dimensions
reference_image_urls array Yes for ideogram-v3-character-edit Character reference image URLs; only the first image is used, JPEG/PNG/WEBP, max 10 MB total
callback_url string No Webhook URL for completion notification
rendering_speed string No turbo, balanced (default), quality
style string No ideogram-v3-character-edit only: auto, realistic, fiction
enable_prompt_expansion boolean No Use MagicPrompt to expand the prompt
output_count number No 1, 2, 3, 4
seed integer No Seed for the random number generator

Use model: "ideogram-v3-character-edit" on this endpoint for character-guided inpainting. Character edit requests require reference_image_urls.

Response

{
  "id": "281e5b0f39b9",
  "status": "processing"
}

Get Ideogram V3 Edit Status

curl "https://runapi.ai/api/v1/ideogram_v3/edit_image/YOUR_TASK_ID" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

GET https://runapi.ai/api/v1/ideogram_v3/edit_image/:id

Response shape matches the text-to-image status endpoint.

Create Ideogram V3 Remix

curl -X POST "https://runapi.ai/api/v1/ideogram_v3/remix_image" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "ideogram-v3-remix",
    "prompt": "Change the cube into a sphere",
    "source_image_url": "https://cdn.runapi.ai/public/samples/image.jpg",
    "rendering_speed": "balanced",
    "strength": 0.8,
    "output_count": 1
  }'

POST https://runapi.ai/api/v1/ideogram_v3/remix_image

Parameter Type Required Description
model string Yes Must be ideogram-v3-remix
prompt string Yes Up to 5000 characters
source_image_url string Yes URL of the source image. JPEG/PNG/WEBP, max 10 MB
reference_image_urls array Yes for ideogram-v3-character-remix Character reference image URLs; only the first image is used, JPEG/PNG/WEBP, max 10 MB total
callback_url string No Webhook URL for completion notification
rendering_speed string No turbo, balanced (default), quality
style string No auto, general, realistic, design; ideogram-v3-character-remix supports auto, realistic, fiction
enable_prompt_expansion boolean No Use MagicPrompt to expand the prompt
aspect_ratio string No 1:1, 3:4, 9:16, 4:3, 16:9
output_count number No 1, 2, 3, 4
seed integer No Seed for the random number generator
strength number No 0.01–1 for ideogram-v3-remix; 0.1–1 for ideogram-v3-character-remix
negative_prompt string No Up to 5000 characters for ideogram-v3-remix; up to 500 for ideogram-v3-character-remix
style_reference_image_urls array No ideogram-v3-character-remix only: style reference image URLs
reference_mask_urls array No ideogram-v3-character-remix only: masks for character references; ignored without reference_image_urls

Use model: "ideogram-v3-character-remix" on this endpoint for character-guided remixing. Character remix requests require reference_image_urls.

Response

{
  "id": "281e5b0f39b9",
  "status": "processing"
}

Get Ideogram V3 Remix Status

curl "https://runapi.ai/api/v1/ideogram_v3/remix_image/YOUR_TASK_ID" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

GET https://runapi.ai/api/v1/ideogram_v3/remix_image/:id

Response shape matches the text-to-image status endpoint.

Create Ideogram V3 Reframe

curl -X POST "https://runapi.ai/api/v1/ideogram_v3/reframe_image" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "ideogram-v3-reframe",
    "source_image_url": "https://cdn.runapi.ai/public/samples/image.jpg",
    "aspect_ratio": "3:4",
    "rendering_speed": "balanced",
    "style": "auto",
    "output_count": 1
  }'

POST https://runapi.ai/api/v1/ideogram_v3/reframe_image

Parameter Type Required Description
model string Yes Must be ideogram-v3-reframe
source_image_url string Yes URL of the source image. JPEG/PNG/WEBP, max 10 MB
aspect_ratio string Yes 1:1, 3:4, 9:16, 4:3, 16:9
callback_url string No Webhook URL for completion notification
rendering_speed string No turbo, balanced (default), quality
style string No auto, general, realistic, design
output_count number No 1, 2, 3, 4
seed integer No Seed for the random number generator

Response

{
  "id": "281e5b0f39b9",
  "status": "processing"
}

Get Ideogram V3 Reframe Status

curl "https://runapi.ai/api/v1/ideogram_v3/reframe_image/YOUR_TASK_ID" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

GET https://runapi.ai/api/v1/ideogram_v3/reframe_image/:id

Response shape matches the text-to-image status endpoint.

ElevenLabs

ElevenLabs on RunAPI provides text-to-speech, multi-speaker dialogue generation, text-to-sound, speech-to-text, and isolate audio through a consistent async task interface.

ElevenLabs Endpoints

Task Endpoint Models
Create speech Create ElevenLabs Speech text-to-speech-turbo-v2.5, text-to-speech-multilingual-v2
Get speech Get ElevenLabs Speech -
Create dialogue Create ElevenLabs Dialogue text-to-dialogue-v3
Get dialogue Get ElevenLabs Dialogue -
Create text-to-sound Create ElevenLabs Text to Sound sound-effect-v2
Get text-to-sound Get ElevenLabs Text to Sound -
Create speech-to-text Create ElevenLabs Speech to Text speech-to-text
Get speech-to-text Get ElevenLabs Speech to Text -
Create isolate-audio Create ElevenLabs Isolate Audio audio-isolation
Get isolate-audio Get ElevenLabs Isolate Audio -

Create ElevenLabs Speech

curl -X POST "https://runapi.ai/api/v1/elevenlabs/text_to_speech" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "text-to-speech-turbo-v2.5",
    "text": "Hello from RunAPI",
    "voice": "EkK5I93UQWFDigLMpZcX",
    "callback_url": "https://example.com/callback"
  }'

HTTP 202

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "processing"
}

POST https://runapi.ai/api/v1/elevenlabs/text_to_speech

Parameter Type Required Description
model string Yes text-to-speech-turbo-v2.5 or text-to-speech-multilingual-v2
text string Yes Speech text, max 5000 chars
voice string Conditional Voice name or voice ID; required for multilingual, optional for turbo. Turbo defaults to EkK5I93UQWFDigLMpZcX when omitted.
callback_url string No HTTPS callback URL
stability number No 0-1
similarity_boost number No 0-1
style number No 0-1
speed number No 0.7-1.2
timestamps boolean No Return word timestamps
previous_text string No Context text before current request
next_text string No Context text after current request
language_code string No Language hint

Get ElevenLabs Speech

curl "https://runapi.ai/api/v1/elevenlabs/text_to_speech/YOUR_TASK_ID" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "audios": [
    { "url": "https://file.runapi.ai/audio.mp3" }
  ]
}

Create ElevenLabs Dialogue

curl -X POST "https://runapi.ai/api/v1/elevenlabs/text_to_dialogue" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "dialogue": [
      { "text": "Hello", "voice": "Adam" },
      { "text": "How are you?", "voice": "Brian" }
    ],
    "stability": 0.5
  }'
Parameter Type Required Description
dialogue array Yes Dialogue lines with text and voice; total text max 5000 chars
stability number No 0, 0.5, or 1
language_code string No Language hint
callback_url string No HTTPS callback URL

Get ElevenLabs Dialogue

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "audios": [
    { "url": "https://tempfile.runapi.ai/dialogue.mp3" }
  ]
}

Create ElevenLabs Text to Sound

curl -X POST "https://runapi.ai/api/v1/elevenlabs/text_to_sound" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Thunder crash and heavy rain",
    "output_format": "mp3_44100_128"
  }'
Parameter Type Required Description
text string Yes Sound effect prompt, max 5000 chars
loop boolean No Generate a looping sound
duration_seconds number No 0.5-22
prompt_influence number No 0-1
output_format string No Output codec and bitrate
callback_url string No HTTPS callback URL

Get ElevenLabs Text to Sound

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "audios": [
    { "url": "https://file.runapi.ai/text-to-sound.mp3" }
  ]
}

Create ElevenLabs Speech to Text

curl -X POST "https://runapi.ai/api/v1/elevenlabs/speech_to_text" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "source_audio_url": "https://cdn.runapi.ai/public/samples/voice.mp3",
    "diarize": true
  }'
Parameter Type Required Description
source_audio_url string Yes Source audio URL
language_code string No Language hint
tag_audio_events boolean No Tag applause, laughter, etc.
diarize boolean No Label speakers
callback_url string No HTTPS callback URL

Get ElevenLabs Speech to Text

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "text": "Hello from ElevenLabs"
}

Create ElevenLabs Isolate Audio

curl -X POST "https://runapi.ai/api/v1/elevenlabs/isolate_audio" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "source_audio_url": "https://cdn.runapi.ai/public/samples/voice.mp3"
  }'
Parameter Type Required Description
source_audio_url string Yes Source audio URL
callback_url string No HTTPS callback URL

Get ElevenLabs Isolate Audio

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "audios": [
    { "url": "https://file.runapi.ai/isolated.mp3" }
  ]
}

InfiniteTalk

InfiniteTalk on RunAPI creates lip-sync videos from a single image, a driving audio clip, and a prompt through the same async task interface used across the platform.

InfiniteTalk Endpoints

Task Endpoint Models
Create from-audio task Create InfiniteTalk From Audio infinitetalk-from-audio
Get task status Get InfiniteTalk From Audio Status -

Create InfiniteTalk From Audio

curl -X POST "https://runapi.ai/api/v1/infinitetalk/audio_to_video" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "infinitetalk-from-audio",
    "source_image_url": "https://cdn.runapi.ai/public/samples/portrait.jpg",
    "source_audio_url": "https://cdn.runapi.ai/public/samples/voice.mp3",
    "prompt": "A young woman with long dark hair talking on a podcast.",
    "output_resolution": "480p",
    "seed": 12345,
    "callback_url": "https://example.com/callback"
  }'

HTTP 202

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "processing"
}

POST https://runapi.ai/api/v1/infinitetalk/audio_to_video

Parameter Type Required Description
model string Yes Must be infinitetalk-from-audio
source_image_url string Yes Source image URL
source_audio_url string Yes Source audio URL
prompt string Yes Prompt text, max 5000 chars
output_resolution string No 480p or 720p
seed integer No Integer between 10000 and 1000000
callback_url string No HTTPS callback URL

Get InfiniteTalk From Audio Status

curl "https://runapi.ai/api/v1/infinitetalk/audio_to_video/YOUR_TASK_ID" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "videos": [
    { "url": "https://file.runapi.ai/infinitetalk/video.mp4" }
  ]
}

Gemini Omni

Gemini Omni on RunAPI creates reusable voice resources, character resources, and multimodal video tasks.

Gemini Omni Endpoints

Task Endpoint Models
Create audio voice Create Gemini Omni Audio gemini-omni-audio
Create character Create Gemini Omni Character gemini-omni-character
Text-to-video Gemini Omni Text-to-Video gemini-omni-text-to-video
Check video status Get Gemini Omni Text-to-Video Status -

Create Gemini Omni Audio

curl -X POST "https://runapi.ai/api/v1/gemini_omni/create_audio" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "audio_id": "achernar",
    "name": "Acher Narrator",
    "voice_description": "A calm, clear, and friendly male voice suitable for tech explainers and daily conversation.",
    "example_dialogue": "Hello, I am achernar"
  }'

HTTP 200

{
  "id": "a8f1c2d3e4f5",
  "audio": {
    "id": "a8f1c2d3e4f5",
    "name": "Acher Narrator"
  }
}

POST https://runapi.ai/api/v1/gemini_omni/create_audio

Parameter Type Required Description
audio_id string Yes Preset voice ID, such as achernar, achird, charon, puck, or zephyr
name string Yes Voice name, max 210 characters
voice_description string No Timbre, style, pace, and emotion description, max 20000 characters
example_dialogue string No Example line spoken by the voice, max 120 characters

Create Gemini Omni Character

curl -X POST "https://runapi.ai/api/v1/gemini_omni/create_character" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "descriptions": "A young female character with short silver hair and a futuristic utility jacket, calm, agile, and strongly cyberpunk in style.",
    "reference_image_url": "https://cdn.runapi.ai/public/samples/reference-1.jpg",
    "audio_ids": ["audio_01hx8p0demo"],
    "character_name": "Jenny"
  }'

HTTP 200

{
  "id": "b09dbf56",
  "character": {
    "id": "b09dbf56",
    "name": "Jenny",
    "images": [
      {
        "url": "https://file.runapi.ai/gemini/jenny.png"
      }
    ]
  }
}

POST https://runapi.ai/api/v1/gemini_omni/create_character

Parameter Type Required Description
descriptions string Yes Character appearance, identity, style, clothing, or personality description
reference_image_url string Yes Character reference image URL; the image must be no larger than 20MB
audio_ids array[string] No Audio IDs returned by Create Gemini Omni Audio, used as voice or persona guidance
character_name string No Character name, max 210 characters

Gemini Omni Text-to-Video

curl -X POST "https://runapi.ai/api/v1/gemini_omni/text_to_video" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Create a futuristic night city short film with a slow push-in shot as the character walks out from a neon-lit street.",
    "reference_image_urls": ["https://cdn.runapi.ai/public/samples/reference-1.jpg"],
    "audio_ids": ["audio_01hx8p0demo"],
    "character_ids": ["character_01hx8p0demo"],
    "duration_seconds": 8,
    "aspect_ratio": "16:9",
    "output_resolution": "1080p",
    "seed": 12345,
    "callback_url": "https://your-domain.com/api/callback"
  }'

HTTP 202

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "processing"
}

POST https://runapi.ai/api/v1/gemini_omni/text_to_video

Parameter Type Required Description
prompt string Yes Video prompt, max 20000 characters
reference_image_urls array[string] No Reference image URLs, max 7 images, max 20MB each
audio_ids array[string] No Audio IDs returned by Create Gemini Omni Audio, max 3
character_ids array[string] No Character IDs returned by Create Gemini Omni Character, max 3
video_list array[object] No Source video clips, max 1 clip; each clip has url, start, and ends, and uses 2 reference units
duration_seconds number Yes One of 4, 6, 8, or 10; ignored when video_list is provided
aspect_ratio string No 16:9 or 9:16
output_resolution string No 720p, 1080p, or 4k; defaults to 720p
seed integer No Integer from 0 to 2147483647
callback_url string No HTTPS callback URL for completion events

Reference inputs share a 7-unit limit: each reference image counts as 1, each video clip counts as 2, and each character ID counts as 1.

Get Gemini Omni Text-to-Video Status

curl "https://runapi.ai/api/v1/gemini_omni/text_to_video/YOUR_TASK_ID" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

HTTP 200

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "videos": [
    {
      "url": "https://file.runapi.ai/gemini-omni/output.mp4"
    }
  ]
}

GET https://runapi.ai/api/v1/gemini_omni/text_to_video/:id

Parameter Description
id Task ID returned by POST /api/v1/gemini_omni/text_to_video

If callback_url is provided when creating the task, RunAPI sends the same completed or failed response body when the task finishes.

Wan

Wan is Alibaba's state-of-the-art video and image generation model family. It supports text-to-video, image-to-video, speech-to-video, animation, image generation, reference-guided text-to-video, and video editing across multiple model versions.

Models

Model Type Pricing
wan-2.2-a14b-text-to-video-turbo Text to video Pricing
wan-2.5-text-to-video Text to video Pricing
wan-2.6-text-to-video Text to video Pricing
wan-2.7-text-to-video Text to video Pricing
wan-2.2-a14b-image-to-video-turbo Image to video Pricing
wan-2.5-image-to-video Image to video Pricing
wan-2.6-image-to-video Image to video Pricing
wan-2.6-flash-image-to-video Image to video Pricing
wan-2.7-image-to-video Image to video Pricing
wan-2.6-edit-video Video edit Pricing
wan-2.6-flash-edit-video Video edit Pricing
wan-2.2-a14b-speech-to-video-turbo Speech to video Pricing
wan-2.2-animate-move Animation Pricing
wan-2.2-animate-replace Animation Pricing
wan-2.7-image Image generation Pricing
wan-2.7-image-pro Image generation Pricing
wan-2.7-r2v R2V text to video Pricing
wan-2.7-edit-video Video edit Pricing

Wan Endpoints

Task Endpoint Method
Generate text-to-video Text to Video POST
Get text-to-video status Get Text-to-Video GET
Generate image-to-video Image to Video POST
Get image-to-video status Get Image-to-Video GET
Generate speech-to-video Speech to Video POST
Get speech-to-video status Get Speech-to-Video GET
Generate animation Animation POST
Get animation status Get Animation GET
Generate image Image Generation POST
Get image status Get Image GET
Edit video Video Edit POST
Get video edit status Get Video Edit GET

Wan Text to Video

Text-to-video generation:

curl -X POST "https://runapi.ai/api/v1/wan/text_to_video" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "wan-2.6-text-to-video",
    "prompt": "A timelapse of cherry blossoms falling in a Japanese garden",
    "output_resolution": "720p",
    "aspect_ratio": "16:9"
  }'
require 'net/http'
require 'uri'
require 'json'

uri = URI('https://runapi.ai/api/v1/wan/text_to_video')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
request['Content-Type'] = 'application/json'
request.body = {
  model: 'wan-2.6-text-to-video',
  prompt: 'A timelapse of cherry blossoms falling in a Japanese garden',
  output_resolution: '720p',
  aspect_ratio: '16:9'
}.to_json

response = http.request(request)
puts response.body
import requests

response = requests.post(
    'https://runapi.ai/api/v1/wan/text_to_video',
    headers={'Authorization': 'Bearer YOUR_API_TOKEN'},
    json={
        'model': 'wan-2.6-text-to-video',
        'prompt': 'A timelapse of cherry blossoms falling in a Japanese garden',
        'output_resolution': '720p',
        'aspect_ratio': '16:9',
    }
)
print(response.json())
fetch('https://runapi.ai/api/v1/wan/text_to_video', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    model: 'wan-2.6-text-to-video',
    prompt: 'A timelapse of cherry blossoms falling in a Japanese garden',
    output_resolution: '720p',
    aspect_ratio: '16:9'
  })
}).then(r => r.json()).then(console.log);

Response:

{
  "id": "task_abc123"
}

POST /api/v1/wan/text_to_video

Creates an asynchronous text-to-video generation task. Poll the status endpoint to retrieve the result.

Request Parameters

Parameter Type Required Description
model string Yes Model version. One of: wan-2.2-a14b-text-to-video-turbo, wan-2.5-text-to-video, wan-2.6-text-to-video, wan-2.7-text-to-video, wan-2.7-r2v
prompt string Yes Text description of the video to generate
callback_url string No Webhook URL for async completion notification
duration_seconds number No Duration in seconds. Required for wan-2.5-*
output_resolution string No Output resolution (e.g. 720p, 1080p)
aspect_ratio string No Aspect ratio: 16:9, 9:16, 1:1, 4:3, 3:4. Not applicable for wan-2.7-*
ratio string No Alternative ratio format for wan-2.7-* only
negative_prompt string No What to avoid in the video. Supported by wan-2.5-* and wan-2.7-*
reference_image_urls array No Reference image URLs for wan-2.7-r2v. At least one reference image or video URL is required
reference_video_urls array No Reference video URLs for wan-2.7-r2v. At least one reference image or video URL is required
first_frame_image_url string No First frame image URL for wan-2.7-r2v
reference_audio_url string No Reference audio URL for wan-2.7-r2v
enable_prompt_expansion boolean No Auto-expand the prompt
seed integer No Random seed for reproducibility
acceleration string No Generation speed setting. wan-2.2-* only
enable_safety_checker boolean No Content safety check toggle
watermark boolean No Add watermark to the output. wan-2.7-* only
background_audio_url string No Background audio URL. wan-2.7-text-to-video only

Wan 2.7 R2V Text to Video

Generate a prompt-led video guided by reference images/videos:

curl -X POST "https://runapi.ai/api/v1/wan/text_to_video" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "wan-2.7-r2v",
    "prompt": "A person walking through autumn leaves",
    "reference_image_urls": ["https://cdn.runapi.ai/public/samples/portrait.jpg"],
    "output_resolution": "1080p"
  }'
response = requests.post(
    'https://runapi.ai/api/v1/wan/text_to_video',
    headers={'Authorization': 'Bearer YOUR_API_TOKEN'},
    json={
        'model': 'wan-2.7-r2v',
        'prompt': 'A person walking through autumn leaves',
        'reference_image_urls': ['https://cdn.runapi.ai/public/samples/portrait.jpg'],
        'output_resolution': '1080p',
    }
)

Response

Field Type Description
id string Task ID used to poll for results

Get Wan Text to Video

Poll for status:

curl "https://runapi.ai/api/v1/wan/text_to_video/TASK_ID" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
response = Net::HTTP.get(URI("https://runapi.ai/api/v1/wan/text_to_video/TASK_ID"),
  'Authorization' => 'Bearer YOUR_API_TOKEN')
puts response
response = requests.get(
    'https://runapi.ai/api/v1/wan/text_to_video/TASK_ID',
    headers={'Authorization': 'Bearer YOUR_API_TOKEN'}
)
print(response.json())
fetch('https://runapi.ai/api/v1/wan/text_to_video/TASK_ID', {
  headers: { 'Authorization': 'Bearer YOUR_API_TOKEN' }
}).then(r => r.json()).then(console.log);

Completed response:

{
  "id": "task_abc123",
  "status": "completed",
  "videos": [
    { "url": "https://file.runapi.ai/result.mp4" }
  ]
}

GET /api/v1/wan/text_to_video/:id

Retrieves the current status of a text-to-video task.

Response

Field Type Description
id string Task ID
status string processing, completed, or failed
videos array Generated video objects with url field (when completed)
error string Error message (when failed)

Wan Image to Video

Image-to-video generation (2-6):

curl -X POST "https://runapi.ai/api/v1/wan/image_to_video" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "wan-2.6-image-to-video",
    "prompt": "The cat gently swishes its tail",
    "first_frame_image_url": "https://cdn.runapi.ai/public/samples/image-to-video.jpg",
    "output_resolution": "720p"
  }'
response = requests.post(
    'https://runapi.ai/api/v1/wan/image_to_video',
    headers={'Authorization': 'Bearer YOUR_API_TOKEN'},
    json={
        'model': 'wan-2.6-image-to-video',
        'prompt': 'The cat gently swishes its tail',
        'first_frame_image_url': 'https://cdn.runapi.ai/public/samples/image-to-video.jpg',
        'output_resolution': '720p',
    }
)
fetch('https://runapi.ai/api/v1/wan/image_to_video', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    model: 'wan-2.6-image-to-video',
    prompt: 'The cat gently swishes its tail',
    first_frame_image_url: 'https://cdn.runapi.ai/public/samples/image-to-video.jpg',
    output_resolution: '720p'
  })
}).then(r => r.json()).then(console.log);

POST /api/v1/wan/image_to_video

Creates an asynchronous image-to-video generation task.

Request Parameters

Parameter Type Required Description
model string Yes Model version. One of: wan-2.2-a14b-image-to-video-turbo, wan-2.5-image-to-video, wan-2.6-image-to-video, wan-2.6-flash-image-to-video, wan-2.7-image-to-video
prompt string Conditional Text prompt. Required for wan-2.6-* and wan-2.7-*; required for flash models
callback_url string No Webhook URL for async completion notification
first_frame_image_url string Conditional First frame source image URL. Required for wan-2.2-*, wan-2.5-*, and wan-2.6-*; optional for wan-2.7-* frame anchoring
duration_seconds number Conditional Duration in seconds. Required for wan-2.5-*
output_resolution string No Output resolution
aspect_ratio string No Aspect ratio. Supported by wan-2.2-* and wan-2.5-*
ratio string No Alternative ratio format. wan-2.7-* only
negative_prompt string No What to avoid. Supported by wan-2.5-* and wan-2.7-*
enable_prompt_expansion boolean No Auto-expand prompt
seed integer No Random seed
enable_safety_checker boolean No Content safety check toggle
watermark boolean No Add watermark. wan-2.7-* only
audio boolean No Generate audio. Flash models only
multi_shots boolean No Multi-shot mode. Flash models only
last_frame_image_url string No Last frame image URL. wan-2.7-* only
source_video_url string No Source video URL for continuation. wan-2.7-* only
driving_audio_url string No Driving audio URL. wan-2.7-* only
background_audio_url string No Background audio URL. wan-2.7-* only

Get Wan Image to Video

GET /api/v1/wan/image_to_video/:id

Same response format as Get Text-to-Video.

Wan Speech to Video

Speech-driven talking-head video:

curl -X POST "https://runapi.ai/api/v1/wan/speech_to_video" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "wan-2.2-a14b-speech-to-video-turbo",
    "source_image_url": "https://cdn.runapi.ai/public/samples/portrait.jpg",
    "source_audio_url": "https://cdn.runapi.ai/public/samples/voice.mp3"
  }'
response = requests.post(
    'https://runapi.ai/api/v1/wan/speech_to_video',
    headers={'Authorization': 'Bearer YOUR_API_TOKEN'},
    json={
        'model': 'wan-2.2-a14b-speech-to-video-turbo',
        'source_image_url': 'https://cdn.runapi.ai/public/samples/portrait.jpg',
        'source_audio_url': 'https://cdn.runapi.ai/public/samples/voice.mp3',
    }
)

POST /api/v1/wan/speech_to_video

Request Parameters

Parameter Type Required Description
model string Yes wan-2.2-a14b-speech-to-video-turbo
source_image_url string Yes Portrait source image URL
source_audio_url string Yes Driving speech audio URL
prompt string No Additional description prompt
callback_url string No Webhook URL for async completion notification
num_frames integer No Number of output frames
frames_per_second integer No Frames per second
output_resolution string No Output resolution
negative_prompt string No What to avoid
seed integer No Random seed
num_inference_steps integer No Denoising steps
guidance_scale float No Classifier-free guidance scale
shift float No Noise shift
enable_safety_checker boolean No Content safety check toggle

Get Wan Speech to Video

GET /api/v1/wan/speech_to_video/:id

Same response format as Get Text-to-Video.

Wan Animation

Animate a character using a motion reference video:

curl -X POST "https://runapi.ai/api/v1/wan/animate" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "wan-2.2-animate-move",
    "reference_video_url": "https://cdn.runapi.ai/public/samples/video.mp4",
    "source_image_url": "https://cdn.runapi.ai/public/samples/image.jpg"
  }'
response = requests.post(
    'https://runapi.ai/api/v1/wan/animate',
    headers={'Authorization': 'Bearer YOUR_API_TOKEN'},
    json={
        'model': 'wan-2.2-animate-move',
        'reference_video_url': 'https://cdn.runapi.ai/public/samples/video.mp4',
        'source_image_url': 'https://cdn.runapi.ai/public/samples/image.jpg',
    }
)

POST /api/v1/wan/animate

Request Parameters

Parameter Type Required Description
model string Yes wan-2.2-animate-move or wan-2.2-animate-replace
reference_video_url string Yes Motion reference video URL
source_image_url string Yes Character/subject image URL
callback_url string No Webhook URL for async completion notification
output_resolution string No Output resolution
enable_safety_checker boolean No Content safety check toggle

Get Wan Animation

GET /api/v1/wan/animate/:id

Same response format as Get Text-to-Video.

Wan Image Generation

Generate images from text:

curl -X POST "https://runapi.ai/api/v1/wan/text_to_image" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "wan-2.7-image",
    "prompt": "A surreal dreamscape with floating islands and waterfalls",
    "aspect_ratio": "1:8"
  }'
response = requests.post(
    'https://runapi.ai/api/v1/wan/text_to_image',
    headers={'Authorization': 'Bearer YOUR_API_TOKEN'},
    json={
        'model': 'wan-2.7-image',
        'prompt': 'A surreal dreamscape with floating islands and waterfalls',
        'aspect_ratio': '1:8',
    }
)

POST /api/v1/wan/text_to_image

Request Parameters

Parameter Type Required Description
model string Yes wan-2.7-image or wan-2.7-image-pro
prompt string Yes Text description of the image
callback_url string No Webhook URL for async completion notification
aspect_ratio string No 1:1, 16:9, 4:3, 21:9, 3:4, 9:16, 8:1, 1:8
output_resolution string No Output resolution
output_count integer No Number of images to generate
enable_sequential boolean No Sequential generation mode
thinking_mode boolean No Enhanced reasoning mode. wan-2.7-image-pro only
watermark boolean No Add watermark
seed integer No Random seed
enable_safety_checker boolean No Content safety check toggle
source_image_urls array No Source image URLs for image editing
color_palette array No Color palette constraints. Each item: { hex, ratio }
bbox_list array No Bounding box constraints

Response

Field Type Description
id string Task ID
status string processing, completed, or failed
images array Generated image objects with url field (when completed)
error string Error message (when failed)

Get Wan Image

GET /api/v1/wan/text_to_image/:id

Returns the same format as the Image Generation response above.

Wan Video Edit

Edit an existing video with a text prompt:

curl -X POST "https://runapi.ai/api/v1/wan/edit_video" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "wan-2.7-edit-video",
    "source_video_url": "https://cdn.runapi.ai/public/samples/video.mp4",
    "prompt": "Make the sky more dramatic with storm clouds"
  }'
response = requests.post(
    'https://runapi.ai/api/v1/wan/edit_video',
    headers={'Authorization': 'Bearer YOUR_API_TOKEN'},
    json={
        'model': 'wan-2.7-edit-video',
        'source_video_url': 'https://cdn.runapi.ai/public/samples/video.mp4',
        'prompt': 'Make the sky more dramatic with storm clouds',
    }
)

POST /api/v1/wan/edit_video

Request Parameters

Parameter Type Required Description
model string Yes wan-2.6-edit-video, wan-2.6-flash-edit-video, or wan-2.7-edit-video
source_video_url string Required for wan-2.7-edit-video Source video URL
source_video_urls array Required for wan-2.6-edit-video and wan-2.6-flash-edit-video Source video URLs
prompt string No Text description of the desired edit
callback_url string No Webhook URL for async completion notification
negative_prompt string No What to avoid
reference_image_url string No Reference image URL for style guidance
output_resolution string No Output resolution
aspect_ratio string No Output aspect ratio
duration_seconds number No Output duration in seconds
audio_setting string No Audio handling setting
audio boolean No Generate audio. Flash model only
multi_shots boolean No Multi-shot mode. Flash model only
enable_prompt_expansion boolean No Auto-expand the prompt
watermark boolean No Add watermark
seed integer No Random seed
enable_safety_checker boolean No Content safety check toggle

Get Wan Video Edit

GET /api/v1/wan/edit_video/:id

Same response format as Get Text-to-Video.

Luma

Luma video modification turns an existing public video into a new variation guided by a prompt. Submit the source video once, poll the task status, or provide callback_url to receive the final result asynchronously.

Endpoints

Task Endpoint Method
Create a video modification task Create Luma Video Modification POST
Check task status Get Luma Video Modification GET

Create Luma Video Modification

Create a Luma video modification task:

curl -X POST "https://runapi.ai/api/v1/luma/modify_video" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Turn the street into a rainy cyberpunk night with neon reflections",
    "source_video_url": "https://storage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4",
    "callback_url": "https://your-domain.com/api/callbacks/luma",
    "watermark": "demo-watermark"
  }'
require 'net/http'
require 'uri'
require 'json'

uri = URI('https://runapi.ai/api/v1/luma/modify_video')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
request['Content-Type'] = 'application/json'
request.body = {
  prompt: 'Turn the street into a rainy cyberpunk night with neon reflections',
  source_video_url: 'https://storage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4',
  callback_url: 'https://your-domain.com/api/callbacks/luma',
  watermark: 'demo-watermark'
}.to_json

response = http.request(request)
puts response.body
import requests

response = requests.post(
    'https://runapi.ai/api/v1/luma/modify_video',
    headers={
        'Authorization': 'Bearer YOUR_API_TOKEN',
        'Content-Type': 'application/json'
    },
    json={
        'prompt': 'Turn the street into a rainy cyberpunk night with neon reflections',
        'source_video_url': 'https://storage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4',
        'callback_url': 'https://your-domain.com/api/callbacks/luma',
        'watermark': 'demo-watermark'
    }
)
print(response.json())
fetch('https://runapi.ai/api/v1/luma/modify_video', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    prompt: 'Turn the street into a rainy cyberpunk night with neon reflections',
    source_video_url: 'https://storage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4',
    callback_url: 'https://your-domain.com/api/callbacks/luma',
    watermark: 'demo-watermark'
  })
}).then(r => r.json()).then(console.log);

HTTP 202 - Task accepted:

{
  "id": "task_abc123",
  "status": "processing"
}

POST /api/v1/luma/modify_video

Creates an asynchronous video modification task.

Request Parameters

Parameter Type Required Description
prompt string Yes English prompt describing how to transform the source video
source_video_url string Yes Publicly accessible source video URL. Supports MP4, MOV, and AVI
callback_url string No HTTPS webhook URL for completion events
watermark string No Watermark identifier added to the generated video

Response

Field Type Description
id string Task ID used for polling or callbacks
status string Initial async status, typically processing

Callback Format

If callback_url is provided, a POST request will be sent when processing finishes.

Success callback example:

{
  "id": "task_abc123",
  "status": "completed",
  "videos": [
    {
      "url": "https://tempfile.runapi.ai/generated-video.mp4"
    }
  ],
  "sources": [
    {
      "url": "https://storage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4"
    }
  ]
}

Failed callback example:

{
  "id": "task_abc123",
  "status": "failed",
  "error": "Modify record generation failed."
}

Get Luma Video Modification

Get task status and result:

curl -X GET "https://runapi.ai/api/v1/luma/modify_video/task_abc123" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
task_id = 'task_abc123'
uri = URI("https://runapi.ai/api/v1/luma/modify_video/#{task_id}")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'

response = http.request(request)
puts response.body
import requests

task_id = 'task_abc123'
response = requests.get(
    f'https://runapi.ai/api/v1/luma/modify_video/{task_id}',
    headers={'Authorization': 'Bearer YOUR_API_TOKEN'}
)
print(response.json())
const taskId = 'task_abc123';

fetch(`https://runapi.ai/api/v1/luma/modify_video/${taskId}`, {
  headers: { 'Authorization': 'Bearer YOUR_API_TOKEN' }
}).then(r => r.json()).then(console.log);

HTTP 200 - Completed:

{
  "id": "task_abc123",
  "status": "completed",
  "videos": [
    {
      "url": "https://tempfile.runapi.ai/generated-video.mp4"
    }
  ],
  "sources": [
    {
      "url": "https://storage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4"
    }
  ]
}

GET /api/v1/luma/modify_video/:id

Returns the latest task status. Luma's provider-specific callback failure state is normalized to completed because the generation itself has succeeded.

Response Fields

Field Type Description
id string Task ID
status string processing, completed, or failed
videos array Generated video URLs when the task is complete
sources array Source video URLs used for the modification
error string Error message when the task fails

Hailuo

Hailuo on RunAPI provides two async resources: text-to-video and image-to-video.

Models

Model Endpoint Notes
hailuo-02-text-to-video-pro POST /api/v1/hailuo/text_to_video Fixed pro text-to-video profile
hailuo-02-text-to-video-standard POST /api/v1/hailuo/text_to_video Standard text-to-video, supports duration_seconds
hailuo-02-image-to-video-pro POST /api/v1/hailuo/image_to_video Fixed pro image-to-video profile
hailuo-02-image-to-video-standard POST /api/v1/hailuo/image_to_video Supports duration_seconds, output_resolution, optional last_frame_image_url
hailuo-2.3-image-to-video-pro POST /api/v1/hailuo/image_to_video Supports duration_seconds, output_resolution
hailuo-2.3-image-to-video-standard POST /api/v1/hailuo/image_to_video Supports duration_seconds, output_resolution

Create Text-to-Video

POST https://runapi.ai/api/v1/hailuo/text_to_video

Parameter Type Required Description
model string Yes hailuo-02-text-to-video-pro or hailuo-02-text-to-video-standard
prompt string Yes Up to 1500 characters
duration_seconds number No 6 or 10. Supported by hailuo-02-text-to-video-standard only. Defaults to 6.
prompt_optimizer boolean No Enable Hailuo prompt optimization
enable_safety_checker boolean No Content safety check toggle
callback_url string No HTTPS callback URL

Create Image-to-Video

POST https://runapi.ai/api/v1/hailuo/image_to_video

Parameter Type Required Description
model string Yes Any supported Hailuo image-to-video model
prompt string Yes Up to 1500 characters on hailuo-02-*; up to 5000 on hailuo-2.3-*
first_frame_image_url string Yes Public first-frame image URL
last_frame_image_url string No Last-frame image URL. hailuo-02-* only.
duration_seconds number No 6 or 10 on standard / 2.3 models
output_resolution string No 512p / 768p on hailuo-02-image-to-video-standard; 768p / 1080p on 2.3 models
prompt_optimizer boolean No hailuo-02-* only
enable_safety_checker boolean No Content safety check toggle
callback_url string No HTTPS callback URL

Query Task Status

Completed response:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "videos": [
    {
      "url": "https://tempfile.runapi.ai/hailuo/output.mp4"
    }
  ]
}

HappyHorse

HappyHorse on RunAPI creates asynchronous text, image, and edit-video tasks with 720p or 1080p output. Text-to-video also supports a character-guided model that uses ordered reference images.

HappyHorse Endpoints

Task Endpoint Models
Text-to-video Create HappyHorse Text-to-Video happyhorse-text-to-video, happyhorse-character
Image-to-video Create HappyHorse Image-to-Video happyhorse-image-to-video
Edit video Create HappyHorse Edit Video happyhorse-edit-video
Check video status Get HappyHorse Text-to-Video Status -
Check image-to-video status Get HappyHorse Image-to-Video Status -
Check edit-video status Get HappyHorse Edit Video Status -

Create HappyHorse Text-to-Video

curl -X POST "https://runapi.ai/api/v1/happyhorse/text_to_video" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "happyhorse-text-to-video",
    "prompt": "A tiny paper horse gallops through a miniature cardboard city at night, cinematic camera move, warm window lights.",
    "output_resolution": "1080p",
    "aspect_ratio": "16:9",
    "duration_seconds": 5,
    "seed": 491001,
    "callback_url": "https://your-domain.com/api/callback"
  }'

Character-guided text-to-video uses the same endpoint with the happyhorse-character model and reference_image_urls:

curl -X POST "https://runapi.ai/api/v1/happyhorse/text_to_video" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "happyhorse-character",
    "prompt": "Character1 walks through a paper city and waves at character2 during a gentle cinematic camera move.",
    "reference_image_urls": [
      "https://cdn.runapi.ai/public/samples/reference-1.jpg",
      "https://cdn.runapi.ai/public/samples/reference-2.jpg"
    ],
    "output_resolution": "1080p",
    "aspect_ratio": "16:9",
    "duration_seconds": 5,
    "seed": 493001,
    "callback_url": "https://your-domain.com/api/callback"
  }'

HTTP 202

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "processing"
}

POST https://runapi.ai/api/v1/happyhorse/text_to_video

Parameter Type Required Description
model string Yes happyhorse-text-to-video or happyhorse-character
prompt string Yes Video prompt, max 5000 non-Chinese characters or 2500 Chinese characters
reference_image_urls array Required for happyhorse-character 1-9 public reference image URLs; order maps to character1, character2, and so on
output_resolution string No 720p or 1080p; defaults to 1080p
aspect_ratio string No 16:9, 9:16, 1:1, 4:3, or 3:4; defaults to 16:9
duration_seconds integer No Integer from 3 to 15 seconds; defaults to 5
seed integer No Integer from 0 to 2147483647
callback_url string No HTTPS callback URL for completion events

Get HappyHorse Text-to-Video Status

curl "https://runapi.ai/api/v1/happyhorse/text_to_video/YOUR_TASK_ID" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

HTTP 200

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "videos": [
    {
      "url": "https://file.runapi.ai/happyhorse/output.mp4"
    }
  ]
}

GET https://runapi.ai/api/v1/happyhorse/text_to_video/:id

Parameter Description
id Task ID returned by POST /api/v1/happyhorse/text_to_video

If callback_url is provided when creating the task, RunAPI sends the same completed or failed response body when the task finishes.

Create HappyHorse Edit Video

curl -X POST "https://runapi.ai/api/v1/happyhorse/edit_video" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "happyhorse-edit-video",
    "prompt": "Make the horse-headed humanoid character in the video wear the striped sweater from the reference image.",
    "source_video_url": "https://cdn.runapi.ai/public/samples/video.mp4",
    "reference_image_urls": [
      "https://cdn.runapi.ai/public/samples/reference-1.jpg"
    ],
    "output_resolution": "1080p",
    "audio_setting": "auto",
    "seed": 494001,
    "callback_url": "https://your-domain.com/api/callback"
  }'

HTTP 202

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "processing"
}

POST https://runapi.ai/api/v1/happyhorse/edit_video

Parameter Type Required Description
model string Yes Must be happyhorse-edit-video
prompt string Yes Edit instruction, max 5000 non-Chinese characters or 2500 Chinese characters
source_video_url string Yes One public MP4 or MOV source video URL; 3-60 seconds
reference_image_urls array No 0-5 public reference image URLs
output_resolution string No 720p or 1080p; defaults to 1080p
audio_setting string No auto or original; defaults to auto
seed integer No Integer from 0 to 2147483647
callback_url string No HTTPS callback URL for completion events

Get HappyHorse Edit Video Status

curl "https://runapi.ai/api/v1/happyhorse/edit_video/YOUR_TASK_ID" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

HTTP 200

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "videos": [
    {
      "url": "https://file.runapi.ai/happyhorse/output.mp4"
    }
  ]
}

GET https://runapi.ai/api/v1/happyhorse/edit_video/:id

Parameter Description
id Task ID returned by POST /api/v1/happyhorse/edit_video

If callback_url is provided when creating the task, RunAPI sends the same completed or failed response body when the task finishes.

Create HappyHorse Image-to-Video

curl -X POST "https://runapi.ai/api/v1/happyhorse/image_to_video" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "happyhorse-image-to-video",
    "first_frame_image_url": "https://cdn.runapi.ai/public/samples/image-to-video.jpg",
    "prompt": "Bring the still frame to life with a gentle cinematic camera move.",
    "output_resolution": "1080p",
    "duration_seconds": 5,
    "seed": 492001,
    "callback_url": "https://your-domain.com/api/callback"
  }'

HTTP 202

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "processing"
}

POST https://runapi.ai/api/v1/happyhorse/image_to_video

Parameter Type Required Description
model string Yes Must be happyhorse-image-to-video
first_frame_image_url string Yes Public first-frame image URL
prompt string No Video prompt, max 5000 non-Chinese characters or 2500 Chinese characters
output_resolution string No 720p or 1080p; defaults to 1080p
duration_seconds integer No Integer from 3 to 15 seconds; defaults to 5
seed integer No Integer from 0 to 2147483647
callback_url string No HTTPS callback URL for completion events

Get HappyHorse Image-to-Video Status

curl "https://runapi.ai/api/v1/happyhorse/image_to_video/YOUR_TASK_ID" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

HTTP 200

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "videos": [
    {
      "url": "https://file.runapi.ai/happyhorse/output.mp4"
    }
  ]
}

GET https://runapi.ai/api/v1/happyhorse/image_to_video/:id

Parameter Description
id Task ID returned by POST /api/v1/happyhorse/image_to_video

If callback_url is provided when creating the task, RunAPI sends the same completed or failed response body when the task finishes.

GPT Image

GPT Image is an advanced image generation model line supporting text-to-image generation and image editing with high-quality output in multiple aspect ratios.

Models

Model Type
gpt-image-1.5 Text-to-image
gpt-image-1.5 Edit image

GPT Image Endpoints

Task Endpoint Method
Create text-to-image Create Text-to-Image POST
Check text-to-image status Get Text-to-Image Status GET
Edit image Edit Image POST
Check edit status Get Edit Status GET

Create Text-to-Image

Text-to-image generation:

curl -X POST "https://runapi.ai/api/v1/gpt_image/text_to_image" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-image-1.5",
    "prompt": "A photorealistic portrait of an astronaut floating in space with Earth in the background",
    "aspect_ratio": "1:1",
    "quality": "high"
  }'
require 'net/http'
require 'uri'
require 'json'

uri = URI('https://runapi.ai/api/v1/gpt_image/text_to_image')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
request['Content-Type'] = 'application/json'
request.body = {
  model: 'gpt-image-1.5',
  prompt: 'A photorealistic portrait of an astronaut floating in space with Earth in the background',
  aspect_ratio: '1:1',
  quality: 'high'
}.to_json

response = http.request(request)
puts response.body
import requests

url = 'https://runapi.ai/api/v1/gpt_image/text_to_image'
headers = {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
}
data = {
    'model': 'gpt-image-1.5',
    'prompt': 'A photorealistic portrait of an astronaut floating in space with Earth in the background',
    'aspect_ratio': '1:1',
    'quality': 'high'
}

response = requests.post(url, headers=headers, json=data)
print(response.json())
const data = {
  model: 'gpt-image-1.5',
  prompt: 'A photorealistic portrait of an astronaut floating in space with Earth in the background',
  aspect_ratio: '1:1',
  quality: 'high'
};

fetch('https://runapi.ai/api/v1/gpt_image/text_to_image', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => console.log(data));

HTTP 202 - Task accepted:

{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "processing"
}

Create a new text-to-image task using GPT Image.

HTTP Request

POST https://runapi.ai/api/v1/gpt_image/text_to_image

Request Parameters

Parameter Type Required Description
model string Yes gpt-image-1.5
prompt string Yes Text description of the desired image
aspect_ratio string Yes Output aspect ratio: 1:1, 2:3, 3:2
quality string Yes Output quality: medium, high
callback_url string No URL for completion callback

Response

Returns a task ID for checking text-to-image status:

Field Type Description
id string Unique task identifier
status string Initial status: processing

Callback Format

If callback_url is provided, a POST request will be sent when the task completes.

Success Response: - Includes status: "completed" - Contains images array with generated image URLs

Failed Response: - Includes status: "failed" - Contains error message describing the failure reason

Success callback example:

{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "completed",
  "images": [
    {
      "url": "https://file.runapi.ai/generated/image1.png"
    }
  ]
}

Failed callback example:

{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "failed",
  "error": "Task failed"
}

Get Text-to-Image Status

Poll for text-to-image results:

curl "https://runapi.ai/api/v1/gpt_image/text_to_image/a1b2c3d4-e5f6-7890-abcd-ef1234567890" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
require 'net/http'
require 'uri'

task_id = 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'
uri = URI("https://runapi.ai/api/v1/gpt_image/text_to_image/#{task_id}")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'

response = http.request(request)
puts response.body
import requests

task_id = 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'
url = f'https://runapi.ai/api/v1/gpt_image/text_to_image/{task_id}'
headers = {
    'Authorization': 'Bearer YOUR_API_TOKEN'
}

response = requests.get(url, headers=headers)
print(response.json())
const taskId = 'a1b2c3d4-e5f6-7890-abcd-ef1234567890';

fetch(`https://runapi.ai/api/v1/gpt_image/text_to_image/${taskId}`, {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN'
  }
})
.then(response => response.json())
.then(data => console.log(data));

Processing:

{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "processing"
}

Completed:

{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "completed",
  "images": [
    {
      "url": "https://file.runapi.ai/generated/image1.png"
    }
  ]
}

Failed:

{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "failed",
  "error": "Generation failed."
}

Retrieve the status and results of a GPT Image text-to-image task.

HTTP Request

GET https://runapi.ai/api/v1/gpt_image/text_to_image/:id

URL Parameters

Parameter Description
id The ID of the task returned from the create request

Response Fields

Field Type Description
id string Unique task identifier
status string Task status: processing, completed, failed
images array Array of image objects (only present when status is completed)
images[].url string CDN URL of the generated image
error string Error message (only present when status is failed)

Status Values

Edit Image

Edit image:

curl -X POST "https://runapi.ai/api/v1/gpt_image/edit_image" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-image-1.5",
    "prompt": "Transform this photo into a vibrant oil painting with warm autumn colors",
    "source_image_urls": [
      "https://cdn.runapi.ai/public/samples/image.jpg"
    ],
    "aspect_ratio": "3:2",
    "quality": "high"
  }'
require 'net/http'
require 'uri'
require 'json'

uri = URI('https://runapi.ai/api/v1/gpt_image/edit_image')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
request['Content-Type'] = 'application/json'
request.body = {
  model: 'gpt-image-1.5',
  prompt: 'Transform this photo into a vibrant oil painting with warm autumn colors',
  source_image_urls: [
    'https://cdn.runapi.ai/public/samples/image.jpg'
  ],
  aspect_ratio: '3:2',
  quality: 'high'
}.to_json

response = http.request(request)
puts response.body
import requests

url = 'https://runapi.ai/api/v1/gpt_image/edit_image'
headers = {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
}
data = {
    'model': 'gpt-image-1.5',
    'prompt': 'Transform this photo into a vibrant oil painting with warm autumn colors',
    'source_image_urls': [
        'https://cdn.runapi.ai/public/samples/image.jpg'
    ],
    'aspect_ratio': '3:2',
    'quality': 'high'
}

response = requests.post(url, headers=headers, json=data)
print(response.json())
const data = {
  model: 'gpt-image-1.5',
  prompt: 'Transform this photo into a vibrant oil painting with warm autumn colors',
  source_image_urls: [
    'https://cdn.runapi.ai/public/samples/image.jpg'
  ],
  aspect_ratio: '3:2',
  quality: 'high'
};

fetch('https://runapi.ai/api/v1/gpt_image/edit_image', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => console.log(data));

HTTP 202 - Task accepted:

{
  "id": "b2c3d4e5-f6a7-8901-bcde-f01234567891",
  "status": "processing"
}

Create a new image editing task using GPT Image.

HTTP Request

POST https://runapi.ai/api/v1/gpt_image/edit_image

Request Parameters

Parameter Type Required Description
model string Yes gpt-image-1.5
prompt string Yes Text description of the desired edit
source_image_urls array Yes Source image URLs (max 16 images)
aspect_ratio string Yes Output aspect ratio: 1:1, 2:3, 3:2
quality string Yes Output quality: medium, high
callback_url string No URL for completion callback

Response

Returns a task ID for checking edit status:

Field Type Description
id string Unique task identifier
status string Initial status: processing

Callback Format

If callback_url is provided, a POST request will be sent when editing completes.

Success callback example:

{
  "id": "b2c3d4e5-f6a7-8901-bcde-f01234567891",
  "status": "completed",
  "images": [
    {
      "url": "https://file.runapi.ai/edited/image1.png"
    }
  ]
}

Failed callback example:

{
  "id": "b2c3d4e5-f6a7-8901-bcde-f01234567891",
  "status": "failed",
  "error": "Edit failed"
}

Get Edit Status

Poll for edit results:

curl "https://runapi.ai/api/v1/gpt_image/edit_image/b2c3d4e5-f6a7-8901-bcde-f01234567891" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
require 'net/http'
require 'uri'

task_id = 'b2c3d4e5-f6a7-8901-bcde-f01234567891'
uri = URI("https://runapi.ai/api/v1/gpt_image/edit_image/#{task_id}")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'

response = http.request(request)
puts response.body
import requests

task_id = 'b2c3d4e5-f6a7-8901-bcde-f01234567891'
url = f'https://runapi.ai/api/v1/gpt_image/edit_image/{task_id}'
headers = {
    'Authorization': 'Bearer YOUR_API_TOKEN'
}

response = requests.get(url, headers=headers)
print(response.json())
const taskId = 'b2c3d4e5-f6a7-8901-bcde-f01234567891';

fetch(`https://runapi.ai/api/v1/gpt_image/edit_image/${taskId}`, {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN'
  }
})
.then(response => response.json())
.then(data => console.log(data));

Processing:

{
  "id": "b2c3d4e5-f6a7-8901-bcde-f01234567891",
  "status": "processing"
}

Completed:

{
  "id": "b2c3d4e5-f6a7-8901-bcde-f01234567891",
  "status": "completed",
  "images": [
    {
      "url": "https://file.runapi.ai/edited/image1.png"
    }
  ]
}

Failed:

{
  "id": "b2c3d4e5-f6a7-8901-bcde-f01234567891",
  "status": "failed",
  "error": "Edit failed."
}

Retrieve the status and results of a GPT Image image editing task.

HTTP Request

GET https://runapi.ai/api/v1/gpt_image/edit_image/:id

URL Parameters

Parameter Description
id The ID of the task returned from the create request

Response Fields

Field Type Description
id string Unique task identifier
status string Task status: processing, completed, failed
images array Array of image objects (only present when status is completed)
images[].url string CDN URL of the edited image
error string Error message (only present when status is failed)

Status Values

GPT Image 2

GPT Image 2 supports text-to-image generation and image editing.

Models

Model Type
gpt-image-2 Text-to-image
gpt-image-2 Edit image

Endpoints

Task Endpoint Method
Create text-to-image Create Text-to-Image POST
Check text-to-image status Get Text-to-Image Status GET
Edit image Edit Image POST
Check edit status Get Edit Status GET

GPT Image 2 Create Text-to-Image

Text-to-image generation:

curl -X POST "https://runapi.ai/api/v1/gpt_image_2/text_to_image" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-image-2",
    "prompt": "A cinematic night city poster with neon reflections on a rainy street",
    "aspect_ratio": "16:9",
    "output_resolution": "2k"
  }'

POST https://runapi.ai/api/v1/gpt_image_2/text_to_image

Request Parameters

Parameter Type Required Description
model string Yes gpt-image-2
prompt string Yes Text prompt, maximum 20,000 characters
aspect_ratio string No auto, 1:1, 9:16, 16:9, 4:3, 3:4
output_resolution string No 1k, 2k, 4k. A 1:1 image cannot be 4k; auto/unset only supports 1k
callback_url string No URL for completion callback

Response

{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "processing"
}

GPT Image 2 Get Text-to-Image Status

GET https://runapi.ai/api/v1/gpt_image_2/text_to_image/:id

Returns the current task status and images when the task completes.

GPT Image 2 Edit

Edit an image:

curl -X POST "https://runapi.ai/api/v1/gpt_image_2/edit_image" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-image-2",
    "prompt": "Transform this product image into a premium e-commerce poster style",
    "source_image_urls": ["https://raw.githubusercontent.com/github/explore/main/topics/python/python.png"],
    "aspect_ratio": "16:9",
    "output_resolution": "2k"
  }'

POST https://runapi.ai/api/v1/gpt_image_2/edit_image

Request Parameters

Parameter Type Required Description
model string Yes gpt-image-2
prompt string Yes Text prompt, maximum 20,000 characters
source_image_urls array Yes Array of source image URLs, maximum 16 images
aspect_ratio string No auto, 1:1, 9:16, 16:9, 4:3, 3:4
output_resolution string No 1k, 2k, 4k. A 1:1 image cannot be 4k; auto/unset only supports 1k
callback_url string No URL for completion callback

Response

{
  "id": "b2c3d4e5-f6a7-8901-bcde-f01234567891",
  "status": "processing"
}

GPT Image 2 Get Edit Status

GET https://runapi.ai/api/v1/gpt_image_2/edit_image/:id

Returns the current task status and images when the task completes.

GPT-4o Image

GPT-4o Image supports prompt-only, image-guided, and variant image tasks.

Models

Model Type
gpt-4o-image Text-to-image / image-guided / variants

Endpoints

Task Endpoint Method
Create text-to-image task Create Text-to-Image POST
Check task status Get Text-to-Image Status GET

GPT-4o Image Create Text-to-Image

Prompt-only, image-guided, or variant request:

curl -X POST "https://runapi.ai/api/v1/gpt_4o_image/text_to_image" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-4o-image",
    "prompt": "A premium watch product photo on black stone",
    "aspect_ratio": "1:1",
    "source_image_urls": ["https://raw.githubusercontent.com/github/explore/main/topics/python/python.png"],
    "output_count": 2
  }'

POST https://runapi.ai/api/v1/gpt_4o_image/text_to_image

Request Parameters

Parameter Type Required Description
model string Yes gpt-4o-image
prompt string Conditionally Required when source_image_urls is blank
aspect_ratio string Yes 1:1, 3:2, 2:3
source_image_urls array No Up to 5 source image URLs
mask_url string No Mask image URL for selective changes
output_count integer No Number of generated images: 1, 2, or 4
enable_prompt_expansion boolean No Prompt expansion toggle
callback_url string No URL for completion callback

Response

{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "processing"
}

GPT-4o Image Get Text-to-Image Status

GET https://runapi.ai/api/v1/gpt_4o_image/text_to_image/:id

Returns the current task status, progress, and images when the task completes.

Grok-Imagine

Grok-Imagine is a multimodal generation family on RunAPI. It supports text-to-video, image-to-video, text-to-image, image editing, plus extend and upscale operations on prior video tasks.

Model Variants

Model Description Best For
grok-imagine-text-to-video Text-driven video generation with motion style control Ideation and stylised shorts
grok-imagine-image-to-video Animate one or more reference images into video Bringing stills to motion
grok-imagine-text-to-image Text-driven image generation with optional Pro quality Key-art and concept images
grok-imagine-edit-image Edit a single source image Style re-interpretation

Grok-Imagine Endpoints

Task Endpoint Model
Create text-to-video task Create Text-to-Video grok-imagine-text-to-video
Create image-to-video task Create Image-to-Video grok-imagine-image-to-video
Create text-to-image task Create Text-to-Image grok-imagine-text-to-image
Create edit-image task Create Edit Image grok-imagine-edit-image
Extend a prior video Extend Video -
Upscale a prior video Upscale Video -
Check task status Get Task Status -

Lifecycle

All six create endpoints are asynchronous. A successful POST returns HTTP 202 with { "id", "status": "processing" }. Poll the matching GET /:id endpoint, or supply a callback_url, to receive the final result.

Create Grok-Imagine Text-to-Video

Create a text-to-video task:

curl -X POST "https://runapi.ai/api/v1/grok_imagine/text_to_video" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "grok-imagine-text-to-video",
    "prompt": "A neon dragon gliding over a rain-soaked Tokyo street at night",
    "aspect_ratio": "16:9",
    "motion_style": "normal",
    "duration_seconds": 10,
    "output_resolution": "720p",
    "enable_safety_checker": false,
    "callback_url": "https://your-domain.com/api/callback"
  }'
require 'net/http'
require 'uri'
require 'json'

uri = URI('https://runapi.ai/api/v1/grok_imagine/text_to_video')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
request['Content-Type'] = 'application/json'
request.body = {
  model: 'grok-imagine-text-to-video',
  prompt: 'A neon dragon gliding over a rain-soaked Tokyo street at night',
  aspect_ratio: '16:9',
  motion_style: 'normal',
  duration_seconds: 10,
  output_resolution: '720p',
  enable_safety_checker: false,
  callback_url: 'https://your-domain.com/api/callback'
}.to_json

response = http.request(request)
puts response.body
import requests

url = 'https://runapi.ai/api/v1/grok_imagine/text_to_video'
headers = {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
}
data = {
    'model': 'grok-imagine-text-to-video',
    'prompt': 'A neon dragon gliding over a rain-soaked Tokyo street at night',
    'aspect_ratio': '16:9',
    'motion_style': 'normal',
    'duration_seconds': 10,
    'output_resolution': '720p',
    'enable_safety_checker': False,
    'callback_url': 'https://your-domain.com/api/callback'
}

response = requests.post(url, headers=headers, json=data)
print(response.json())
const data = {
  model: 'grok-imagine-text-to-video',
  prompt: 'A neon dragon gliding over a rain-soaked Tokyo street at night',
  aspect_ratio: '16:9',
  motion_style: 'normal',
  duration_seconds: 10,
  output_resolution: '720p',
  enable_safety_checker: false,
  callback_url: 'https://your-domain.com/api/callback'
};

fetch('https://runapi.ai/api/v1/grok_imagine/text_to_video', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => console.log(data));

HTTP 202 - Task accepted:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "processing"
}

HTTP Request

POST https://runapi.ai/api/v1/grok_imagine/text_to_video

Request Parameters

Parameter Type Required Description
model string Yes Must be grok-imagine-text-to-video
prompt string Yes Up to 5000 characters
aspect_ratio string No 2:3, 3:2, 1:1, 16:9, 9:16. Defaults to 2:3
motion_style string No fun, normal, or spicy. Defaults to normal
duration_seconds integer No Seconds, 6 through 30
output_resolution string No 480p or 720p. Defaults to 480p
enable_safety_checker boolean No Content safety check toggle
callback_url string No HTTPS callback URL for completion events

Create Grok-Imagine Image-to-Video

Create an image-to-video task from reference images:

curl -X POST "https://runapi.ai/api/v1/grok_imagine/image_to_video" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "grok-imagine-image-to-video",
    "source_image_urls": [
      "https://cdn.runapi.ai/public/samples/image-to-video.jpg"
    ],
    "prompt": "Slow dolly-in on the subject as wind ruffles the hair",
    "motion_style": "normal",
    "duration_seconds": 8,
    "output_resolution": "720p",
    "aspect_ratio": "16:9",
    "enable_safety_checker": false,
    "callback_url": "https://your-domain.com/api/callback"
  }'

Alternatively, animate an image generated by a prior grok-imagine-text-to-image task:

curl -X POST "https://runapi.ai/api/v1/grok_imagine/image_to_video" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "grok-imagine-image-to-video",
    "source_task_id": "a1b2c3d4-e5f6-7890-abcd-1234567890ab",
    "index": 0,
    "prompt": "Gentle camera orbit around the subject",
    "duration_seconds": 10,
    "output_resolution": "720p"
  }'

HTTP 202 - Task accepted:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "processing"
}

HTTP Request

POST https://runapi.ai/api/v1/grok_imagine/image_to_video

Request Parameters

Parameter Type Required Description
model string Yes Must be grok-imagine-image-to-video
source_image_urls array Conditional Exactly one source image URL. Required unless source_task_id is provided
source_task_id string Conditional Task id from a prior grok-imagine-text-to-image task. Required unless source_image_urls is provided
index integer No When using source_task_id, selects which generated image to animate (0-5)
prompt string No Motion guidance prompt
motion_style string No fun, normal, or spicy. spicy is not available when source_image_urls is used
duration_seconds integer No Seconds, 6 through 30
output_resolution string No 480p or 720p
aspect_ratio string No 2:3, 3:2, 1:1, 16:9, 9:16. Defaults to 16:9
enable_safety_checker boolean No Content safety check toggle
callback_url string No HTTPS callback URL

Create Grok-Imagine Text-to-Image

Create a text-to-image task:

curl -X POST "https://runapi.ai/api/v1/grok_imagine/text_to_image" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "grok-imagine-text-to-image",
    "prompt": "A cyberpunk fox warrior standing on a rooftop overlooking a neon city",
    "aspect_ratio": "1:1",
    "enable_pro": true,
    "enable_safety_checker": false,
    "callback_url": "https://your-domain.com/api/callback"
  }'

HTTP 202 - Task accepted:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "processing"
}

HTTP Request

POST https://runapi.ai/api/v1/grok_imagine/text_to_image

Request Parameters

Parameter Type Required Description
model string Yes Must be grok-imagine-text-to-image
prompt string Yes Up to 5000 characters
aspect_ratio string No 2:3, 3:2, 1:1, 16:9, 9:16. Defaults to 1:1
enable_pro boolean No Enable Pro quality mode. Content safety check toggle
enable_safety_checker boolean No Content safety check toggle
callback_url string No HTTPS callback URL

Create Grok-Imagine Edit Image

Create an edit-image task:

curl -X POST "https://runapi.ai/api/v1/grok_imagine/edit_image" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "grok-imagine-edit-image",
    "source_image_url": "https://cdn.runapi.ai/public/samples/image.jpg",
    "prompt": "Reimagine the subject as an oil painting",
    "enable_safety_checker": false,
    "callback_url": "https://your-domain.com/api/callback"
  }'

HTTP 202 - Task accepted:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "processing"
}

HTTP Request

POST https://runapi.ai/api/v1/grok_imagine/edit_image

Request Parameters

Parameter Type Required Description
model string Yes Must be grok-imagine-edit-image
source_image_url string Yes Source image URL
prompt string No Edit prompt
enable_safety_checker boolean No Content safety check toggle
callback_url string No HTTPS callback URL

Extend Grok-Imagine Video

Extend a previously generated Grok-Imagine video:

curl -X POST "https://runapi.ai/api/v1/grok_imagine/extend_video" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "source_task_id": "a1b2c3d4-e5f6-7890-abcd-1234567890ab",
    "prompt": "Continue with the dragon soaring above the skyline",
    "start_seconds": 6,
    "extension_duration_seconds": 6,
    "callback_url": "https://your-domain.com/api/callback"
  }'

HTTP 202 - Task accepted:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "processing"
}

HTTP Request

POST https://runapi.ai/api/v1/grok_imagine/extend_video

Request Parameters

Parameter Type Required Description
source_task_id string Yes Task id of a prior Grok-Imagine video task (grok-imagine-text-to-video or grok-imagine-image-to-video) owned by the same account
prompt string Yes Prompt guiding the extension
start_seconds integer Yes Seconds into the source video where the extension begins
extension_duration_seconds integer Yes 6 or 10 — the duration of the appended segment in seconds
callback_url string No HTTPS callback URL

Upscale Grok-Imagine Video

Upscale a previously generated Grok-Imagine video:

curl -X POST "https://runapi.ai/api/v1/grok_imagine/upscale_image" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "source_task_id": "a1b2c3d4-e5f6-7890-abcd-1234567890ab",
    "callback_url": "https://your-domain.com/api/callback"
  }'

HTTP 202 - Task accepted:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "processing"
}

HTTP Request

POST https://runapi.ai/api/v1/grok_imagine/upscale_image

Request Parameters

Parameter Type Required Description
source_task_id string Yes Task id of a prior Grok-Imagine video task owned by the same account. Only 480p source videos are supported for upscale.
callback_url string No HTTPS callback URL

Get Grok-Imagine Task Status

Each create endpoint has a matching status endpoint at the same path plus /:id. Poll it to check whether the task is still running, or inspect the final result.

Created via Status endpoint
POST /api/v1/grok_imagine/text_to_video GET /api/v1/grok_imagine/text_to_video/:id
POST /api/v1/grok_imagine/image_to_video GET /api/v1/grok_imagine/image_to_video/:id
POST /api/v1/grok_imagine/text_to_image GET /api/v1/grok_imagine/text_to_image/:id
POST /api/v1/grok_imagine/edit_image GET /api/v1/grok_imagine/edit_image/:id
POST /api/v1/grok_imagine/extend_video GET /api/v1/grok_imagine/extend_video/:id
POST /api/v1/grok_imagine/upscale_image GET /api/v1/grok_imagine/upscale_image/:id

Check a Grok-Imagine task:

curl "https://runapi.ai/api/v1/grok_imagine/text_to_video/YOUR_TASK_ID" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
task_id = 'YOUR_TASK_ID'
uri = URI("https://runapi.ai/api/v1/grok_imagine/text_to_video/#{task_id}")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'

response = http.request(request)
puts response.body
task_id = 'YOUR_TASK_ID'
response = requests.get(
    f'https://runapi.ai/api/v1/grok_imagine/text_to_video/{task_id}',
    headers={'Authorization': 'Bearer YOUR_API_TOKEN'}
)
print(response.json())
const taskId = 'YOUR_TASK_ID';

fetch(`https://runapi.ai/api/v1/grok_imagine/text_to_video/${taskId}`, {
  headers: { 'Authorization': 'Bearer YOUR_API_TOKEN' }
})
.then(res => res.json())
.then(data => console.log(data));

Completed video response example:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "videos": [
    {
      "url": "https://file.runapi.ai/grok-imagine/generated-video.mp4"
    }
  ]
}

Completed image response example:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "images": [
    {
      "url": "https://file.runapi.ai/grok-imagine/generated-image.png"
    }
  ]
}

Failed response example:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "failed",
  "error": "Generation failed"
}

Response Fields

Field Type Description
id string Task identifier
status string processing, completed, or failed
videos array Generated video URLs when a video task completes
images array Generated image URLs when an image task completes
error string Error message when the task fails

Callback Format

If callback_url was provided when creating the task, a POST request with the same body as the completed/failed response above is sent when the task finishes.

Topaz

Topaz provides dedicated RunAPI endpoints for image and video upscaling.

Models

Model Type Pricing
topaz-upscale-image Image upscale Pricing
topaz-upscale-video Video upscale Pricing

Endpoints

Task Endpoint Method
Upscale image Upscale Image POST
Check image status Get Upscale Image Status GET
Upscale video Upscale Video POST
Check video status Get Upscale Video Status GET

Topaz Upscale Image

curl -X POST "https://runapi.ai/api/v1/topaz/upscale_image" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "topaz-upscale-image",
    "source_image_url": "https://cdn.runapi.ai/public/samples/upscale.jpg",
    "upscale_factor": 4
  }'

POST https://runapi.ai/api/v1/topaz/upscale_image

Request Parameters

Parameter Type Required Description
model string Yes topaz-upscale-image
source_image_url string Yes Public input image URL
upscale_factor number Yes 1, 2, 4, or 8
callback_url string No URL for completion callback

Response

{
  "id": "img-task-123",
  "status": "processing"
}

Topaz Get Upscale Image Status

GET https://runapi.ai/api/v1/topaz/upscale_image/:id

Returns the current task status and images when the task completes.

Topaz Upscale Video

curl -X POST "https://runapi.ai/api/v1/topaz/upscale_video" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "topaz-upscale-video",
    "source_video_url": "https://cdn.runapi.ai/public/samples/video-lowres.mp4",
    "upscale_factor": 2
  }'

POST https://runapi.ai/api/v1/topaz/upscale_video

Request Parameters

Parameter Type Required Description
model string Yes topaz-upscale-video
source_video_url string Yes Public input video URL
upscale_factor number No 1, 2, or 4; omitted uses the service default
callback_url string No URL for completion callback

Response

{
  "id": "vid-task-123",
  "status": "processing"
}

Topaz Get Upscale Video Status

GET https://runapi.ai/api/v1/topaz/upscale_video/:id

Returns the current task status and videos when the task completes.

GPT

Access OpenAI GPT language models through RunAPI. The API supports both the Chat Completions format (GPT 5.2) and the Responses API format (GPT 5.5, GPT 5.4, GPT Codex).

SDK Quickstart

Using the OpenAI Python SDK:

from openai import OpenAI

client = OpenAI(
    api_key="YOUR_API_TOKEN",
    base_url="https://runapi.ai/v1"
)

# Chat Completions (GPT 5.2)
response = client.chat.completions.create(
    model="gpt-5.2",
    messages=[
        {"role": "user", "content": "Hello!"}
    ]
)
print(response.choices[0].message.content)
import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: 'YOUR_API_TOKEN',
  baseURL: 'https://runapi.ai/v1',
});

// Chat Completions (GPT 5.2)
const response = await client.chat.completions.create({
  model: 'gpt-5.2',
  messages: [
    { role: 'user', content: 'Hello!' }
  ],
});
console.log(response.choices[0].message.content);
require "openai"

client = OpenAI::Client.new(
  access_token: "YOUR_API_TOKEN",
  uri_base: "https://runapi.ai/v1"
)

response = client.chat(
  parameters: {
    model: "gpt-5.2",
    messages: [
      { role: "user", content: "Hello!" }
    ]
  }
)
puts response.dig("choices", 0, "message", "content")
curl -X POST "https://runapi.ai/v1/chat/completions" \
  -H "x-api-key: YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-5.2",
    "messages": [
      {"role": "user", "content": "Hello!"}
    ]
  }'

Set base_url to https://runapi.ai/v1 and use your RunAPI API key.

Models

Model Version String Endpoint Capabilities
GPT 5.5 gpt-5.5 /v1/responses Chat, multimodal input, web search, function calling, reasoning
GPT 5.2 gpt-5.2 /v1/chat/completions Chat, web search, reasoning effort
GPT 5.4 gpt-5.4 /v1/responses Chat, multimodal input, web search, function calling, reasoning
GPT Codex gpt-5-codex /v1/responses Code generation, multimodal, web search, function calling, reasoning
GPT Codex gpt-5.1-codex /v1/responses Code generation, multimodal, web search, function calling, reasoning
GPT Codex gpt-5.2-codex /v1/responses Code generation, multimodal, web search, function calling, reasoning
GPT Codex gpt-5.3-codex /v1/responses Code generation, multimodal, web search, function calling, reasoning
GPT Codex gpt-5.4-codex /v1/responses Code generation, multimodal, web search, function calling, reasoning

List Models

List GPT models in OpenAI-compatible format:

curl -X GET "https://runapi.ai/v1/models" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
from openai import OpenAI

client = OpenAI(api_key="YOUR_API_TOKEN", base_url="https://runapi.ai/v1")
models = client.models.list()
for model in models.data:
    print(model.id)
{
  "object": "list",
  "data": [
    {
      "id": "gpt-5.5",
      "object": "model",
      "created": 1714900000,
      "owned_by": "system"
    }
  ]
}

GET /v1/models

Returns available GPT models in OpenAI List Models format. If the API key has allowed_models restrictions, only permitted models are returned.

Chat Completions

Endpoint: POST https://runapi.ai/v1/chat/completions

For GPT 5.2. Compatible with the OpenAI Chat Completions API format.

Chat Completions request:

curl -X POST "https://runapi.ai/v1/chat/completions" \
  -H "x-api-key: YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-5.2",
    "messages": [
      {"role": "user", "content": "Explain quantum computing in one sentence."}
    ],
    "reasoning_effort": "high"
  }'
response = client.chat.completions.create(
    model="gpt-5.2",
    messages=[
        {"role": "user", "content": "Explain quantum computing in one sentence."}
    ]
)
const response = await client.chat.completions.create({
  model: 'gpt-5.2',
  messages: [
    { role: 'user', content: 'Explain quantum computing in one sentence.' }
  ],
});
response = client.chat(
  parameters: {
    model: "gpt-5.2",
    messages: [
      { role: "user", content: "Explain quantum computing in one sentence." }
    ]
  }
)

Response:

{
  "id": "chatcmpl-abc123",
  "object": "chat.completion",
  "created": 1700000000,
  "model": "gpt-5.2",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "Quantum computing uses qubits..."
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 15,
    "completion_tokens": 50,
    "total_tokens": 65
  }
}

Parameters

Parameter Type Required Description
model string Yes Model ID: gpt-5.2
messages array Yes Conversation messages with role and content
tools array No Tool definitions. Supports web_search
reasoning_effort string No "low" or "high" (default: "high")
stream boolean No Enable SSE streaming (default: false)

Messages Format

Messages support multimodal content with text and images:

{
  "messages": [
    {
      "role": "user",
      "content": [
        {"type": "text", "text": "What is in this image?"},
        {"type": "image_url", "image_url": {"url": "https://cdn.runapi.ai/public/samples/image.jpg"}}
      ]
    }
  ]
}

Responses

Endpoint: POST https://runapi.ai/v1/responses

For GPT 5.5, GPT 5.4, and GPT Codex models. Uses the OpenAI Responses API format with multimodal input, reasoning, and tool support.

Responses API request:

curl -X POST "https://runapi.ai/v1/responses" \
  -H "x-api-key: YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-5.4",
    "input": "Explain the theory of relativity.",
    "reasoning": {"effort": "medium"}
  }'
import httpx

response = httpx.post(
    "https://runapi.ai/v1/responses",
    headers={"x-api-key": "YOUR_API_TOKEN"},
    json={
        "model": "gpt-5.4",
        "input": "Explain the theory of relativity.",
        "reasoning": {"effort": "medium"}
    }
)
print(response.json())
const response = await fetch('https://runapi.ai/v1/responses', {
  method: 'POST',
  headers: {
    'x-api-key': 'YOUR_API_TOKEN',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    model: 'gpt-5.4',
    input: 'Explain the theory of relativity.',
    reasoning: { effort: 'medium' },
  }),
});
const data = await response.json();
require "net/http"
require "json"

uri = URI("https://runapi.ai/v1/responses")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request["x-api-key"] = "YOUR_API_TOKEN"
request["Content-Type"] = "application/json"
request.body = {
  model: "gpt-5.4",
  input: "Explain the theory of relativity.",
  reasoning: { effort: "medium" }
}.to_json

response = http.request(request)
puts JSON.parse(response.body)

Response:

{
  "output": [
    {
      "type": "message",
      "id": "msg_abc123",
      "role": "assistant",
      "content": [
        {"type": "output_text", "text": "The theory of relativity..."}
      ],
      "status": "completed"
    }
  ],
  "usage": {
    "input_tokens": 12,
    "output_tokens": 200,
    "total_tokens": 212
  },
  "status": "completed"
}

Parameters

Parameter Type Required Description
model string Yes Model ID: gpt-5.5, gpt-5.4, gpt-5-codex, gpt-5.1-codex, gpt-5.2-codex, gpt-5.3-codex, gpt-5.4-codex
input string or array Yes Text string or array of input items
stream boolean No Enable SSE streaming (default: false)
reasoning object No `{"effort": "minimal"\
tools array No Web search or function calling tools (mutually exclusive)
tool_choice string No Set to "auto" when using function tools

Input Format

The input field accepts a simple string or an array of message objects with multimodal content:

{
  "input": [
    {"role": "user", "content": [
      {"type": "input_text", "text": "Describe this image"},
      {"type": "input_image", "image_url": "https://cdn.runapi.ai/public/samples/image.jpg"}
    ]}
  ]
}

Supported content types: input_text, input_image, input_file.

Web Search Tool

{
  "tools": [{"type": "web_search"}]
}

Function Calling

{
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "Get the current weather",
        "parameters": {
          "type": "object",
          "properties": {
            "location": {"type": "string"}
          },
          "required": ["location"]
        }
      }
    }
  ],
  "tool_choice": "auto"
}

Streaming

Streaming request (Chat Completions):

curl -X POST "https://runapi.ai/v1/chat/completions" \
  -H "x-api-key: YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-5.2",
    "stream": true,
    "messages": [
      {"role": "user", "content": "Write a haiku about coding."}
    ]
  }'

Streaming request (Responses API):

curl -X POST "https://runapi.ai/v1/responses" \
  -H "x-api-key: YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-5.4",
    "stream": true,
    "input": "Write a haiku about coding."
  }'

Set "stream": true to receive Server-Sent Events (SSE). The response streams incrementally with Content-Type: text/event-stream.

Responses API streaming events

Event Description
response.output_text.delta Incremental text content
response.function_call_arguments.delta Incremental function call arguments
response.completed Final event with usage data

Authentication

Method Header Example
API Key x-api-key x-api-key: YOUR_API_TOKEN
Bearer Authorization Authorization: Bearer YOUR_API_TOKEN

Billing

Token-based billing: credits are calculated from actual input and output token usage. A provisional amount is reserved before the request, then adjusted to the actual usage after completion.

Gemini

Access Google Gemini language models through RunAPI using the OpenAI Chat Completions format.

SDK Quickstart

Using the OpenAI Python SDK:

from openai import OpenAI

client = OpenAI(
    api_key="YOUR_API_TOKEN",
    base_url="https://runapi.ai/v1beta/openai"
)

response = client.chat.completions.create(
    model="gemini-2.5-flash",
    messages=[
        {"role": "user", "content": "Hello!"}
    ]
)
print(response.choices[0].message.content)
import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: 'YOUR_API_TOKEN',
  baseURL: 'https://runapi.ai/v1beta/openai',
});

const response = await client.chat.completions.create({
  model: 'gemini-2.5-flash',
  messages: [
    { role: 'user', content: 'Hello!' }
  ],
});
console.log(response.choices[0].message.content);
require "openai"

client = OpenAI::Client.new(
  access_token: "YOUR_API_TOKEN",
  uri_base: "https://runapi.ai/v1beta/openai"
)

response = client.chat(
  parameters: {
    model: "gemini-2.5-flash",
    messages: [
      { role: "user", content: "Hello!" }
    ]
  }
)
puts response.dig("choices", 0, "message", "content")
curl -X POST "https://runapi.ai/v1beta/openai/chat/completions" \
  -H "x-api-key: YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gemini-2.5-flash",
    "messages": [
      {"role": "user", "content": "Hello!"}
    ]
  }'

For the closest drop-in replacement experience, set base_url to https://runapi.ai/v1beta/openai and use your RunAPI API key.

Models

Model Version String Endpoint Capabilities
Gemini 2.5 Flash gemini-2.5-flash /v1beta/openai/chat/completions Chat, multimodal input, Google Search, structured output, thoughts
Gemini 2.5 Pro gemini-2.5-pro /v1beta/openai/chat/completions Chat, multimodal input, Google Search, structured output, thoughts, reasoning effort
Gemini 3.1 Pro gemini-3.1-pro-preview /v1beta/openai/chat/completions Chat, multimodal input, Google Search, thoughts, reasoning effort
Gemini 3.5 Flash gemini-3.5-flash /v1beta/models/gemini-3.5-flash:streamGenerateContent Streaming contents requests, multimodal input, function calling, thoughts
Gemini 3 Flash gemini-3-flash-preview /v1beta/openai/chat/completions or /v1beta/models/gemini-3-flash-preview:streamGenerateContent Chat, multimodal, function calling, structured output, thoughts, reasoning effort — also supports the contents streaming endpoint
Gemini 3 Pro gemini-3-pro-preview /v1beta/openai/chat/completions Chat, multimodal input, Google Search, structured output, thoughts, reasoning effort

List Models

List Gemini models:

curl -X GET "https://runapi.ai/v1beta/models" \
  -H "x-api-key: YOUR_API_TOKEN"
from openai import OpenAI

client = OpenAI(api_key="YOUR_API_TOKEN", base_url="https://runapi.ai/v1beta/openai")
models = client.models.list()
for model in models.data:
    print(model.id)
{
  "models": [
    {
      "name": "models/gemini-3.5-flash",
      "version": "001",
      "displayName": "Gemini 3.5 Flash",
      "description": "Gemini 3.5 Flash language model",
      "inputTokenLimit": 1048576,
      "outputTokenLimit": 65536,
      "supportedGenerationMethods": ["streamGenerateContent"]
    }
  ]
}

GET /v1beta/models

Returns available Gemini models in the Google AI models.list format. If the API key has allowed_models restrictions, only permitted models are returned.

Alternatively, when using the OpenAI SDK with base_url="https://runapi.ai/v1beta/openai", calling client.models.list() will hit /v1beta/openai/models which returns OpenAI-format model list.

Chat Completions

Endpoint: POST https://runapi.ai/v1beta/openai/chat/completions

Compatible with the OpenAI Chat Completions request format.

Gemini request:

curl -X POST "https://runapi.ai/v1beta/openai/chat/completions" \
  -H "x-api-key: YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gemini-2.5-pro",
    "messages": [
      {"role": "user", "content": "Summarize the latest AI news."}
    ],
    "include_thoughts": true,
    "reasoning_effort": "high"
  }'

Structured output:

{
  "model": "gemini-3-pro-preview",
  "messages": [
    {"role": "user", "content": "Extract the title and sentiment."}
  ],
  "response_format": {
    "type": "json_schema",
    "json_schema": {
      "name": "article_summary",
      "schema": {
        "type": "object",
        "properties": {
          "title": {"type": "string"},
          "sentiment": {"type": "string"}
        },
        "required": ["title", "sentiment"]
      }
    }
  }
}

Parameters

Parameter Type Required Description
model string Yes Model ID: gemini-2.5-flash, gemini-2.5-pro, gemini-3.1-pro-preview, gemini-3-flash-preview, or gemini-3-pro-preview
messages array Yes Conversation messages with role and content
tools array No Tool definitions. Google Search uses googleSearch; custom functions follow OpenAI-style tool objects
stream boolean No Enable SSE streaming
include_thoughts boolean No Include Gemini thought traces in the response
reasoning_effort string No low or high; supported on all Gemini models here except gemini-2.5-flash
response_format object No Structured output schema. response_format.type must be json_schema

Notes

Additional Examples

{
  "model": "gemini-3.1-pro-preview",
  "messages": [
    {"role": "user", "content": "Summarize the latest market news."}
  ],
  "include_thoughts": true,
  "reasoning_effort": "high",
  "tools": [
    {"type": "function", "function": {"name": "googleSearch"}}
  ]
}

Gemini Contents Streaming

Endpoint: POST https://runapi.ai/v1beta/models/gemini-3-flash-preview:streamGenerateContent or POST https://runapi.ai/v1beta/models/gemini-3.5-flash:streamGenerateContent

Gemini 3 Flash and Gemini 3.5 Flash support contents requests at the streaming endpoint. Model is inferred from the URL path.

{
  "stream": true,
  "contents": [
    {
      "role": "user",
      "parts": [
        { "text": "What is the weather in Beijing today?" }
      ]
    }
  ],
  "tools": [
    {
      "functionDeclarations": [
        {
          "name": "get_weather_forecast",
          "description": "Get the weather forecast for a given location",
          "parameters": {
            "type": "OBJECT",
            "properties": {
              "location": { "type": "STRING" }
            },
            "required": ["location"]
          }
        }
      ]
    }
  ],
  "generationConfig": {
    "thinkingConfig": {
      "includeThoughts": true,
      "thinkingLevel": "high"
    }
  }
}
{
  "model": "gemini-3-flash-preview",
  "messages": [
    {"role": "user", "content": "Call a tool if needed."}
  ],
  "reasoning_effort": "low",
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "extract_entities",
        "parameters": {
          "type": "object"
        }
      }
    }
  ]
}

DeepSeek

DeepSeek's reasoning-first language models are available through RunAPI on two surfaces: the OpenAI-compatible Chat Completions API and the Anthropic-compatible Messages API. Point either SDK at RunAPI and pass a DeepSeek model id.

Models: deepseek-v4-flash (fast, low-cost; optional thinking mode) and deepseek-v4-pro (frontier reasoning and agentic work).

SDK Quickstart

OpenAI SDK — Chat Completions (https://runapi.ai/v1):

curl https://runapi.ai/v1/chat/completions \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "deepseek-v4-flash",
    "messages": [{"role": "user", "content": "Hello!"}]
  }'
from openai import OpenAI

client = OpenAI(api_key="YOUR_API_TOKEN", base_url="https://runapi.ai/v1")
resp = client.chat.completions.create(
    model="deepseek-v4-flash",
    messages=[{"role": "user", "content": "Hello!"}],
)
print(resp.choices[0].message.content)
import OpenAI from 'openai';

const client = new OpenAI({ apiKey: 'YOUR_API_TOKEN', baseURL: 'https://runapi.ai/v1' });
const resp = await client.chat.completions.create({
  model: 'deepseek-v4-flash',
  messages: [{ role: 'user', content: 'Hello!' }],
});
console.log(resp.choices[0].message.content);

Anthropic SDK — Messages (https://runapi.ai):

import anthropic

client = anthropic.Anthropic(api_key="YOUR_API_TOKEN", base_url="https://runapi.ai")
msg = client.messages.create(
    model="deepseek-v4-flash",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Hello!"}],
)
print(msg.content[0].text)

Models

Model Description
deepseek-v4-flash Fast, low-cost tier. Thinking (reasoning) mode is an optional request parameter.
deepseek-v4-pro Frontier reasoning for the most complex and agentic workloads.

Both models appear in GET /v1/models under both the Anthropic and OpenAI SDK list formats.

Billing

Token-based: credits are calculated from actual input/output token usage. Cached prompt tokens are billed at a reduced cache-read rate.

File Upload

Uploaded files and their returned download_url links are temporary and expire after 24 hours.

Upload via URL

Download a file from a URL and upload it to storage.

HTTP Request

POST https://runapi.ai/api/v1/files/from_url

Request Parameters

Parameter Type Required Description
file_url string Yes HTTPS URL of the file to download
file_name string No Custom filename for the uploaded file

Example Request

Upload file from URL:

curl -X POST "https://runapi.ai/api/v1/files/from_url" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "file_url": "https://cdn.runapi.ai/public/samples/image.jpg",
    "file_name": "downloaded-image.png"
  }'
require 'net/http'
require 'uri'
require 'json'

uri = URI('https://runapi.ai/api/v1/files/from_url')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
request['Content-Type'] = 'application/json'
request.body = {
  file_url: 'https://cdn.runapi.ai/public/samples/image.jpg',
  file_name: 'downloaded-image.png'
}.to_json

response = http.request(request)
puts response.body
import requests

headers = {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
}

data = {
    'file_url': 'https://cdn.runapi.ai/public/samples/image.jpg',
    'file_name': 'downloaded-image.png'
}

response = requests.post(
    'https://runapi.ai/api/v1/files/from_url',
    headers=headers,
    json=data
)
print(response.json())
const data = {
  file_url: 'https://cdn.runapi.ai/public/samples/image.jpg',
  file_name: 'downloaded-image.png'
};

fetch('https://runapi.ai/api/v1/files/from_url', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
})
  .then(response => response.json())
  .then(data => console.log(data));

File Limits

Security

Response

HTTP 201 - Upload successful:

{
  "file_name": "downloaded-image.png",
  "download_url": "https://your-cdn.com/...",
  "file_size": 204800,
  "mime_type": "image/png",
  "uploaded_at": "2025-01-24T10:30:00Z"
}

The returned download_url can be used as upload_url in audio endpoints (for example, Suno). The link is temporary and expires after 24 hours.

Error Responses

Error example:

{ "error": "Missing required parameter: file_url" }

Upload via Stream

Upload a file directly using multipart/form-data.

HTTP Request

POST https://runapi.ai/api/v1/files/from_stream

Request Parameters

Parameter Type Required Description
file file Yes The file to upload
file_name string No Custom filename for the uploaded file

Example Request

Upload file from stream:

curl -X POST "https://runapi.ai/api/v1/files/from_stream" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: multipart/form-data" \
  -F "file=@/path/to/file.png" \
  -F "file_name=my-uploaded-image.png"
require 'net/http'
require 'uri'

uri = URI('https://runapi.ai/api/v1/files/from_stream')
request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
form_data = [
  ['file', File.open('/path/to/file.png')],
  ['file_name', 'my-uploaded-image.png']
]
request.set_form(form_data, 'multipart/form-data')

http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
response = http.request(request)
puts response.body
import requests

headers = {
    'Authorization': 'Bearer YOUR_API_TOKEN'
}

files = {
    'file': open('/path/to/file.png', 'rb')
}

data = {
    'file_name': 'my-uploaded-image.png'
}

response = requests.post(
    'https://runapi.ai/api/v1/files/from_stream',
    headers=headers,
    files=files,
    data=data
)
print(response.json())
const formData = new FormData();
formData.append('file', fileInput.files[0]);
formData.append('file_name', 'my-uploaded-image.png');

fetch('https://runapi.ai/api/v1/files/from_stream', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN'
  },
  body: formData
})
  .then(response => response.json())
  .then(data => console.log(data));

File Limits

Response

HTTP 201 - Upload successful:

{
  "file_name": "my-uploaded-image.png",
  "download_url": "https://your-cdn.com/...",
  "file_size": 204800,
  "mime_type": "image/png",
  "uploaded_at": "2025-01-24T10:30:00Z"
}

The returned download_url is temporary and expires after 24 hours.

Error Responses

Error example:

{ "error": "Missing required parameter: file" }

Upload via Base64

Upload a file from Base64 encoded data.

HTTP Request

POST https://runapi.ai/api/v1/files/from_base64

Request Parameters

Parameter Type Required Description
base64_data string Yes Base64 encoded file data (with or without data URL prefix)
file_name string No Custom filename for the uploaded file

Example Request

Upload file from Base64:

curl -X POST "https://runapi.ai/api/v1/files/from_base64" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "base64_data": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA...",
    "file_name": "base64-image.png"
  }'
require 'net/http'
require 'uri'
require 'json'

uri = URI('https://runapi.ai/api/v1/files/from_base64')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
request['Content-Type'] = 'application/json'
request.body = {
  base64_data: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA...',
  file_name: 'base64-image.png'
}.to_json

response = http.request(request)
puts response.body
import requests

headers = {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
}

data = {
    'base64_data': 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA...',
    'file_name': 'base64-image.png'
}

response = requests.post(
    'https://runapi.ai/api/v1/files/from_base64',
    headers=headers,
    json=data
)
print(response.json())
const data = {
  base64_data: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA...',
  file_name: 'base64-image.png'
};

fetch('https://runapi.ai/api/v1/files/from_base64', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
})
  .then(response => response.json())
  .then(data => console.log(data));

File Limits

Base64 Format

Response

HTTP 201 - Upload successful:

{
  "file_name": "base64-image.png",
  "download_url": "https://your-cdn.com/...",
  "file_size": 68,
  "mime_type": "image/png",
  "uploaded_at": "2025-01-24T10:30:00Z"
}

The returned download_url is temporary and expires after 24 hours.

Error Responses

Error example:

{ "error": "Missing required parameter: base64_data" }

Common

Get Balance

Retrieve the current account balance and usage statistics.

HTTP Request

GET https://runapi.ai/api/v1/me/balance

Authentication

Include your API key in the Authorization header:

Authorization: Bearer YOUR_API_TOKEN

Example Request

Get user credits:

curl "https://runapi.ai/api/v1/me/balance" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
require 'net/http'
require 'uri'

uri = URI('https://runapi.ai/api/v1/me/balance')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request['Authorization'] = 'Bearer YOUR_API_TOKEN'

response = http.request(request)
puts response.body
import requests

headers = {
    'Authorization': 'Bearer YOUR_API_TOKEN'
}

response = requests.get(
    'https://runapi.ai/api/v1/me/balance',
    headers=headers
)
print(response.json())
fetch('https://runapi.ai/api/v1/me/balance', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN'
  }
})
  .then(response => response.json())
  .then(data => console.log(data));

Response

HTTP 200 - Success:

{
  "balance_cents": 10000,
  "spent_cents_today": 150,
  "spent_cents_total": 5420
}

Response Fields

Error Response

Error example:

{
  "error": "Unauthorized"
}

Notes

Management Keys

Use management keys to create, list, update, and revoke standard API keys programmatically.

Authentication

Include your management key in the Authorization header:

Authorization: Bearer YOUR_MANAGEMENT_KEY

Generate management keys from the Management Keys page.

List API Keys

HTTP Request

GET https://runapi.ai/api/v1/keys

Example Request

curl "https://runapi.ai/api/v1/keys" \
  -H "Authorization: Bearer YOUR_MANAGEMENT_KEY"

Response

[
  {
    "name": "Production",
    "last_used_at": "2026-04-08T02:58:00Z",
    "created_at": "2026-04-08T02:58:00Z",
    "credit_limit_cents": 100,
    "credit_limit_reset_interval": "daily",
    "allowed_models": null,
    "enabled": true,
    "id": "token_123",
    "masked_token": "abcd••••••••wxyz",
    "guardrail_id": "guardrail_abc123"
  }
]

Create API Key

HTTP Request

POST https://runapi.ai/api/v1/keys

Request Parameters

Parameter Type Required Description
name string No Friendly name for the API key
credit_limit_cents integer No Per-key spending cap in USD cents
credit_limit_reset_interval string No Reset cadence: daily, weekly, or monthly. Omit to make credit_limit_cents a lifetime cap.
allowed_models string[] No Restrict this key to a fixed set of models (e.g. ["gpt-5.4", "claude-opus-4-6"]). Omit, send null, or an empty array to allow all models.
enabled boolean No When false, requests authenticated with this key are rejected with 401 Unauthorized. Defaults to true.
guardrail_id string No Attach a guardrail policy to the new key (e.g. "guardrail_abc123").

When credit_limit_cents is set without credit_limit_reset_interval, the cap is a lifetime budget that does not refresh. With an interval, the cap resets each daily/weekly/monthly window.

When allowed_models is set, requests using a model outside the list are rejected with 422 Unprocessable Content.

To attach a reusable guardrail at creation time, include guardrail_id. See Guardrails below for the full lifecycle.

Example Request

curl -X POST "https://runapi.ai/api/v1/keys" \
  -H "Authorization: Bearer YOUR_MANAGEMENT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Production",
    "credit_limit_cents": 100,
    "credit_limit_reset_interval": "daily",
    "allowed_models": ["gpt-5.4", "claude-opus-4-6"]
  }'

Response

{
  "name": "Production",
  "last_used_at": null,
  "created_at": "2026-04-08T02:58:00Z",
  "credit_limit_cents": 100,
  "credit_limit_reset_interval": "daily",
  "allowed_models": ["gpt-5.4", "claude-opus-4-6"],
  "enabled": true,
  "id": "token_123",
  "masked_token": "abcd••••••••wxyz",
  "guardrail_id": "guardrail_abc123",
  "key": "abcd1234efgh5678"
}

The key value is only returned once when the API key is created.

Get API Key

HTTP Request

GET https://runapi.ai/api/v1/keys/:id

Example Request

curl "https://runapi.ai/api/v1/keys/token_123" \
  -H "Authorization: Bearer YOUR_MANAGEMENT_KEY"

Response

{
  "name": "Production",
  "last_used_at": null,
  "created_at": "2026-04-08T02:58:00Z",
  "credit_limit_cents": 100,
  "credit_limit_reset_interval": "daily",
  "allowed_models": ["gpt-5.4", "claude-opus-4-6"],
  "enabled": true,
  "id": "token_123",
  "masked_token": "abcd••••••••wxyz",
  "guardrail_id": "guardrail_abc123",
  "credit_usage_cents_total": 25,
  "credit_usage_cents_today": 25,
  "credit_usage_cents_this_week": 25,
  "credit_usage_cents_this_month": 25
}

Update API Key

HTTP Request

PATCH https://runapi.ai/api/v1/keys/:id

Example Request

curl -X PATCH "https://runapi.ai/api/v1/keys/token_123" \
  -H "Authorization: Bearer YOUR_MANAGEMENT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Production (rotated)",
    "credit_limit_cents": 500,
    "credit_limit_reset_interval": "weekly",
    "allowed_models": ["gpt-5.4"]
  }'

To clear a limit, send credit_limit_cents as null or an empty string.

allowed_models is overwritten absolutely on each PATCH. Send null or [] to clear the whitelist; omit the field to leave it unchanged.

Send "enabled": false to immediately revoke authentication for this key, or "enabled": true to re-enable it. The flag is independent of credit_limit_cents — clearing the cap and disabling the key in the same request both take effect.

To replace or remove the attached guardrail, use the Guardrail Assignments endpoints — PATCH /api/v1/keys/:id does not accept guardrail_id.

Delete API Key

HTTP Request

DELETE https://runapi.ai/api/v1/keys/:id

Example Request

curl -X DELETE "https://runapi.ai/api/v1/keys/token_123" \
  -H "Authorization: Bearer YOUR_MANAGEMENT_KEY"

Response

HTTP 204 No Content

Credit Limit Notes

Guardrails

Guardrails are reusable policy templates owned by an account. A guardrail can specify model and provider access rules (allowlist or blocklist), a total spending cap, and per-model spending caps with their own reset cadence. Each API key or account member may have at most one direct guardrail; on every request, the key's own limits and any attached guardrails are checked independently.

Any management key can create guardrails in its account. Account admins can update or delete any guardrail. Non-admin management keys can update or delete guardrails they created only while those guardrails are assigned solely to their own API keys; shared-key assignments and member-level assignments require admin.

List Guardrails

HTTP Request

GET https://runapi.ai/api/v1/guardrails

Response

{
  "guardrails": [
    {
      "id": "guardrail_abc123",
      "name": "Tier 1",
      "description": "Standard developer tier",
      "enabled": true,
      "credit_limit_cents": 100000,
      "credit_limit_reset_interval": "monthly",
      "allowed_models": ["gpt-5.4", "claude-sonnet-4-6"],
      "blocked_models": [],
      "allowed_providers": [],
      "blocked_providers": [],
      "model_budgets": [
        {
          "match_mode": "exclude",
          "models": ["gpt-5.4", "claude-sonnet-4-6"],
          "credit_limit_cents": 1000,
          "credit_limit_reset_interval": null
        }
      ],
      "assignment_count": 4,
      "created_at": "2026-05-05T10:00:00Z"
    }
  ]
}

Create Guardrail

HTTP Request

POST https://runapi.ai/api/v1/guardrails

Request Parameters

Parameter Type Required Description
name string Yes Unique guardrail name within the account (case-insensitive)
description string No Free-form description
enabled boolean No Defaults to true
credit_limit_cents integer No Total spend cap across all keys/members assigned to this guardrail. Must be set together with credit_limit_reset_interval.
credit_limit_reset_interval string No daily, weekly, or monthly
allowed_models string[] No Allowlist of public model identifiers. Empty/null means "all allowed".
blocked_models string[] No Blocklist; always wins over the allowlist.
allowed_providers string[] No Allowlist of provider names. Empty/null means "all allowed".
blocked_providers string[] No Blocklist of provider names.
model_budgets object[] No Scoped model spend caps. Each entry: `{ "match_mode": "include"

Model budgets only count requests in their scope; they do not reject requests outside the scope. include counts only listed models. exclude counts every model except listed models, which is fail-safe for future model launches because new models are counted by default.

Example Request

curl -X POST "https://runapi.ai/api/v1/guardrails" \
  -H "Authorization: Bearer YOUR_MANAGEMENT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Tier 1",
    "credit_limit_cents": 100000,
    "credit_limit_reset_interval": "monthly",
    "allowed_models": ["gpt-5.4", "claude-sonnet-4-6"],
    "model_budgets": [
      {
        "match_mode": "exclude",
        "models": ["gpt-5.4", "claude-sonnet-4-6"],
        "credit_limit_cents": 1000,
        "credit_limit_reset_interval": null
      }
    ]
  }'

Response

201 Created — the response body is identical to the list shape above, wrapped in {"guardrail": {...}}.

Get Guardrail

GET https://runapi.ai/api/v1/guardrails/:id

Returns {"guardrail": {...}}.

Update Guardrail

PATCH https://runapi.ai/api/v1/guardrails/:id

Account admins can update any guardrail. Non-admin management keys can update guardrails they created only while those guardrails are assigned solely to their own API keys.

Scalar fields (name, description, enabled, credit_limit_cents, credit_limit_reset_interval) are overwritten when present and preserved when omitted.

Rule arrays (allowed_models, blocked_models, allowed_providers, blocked_providers) and model_budgets are absolute replacement when present. Send null or [] to clear; omit to leave unchanged.

Delete Guardrail

DELETE https://runapi.ai/api/v1/guardrails/:id

Account admins can delete any guardrail. Non-admin management keys can delete guardrails they created only while those guardrails are assigned solely to their own API keys.

Soft-deletes the guardrail and destroys all its assignments. Returns 204 No Content. The name becomes available for reuse.

Guardrail Assignments

A guardrail assignment links a single guardrail to a single API key OR a single account member. Each target may have at most one direct assignment.

List Assignments

GET https://runapi.ai/api/v1/guardrail_assignments

Returns {"guardrail_assignments": [...]}. Account admins see all assignments in the account; non-admin management keys see only assignments on their own API keys.

Create Assignment

POST https://runapi.ai/api/v1/guardrail_assignments

Request Parameters

Parameter Type Required Description
guardrail_id string Yes Prefix ID of the guardrail (e.g. guardrail_abc123)
api_token_id string One of Prefix ID of the API key to attach the guardrail to
account_user_id string One of Prefix ID of the account member (admin only)

Provide exactly one of api_token_id or account_user_id.

Permissions

Replacement

To replace the guardrail attached to a key or member, DELETE the existing assignment and create a new one. 422 Unprocessable Content is returned if the target already has a direct assignment.

Response

{
  "guardrail_assignment": {
    "id": "guardrail_assignment_xyz",
    "guardrail_id": "guardrail_abc123",
    "api_token_id": "token_123",
    "account_user_id": null,
    "created_at": "2026-05-05T10:00:00Z"
  }
}

Delete Assignment

DELETE https://runapi.ai/api/v1/guardrail_assignments/:id

Returns 204 No Content. Removes the guardrail from its target without affecting the guardrail or the target itself.

Errors

The runapi.ai API uses standard HTTP response codes to indicate the success or failure of requests.

HTTP Status Codes

Status Code Meaning
200 OK - Request succeeded
201 Created - Resource created successfully
400 Bad Request - Invalid parameters or malformed request
401 Unauthorized - Invalid or missing API key
402 Payment Required - Account has insufficient credits
403 Forbidden - Valid key but insufficient permissions or API key credit limit reached
404 Not Found - Resource doesn't exist
422 Unprocessable Entity - Validation failed
429 Too Many Requests - Rate limit exceeded
500 Internal Server Error - Something went wrong on our end
503 Service Unavailable - Temporary service interruption

Error Response Format

Error response example:

{
  "error": "Missing required parameter: prompt"
}

All error responses follow a simple JSON format with an error field containing a human-readable error message.

Common Error Messages

Status Code Error Message Description
400 Missing required parameter: xxx Required parameter is missing
401 Unauthorized Invalid or missing API key
402 Insufficient credits Account has insufficient credits
403 API key credit limit exceeded The API key reached its configured spend limit for the current reset period
404 Task not found The specified task doesn't exist
404 Record does not exist The requested resource doesn't exist
408 Download timeout File download timed out
413 File size exceeds maximum allowed size Uploaded file is too large (max 10MB)
415 File type not supported Unsupported file type
422 Records are being generated Resource is still processing
500 Internal server error Server encountered an error

Task-Specific Errors

When a task fails, the error message is included in the task response:

{
  "id": "task-id",
  "status": "failed",
  "error": "Generation failed due to content policy violation"
}