ProductApril 10, 2026Seedance Team13 min read

OmniHuman v1.5 API: Programmatic Avatar Video Generation

A developer guide to the OmniHuman v1.5 API on Seedance. Learn endpoint structure, authentication, request parameters, response handling, webhook integration, and best practices for building automated avatar video workflows.

OmniHuman v1.5 API: Programmatic Avatar Video Generation

Running OmniHuman v1.5 through the Seedance UI is great for one-off creation. For high-volume workflows — personalized sales outreach, multilingual rollouts, CMS-driven video generation, automated news digests — you want the API. This guide walks through authentication, endpoints, request structure, webhook handling, and production patterns. Every generation costs the same 960 credits ($9.60) whether you invoke it via UI or API.

TL;DR

TL;DR

  • Programmatically generate OmniHuman v1.5 videos via the Seedance REST API
  • Same $9.60 per generation pricing as the UI — no API premium
  • Async generation with webhook or polling-based result retrieval
  • Ideal for personalized sales video, automated training libraries, multilingual rollouts
  • Authentication via API key from your Seedance dashboard

Why Use the API

The API unlocks automation patterns the UI cannot match:

  • Batch generation. Run 100+ videos in a single pipeline run.
  • Dynamic personalization. Pull data from a CRM and generate a video per prospect.
  • Scheduled workflows. Daily news digests, weekly summary videos, triggered updates.
  • Integration with existing stacks. Node.js, Python, Go, Ruby — any language with HTTP can call it.
  • Reproducible production. Version-controlled scripts instead of manual UI clicks.

If your use case involves more than 10 videos with similar structure, the API is worth setting up.

👤

Create your AI presenter now

Turn one photo + audio into a lifelike talking video. $9.60 per video, no subscription.

Try OmniHuman Free

Authentication

Seedance API requests authenticate via an API key passed in the Authorization header as a Bearer token.

Getting Your API Key

  1. Sign in at seedance.it.com
  2. Navigate to your account settings
  3. Find the API section
  4. Generate a new API key
  5. Store it securely — treat it like a password

Never commit your API key to source control. Use environment variables:

export SEEDANCE_API_KEY="your_api_key_here"

Authentication Header

Every request includes:

Authorization: Bearer YOUR_SEEDANCE_API_KEY
Content-Type: application/json

Endpoint Structure

The OmniHuman v1.5 API follows standard async generation patterns:

  • POST to create a generation job
  • GET to poll for status and results
  • Webhook for async delivery (recommended for production)

Base URL

https://api.seedance.it.com/v1

Key Endpoints

| Method | Path | Purpose | |---|---|---| | POST | /omnihuman/generate | Submit a new generation job | | GET | /jobs/{job_id} | Poll for job status and result | | POST | /webhooks | Configure webhook endpoints |

Consult the live Seedance API documentation for exact endpoint paths, as paths may evolve.

Submitting a Generation Job

Request Structure

{
  "model": "omnihuman-v1.5",
  "image_url": "https://example.com/portrait.jpg",
  "audio_url": "https://example.com/speech.mp3",
  "prompt": "Modern corporate office with soft natural lighting, medium close-up framing head and shoulders, professional broadcast style",
  "resolution": "1080p",
  "turbo_mode": false,
  "webhook_url": "https://yourapp.com/webhooks/seedance"
}

Parameter Reference

| Parameter | Type | Required | Description | |---|---|---|---| | model | string | Yes | Must be "omnihuman-v1.5" | | image_url | string | Yes | Publicly accessible URL to reference portrait | | audio_url | string | Yes | Publicly accessible URL to audio file | | prompt | string | Yes | Scene description for background, lighting, framing | | resolution | string | No | "720p" or "1080p" (default: "720p") | | turbo_mode | boolean | No | Enable faster generation (default: false) | | webhook_url | string | No | URL to receive async completion notification |

Input File Requirements

Image:

  • Formats: JPEG, PNG
  • Resolution: 512x512 minimum, 1024x1024+ recommended
  • Accessible via public HTTPS URL

Audio:

  • Formats: MP3, WAV, M4A
  • Duration: ≤60s for 720p, ≤30s for 1080p
  • Accessible via public HTTPS URL

If your files are not already hosted publicly, upload them to S3, Cloudflare R2, Google Cloud Storage, or similar before making the API call.

Example Request in Python

import os
import requests

SEEDANCE_API_KEY = os.environ["SEEDANCE_API_KEY"]
BASE_URL = "https://api.seedance.it.com/v1"

def create_omnihuman_video(image_url, audio_url, prompt,
                           resolution="1080p", turbo=False):
    headers = {
        "Authorization": f"Bearer {SEEDANCE_API_KEY}",
        "Content-Type": "application/json",
    }
    payload = {
        "model": "omnihuman-v1.5",
        "image_url": image_url,
        "audio_url": audio_url,
        "prompt": prompt,
        "resolution": resolution,
        "turbo_mode": turbo,
    }
    response = requests.post(
        f"{BASE_URL}/omnihuman/generate",
        json=payload,
        headers=headers,
    )
    response.raise_for_status()
    return response.json()

