WWeydub API

API guide

Demo Scenarios

Use these scenarios when you want an AI coding assistant, bot, or internal automation tool to prove that a Weydub API integration works end to end.

The scenarios use public demo assets and the same double-MD5 signing model described in Auth and signing. Provide credentials through environment variables only.

Demo Assets

AssetURLRecommended Tests
English source videohttp://gc9.cdn.izhaoli.cn/ghostcut_demo/TextRemoval_Dubbing_Eng.mp4Advanced subtitle/text removal; English-to-Spanish video translation.
Chinese source videohttp://gc9.cdn.izhaoli.cn/ghostcut_demo/HighEmotion_Dubbing_cn2en.mp4High-emotion voice cloning and Chinese-to-English dubbing.
Chinese annotation JSONhttp://gc9.cdn.izhaoli.cn/ghostcut_demo/HighEmotion_Dubbing_cn2en.jsonCustomer input for high-emotion voice cloning.

Environment

bash
export WEYDUB_APP_KEY="your_app_key"
export WEYDUB_APP_SECRET="your_app_secret"

Scenario 1: Advanced Subtitle And Text Removal

Use the English source video and the Advanced Pro full-screen inpainting model.

json
{
  "urls": ["http://gc9.cdn.izhaoli.cn/ghostcut_demo/TextRemoval_Dubbing_Eng.mp4"],
  "needChineseOcclude": 1,
  "videoInpaintLang": "all",
  "extraOptions": "{\"extra_inpaint_config\":{\"model\":\"advanced_full\"}}"
}

Endpoint:

text
POST /v-w-c/gateway/ve/work/free

Scenario 2: Video Translation With Dubbing

Translate the English source video to Spanish, generate subtitles, and dub it with a high-quality voice.

json
{
  "urls": ["http://gc9.cdn.izhaoli.cn/ghostcut_demo/TextRemoval_Dubbing_Eng.mp4"],
  "needWanyin": 1,
  "sourceLang": "en",
  "lang": "es",
  "wyTaskType": "FULL",
  "wyNeedText": 1,
  "wyVoiceParam": "{\"voice_type\":\"CLONE\",\"character_voices\":[{\"character\":\"role_default\",\"id\":102052}],\"font_param\":{\"style\":\"tpl-31-1-T\",\"font_size\":32,\"position\":0.8}}"
}

Endpoint:

text
POST /v-w-c/gateway/ve/work/free

Scenario 3: High-Emotion Voice Cloning

Use the Chinese video and paired JSON to run Chinese-to-English high-emotion voice cloning. This scenario is best for short drama, film, and character-driven content because the model can preserve actor timbre, emotion, and spatial feeling from the original clip.

json
{
  "urls": ["http://gc9.cdn.izhaoli.cn/ghostcut_demo/HighEmotion_Dubbing_cn2en.mp4"],
  "incorporatePro": true,
  "sourceLang": "zh",
  "lang": "en",
  "extraOptions": "{\"customer_input\":{\"url\":\"http://gc9.cdn.izhaoli.cn/ghostcut_demo/HighEmotion_Dubbing_cn2en.json\"}}"
}

Endpoint:

text
POST /v-w-c/gateway/ve/work/voice/incorporate

Python Template

python
import hashlib
import json
import os
import time

import requests

APP_KEY = os.environ["WEYDUB_APP_KEY"]
APP_SECRET = os.environ["WEYDUB_APP_SECRET"]
BASE_URL = "https://api.zhaoli.com"

DEMO_ENG_VIDEO = "http://gc9.cdn.izhaoli.cn/ghostcut_demo/TextRemoval_Dubbing_Eng.mp4"
DEMO_CN_VIDEO = "http://gc9.cdn.izhaoli.cn/ghostcut_demo/HighEmotion_Dubbing_cn2en.mp4"
DEMO_CN_JSON = "http://gc9.cdn.izhaoli.cn/ghostcut_demo/HighEmotion_Dubbing_cn2en.json"