job = create_omnihuman_video(
    image_url="https://cdn.example.com/ceo.jpg",
    audio_url="https://cdn.example.com/weekly-update.mp3",
    prompt="Corporate office with warm lighting, medium close-up, professional style",
)
print(f"Job submitted: {job['job_id']}")

Example Request in Node.js

import fetch from "node-fetch";

const SEEDANCE_API_KEY = process.env.SEEDANCE_API_KEY;
const BASE_URL = "https://api.seedance.it.com/v1";

async function createOmnihumanVideo({
  imageUrl,
  audioUrl,
  prompt,
  resolution = "1080p",
  turbo = false,
}) {
  const response = await fetch(`${BASE_URL}/omnihuman/generate`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${SEEDANCE_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      model: "omnihuman-v1.5",
      image_url: imageUrl,
      audio_url: audioUrl,
      prompt,
      resolution,
      turbo_mode: turbo,
    }),
  });

  if (!response.ok) {
    throw new Error(`Seedance API error: ${response.status}`);
  }
  return response.json();
}

const job = await createOmnihumanVideo({
  imageUrl: "https://cdn.example.com/ceo.jpg",
  audioUrl: "https://cdn.example.com/update.mp3",
  prompt: "Modern office, soft lighting, medium close-up",
});
console.log(`Job submitted: ${job.job_id}`);

Response Format

{
  "job_id": "job_abc123xyz",
  "status": "queued",
  "created_at": "2026-04-10T14:23:00Z",
  "estimated_credits": 960
}

The job_id is what you use for polling or correlating webhook deliveries.

Polling for Results

If you are not using webhooks, poll the job status endpoint until the job completes.

import time

def wait_for_video(job_id, timeout_seconds=600, poll_interval=5):
    headers = {"Authorization": f"Bearer {SEEDANCE_API_KEY}"}
    deadline = time.time() + timeout_seconds

    while time.time() < deadline:
        response = requests.get(
            f"{BASE_URL}/jobs/{job_id}",
            headers=headers,
        )
        response.raise_for_status()
        data = response.json()
        status = data["status"]

        if status == "completed":
            return data["result"]["video_url"]
        if status == "failed":
            raise Exception(f"Generation failed: {data.get('error')}")

        time.sleep(poll_interval)

    raise TimeoutError("Job did not complete within timeout")

video_url = wait_for_video(job["job_id"])
print(f"Video ready: {video_url}")

Job Status Values

| Status | Meaning | |---|---| | queued | Waiting to start | | processing | Generation in progress | | completed | Video ready, URL available | | failed | Generation failed, check error field |

Using Webhooks (Recommended for Production)

Webhooks eliminate polling and let you build event-driven pipelines.

Configuring a Webhook

Pass webhook_url in your generation request. Seedance POSTs to that URL when the job completes.

Webhook Payload

{
  "event": "job.completed",
  "job_id": "job_abc123xyz",
  "status": "completed",
  "result": {
    "video_url": "https://cdn.seedance.it.com/outputs/video_abc123.mp4",
    "resolution": "1080p",
    "duration_seconds": 28.5
  },
  "credits_used": 960,
  "completed_at": "2026-04-10T14:26:45Z"
}

Webhook Handler Example

from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route("/webhooks/seedance", methods=["POST"])
def seedance_webhook():
    payload = request.get_json()

    if payload.get("event") == "job.completed":
        job_id = payload["job_id"]
        video_url = payload["result"]["video_url"]

        # Your business logic: download video, notify users,
        # trigger downstream workflows, etc.
        handle_completed_video(job_id, video_url)

    return jsonify({"received": True}), 200

Webhook Security

Verify webhook signatures if Seedance provides a signing secret. Always validate that webhooks come from Seedance before acting on them.

Ready to try OmniHuman v1.5? Start creating free →

An AI-generated talking head from OmniHuman v1.5

Want a presenter like this? Try OmniHuman free →

Production Patterns

Pattern 1: Personalized Sales Video Pipeline

Generate one video per prospect with dynamic script variables.

def generate_sales_video_for_prospect(prospect):
    script = render_template("sales_template.txt", {
        "first_name": prospect["first_name"],
        "company": prospect["company"],
        "trigger": prospect["trigger_event"],
    })

    audio_url = generate_tts(script)

    job = create_omnihuman_video(
        image_url=YOUR_SDR_PHOTO_URL,
        audio_url=audio_url,
        prompt=STANDARD_SCENE_PROMPT,
        resolution="1080p",
    )
    return job["job_id"]

prospects = load_prospects_from_crm()
for prospect in prospects:
    generate_sales_video_for_prospect(prospect)

See the sales videos guide for scripting and distribution.

Pattern 2: Multilingual Content Rollout

Generate the same message in multiple languages, same photo.

languages = [
    ("en", "english_audio.mp3"),
    ("es", "spanish_audio.mp3"),
    ("pt", "portuguese_audio.mp3"),
    ("fr", "french_audio.mp3"),
    ("de", "german_audio.mp3"),
]

jobs = []
for lang_code, audio_file in languages:
    audio_url = upload_to_cdn(audio_file)
    job = create_omnihuman_video(
        image_url=SPOKESPERSON_PHOTO_URL,
        audio_url=audio_url,
        prompt=STANDARD_PROMPT,
    )
    jobs.append((lang_code, job["job_id"]))

See the multilingual guide for voice and translation tips.

Pattern 3: Daily News Digest Automation

Scheduled pipeline that pulls headlines, generates TTS, and produces a daily video.

from datetime import datetime

def daily_news_digest():
    headlines = fetch_top_headlines()
    script = format_headlines_as_script(headlines)
    audio_url = generate_tts(script, voice="broadcast_news")

    job = create_omnihuman_video(
        image_url=NEWS_ANCHOR_PHOTO_URL,
        audio_url=audio_url,
        prompt="Professional news studio, broadcast style, medium close-up",
        resolution="720p",
    )
    return job["job_id"]

# Schedule via cron, Airflow, or your workflow tool
daily_news_digest()

See the news anchor guide.

Pattern 4: CMS-Triggered Video Generation

When a new blog post or product is published, generate a companion video.

@app.route("/cms/published", methods=["POST"])
def on_content_published():
    content = request.get_json()
    script = summarize_content(content["body"])
    audio_url = generate_tts(script)

    job = create_omnihuman_video(
        image_url=BRAND_SPOKESPERSON_PHOTO,
        audio_url=audio_url,
        prompt=BRAND_SCENE_PROMPT,
        webhook_url="https://yourapp.com/webhooks/seedance",
    )
    store_job_mapping(content["id"], job["job_id"])
    return {"ok": True}

Error Handling Best Practices

Retry with Exponential Backoff

Network errors and transient failures should trigger retries, not immediate abandonment.

import time

def create_with_retry(params, max_retries=3):
    delay = 2
    for attempt in range(max_retries):
        try:
            return create_omnihuman_video(**params)
        except requests.RequestException as e:
            if attempt == max_retries - 1:
                raise
            time.sleep(delay)
            delay *= 2

Validate Inputs Before Submitting

Save credits by validating before each API call:

  • Image URL returns 200 and content-type image/*
  • Audio URL returns 200 and content-type audio/*
  • Audio duration is within the limit for the chosen resolution
  • Prompt is not empty

Handle Rate Limits

The API enforces rate limits. Respect 429 responses and back off appropriately.

Monitor Credit Balance

Check your credit balance before large batch runs. Running out of credits mid-batch is avoidable.

Cost Management

Every API-generated video costs 960 credits ($9.60). The same credit pack that powers the UI powers the API:

| Tier | Price | Credits | Effective Cost per API Call | |---|---|---|---| | Starter | $10 | 1,050 | ~$9.14 | | Popular | $25 | 2,750 | ~$8.73 | | Pro | $50 | 5,750 | ~$8.35 | | Max | $100 | 12,000 | ~$8.00 |

For heavy API workloads, the Max tier gives you the best effective cost per generation. See the pricing guide for details.

Estimating Project Cost

Before starting a batch run, calculate total cost:

total_cost = number_of_videos * 9.60

A 1,000-video batch: $9,600 base rate, ~$8,000 on Max tier. Budget accordingly.

⚙️

API pricing = UI pricing. No upcharge.

No per-seat fees, no API tier lock-in, no monthly minimum. Spin up a batch when you need it, walk away when you don't.

Get Your API Key

Observability

For production workflows, track these metrics:

  • Success rate — % of jobs that complete successfully
  • Average generation time — for capacity planning
  • Credits consumed — rolling totals for budget tracking
  • Webhook delivery rate — detect webhook delivery failures
  • Error categorization — group failures by cause

Log job IDs alongside your internal correlation IDs for debugging.

Security Best Practices

  • Never expose your API key client-side. Always call the API from your backend.
  • Use environment variables or a secrets manager. Never commit keys to source control.
  • Rotate keys periodically. Treat them like any other credential.
  • Validate webhook signatures when available.
  • Use HTTPS for all image and audio URLs you pass to the API.
  • Scope webhook endpoints so only legitimate Seedance payloads are processed.

Getting Started with the API

  1. Sign up for Seedance and collect your 50 free credits
  2. Purchase at least a Starter pack ($10) to have enough for a test generation
  3. Generate your API key in the dashboard
  4. Prep a test image and audio file, upload to a public URL
  5. Make your first API call using the examples above
  6. Poll or wait for webhook to retrieve the video URL
  7. Build your production pipeline

For related reading, see the complete OmniHuman v1.5 guide, pricing breakdown, sales videos guide, and multilingual guide.

Ready to try OmniHuman v1.5? Start creating free →

Start Creating with OmniHuman v1.5

Turn one photo + audio into a lifelike talking video. Pay-per-use, no subscription.

50 free credits on signup. No credit card. No subscription.