def api_post(path: str, payload: dict) -> dict:
    body = json.dumps(payload, ensure_ascii=False, separators=(",", ":"))
    body_md5 = hashlib.md5(body.encode("utf-8")).hexdigest()
    app_sign = hashlib.md5((body_md5 + APP_SECRET).encode("utf-8")).hexdigest()
    headers = {
        "Content-Type": "application/json",
        "AppKey": APP_KEY,
        "AppSign": app_sign,
    }
    response = requests.post(f"{BASE_URL}{path}", headers=headers, data=body, timeout=30)
    response.raise_for_status()
    return response.json()


def extract_work_ids(response: dict) -> list[int]:
    body = response.get("body") or {}
    data_list = body.get("dataList") or body.get("content") or []
    if isinstance(data_list, dict):
        data_list = [data_list]
    return [item["id"] for item in data_list if isinstance(item, dict) and item.get("id")]


def wait_for_work(work_id: int) -> dict:
    while True:
        status = api_post("/v-w-c/gateway/ve/work/status", {"idWorks": [work_id]})
        item = ((status.get("body") or {}).get("content") or [{}])[0]
        process_status = item.get("processStatus")
        if process_status == 1:
            return item
        if isinstance(process_status, int) and process_status > 1:
            raise RuntimeError(item.get("errorDetail") or f"Task {work_id} failed")
        print(f"Task {work_id} processing...")
        time.sleep(10)


scenarios = [
    (
        "advanced_text_removal",
        "/v-w-c/gateway/ve/work/free",
        {
            "urls": [DEMO_ENG_VIDEO],
            "needChineseOcclude": 1,
            "videoInpaintLang": "all",
            "extraOptions": json.dumps(
                {"extra_inpaint_config": {"model": "advanced_full"}},
                separators=(",", ":"),
            ),
        },
    ),
    (
        "video_translation_en_to_es",
        "/v-w-c/gateway/ve/work/free",
        {
            "urls": [DEMO_ENG_VIDEO],
            "needWanyin": 1,
            "sourceLang": "en",
            "lang": "es",
            "wyTaskType": "FULL",
            "wyNeedText": 1,
            "wyVoiceParam": json.dumps(
                {
                    "voice_type": "CLONE",
                    "character_voices": [{"character": "role_default", "id": 102052}],
                    "font_param": {"style": "tpl-31-1-T", "font_size": 32, "position": 0.8},
                },
                separators=(",", ":"),
            ),
        },
    ),
    (
        "high_emotion_clone_zh_to_en",
        "/v-w-c/gateway/ve/work/voice/incorporate",
        {
            "urls": [DEMO_CN_VIDEO],
            "incorporatePro": True,
            "sourceLang": "zh",
            "lang": "en",
            "extraOptions": json.dumps(
                {"customer_input": {"url": DEMO_CN_JSON}},
                separators=(",", ":"),
            ),
        },
    ),
]

for name, path, payload in scenarios:
    print(f"Submitting {name}...")
    response = api_post(path, payload)
    print(json.dumps(response, ensure_ascii=False, indent=2))
    for work_id in extract_work_ids(response):
        result = wait_for_work(work_id)
        print(f"{name} done:", result.get("videoUrl") or result.get("tgtSrtUrl") or result)

Local Repo Helper

This repository also includes a safe helper script:

bash
python3 scripts/run-weydub-api-demos.py --dry-run
python3 scripts/run-weydub-api-demos.py --scenario removal --submit

The helper reads WEYDUB_APP_KEY and WEYDUB_APP_SECRET from environment variables. It does not store credentials.

Notes For AI Assistants

  • Keep extraOptions and wyVoiceParam as compact JSON strings.
  • Use json.dumps(..., separators=(",", ":")) before signing.
  • Poll /v-w-c/gateway/ve/work/status with returned work IDs.
  • Prefer callback webhooks for production systems.
  • Never put AppSecret in frontend code or files committed to a repository.