Digital human / editing APIs
Avatar library, digital-human video, lip sync, motion transfer, and social-style editing — all on one sk-gpushare-* key
Register a reusable digital-human avatar from one photo or a short video, then drive it with audio or text to produce video. You can also lip-sync an existing video, transfer the motion from one video onto still portraits, or hand a talking-head video to social-style editing to have subtitle effects, a title, template styling and background music added automatically.
Authentication is identical to every other endpoint — the same sk-gpushare-* key in whichever of the four forms you prefer (x-api-key or x-goog-api-key header, ?key= query, Authorization: Bearer); see Authentication. Everything bills against your account balance (shared by all keys), and an insufficient balance returns 402 quota_exceeded.
| Endpoint | Purpose | Billing |
|---|---|---|
POST /v1/videos/avatars | Register an avatar (async) | per call |
GET /v1/videos/avatars | Your avatar library | free |
GET /v1/videos/avatars/{id} | Check an avatar's creation status | free |
DELETE /v1/videos/avatars/{id} | Delete an avatar | free |
GET /v1/videos/avatars/presets | The platform's built-in avatars | free |
POST /v1/videos/generations | Produce video (digital human / lip sync / motion transfer per second; social-style editing per task) | per second / per task |
GET /v1/videos/generations/{id} | Poll a production task | free |
GET /v1/videos/clip-templates | Social-style editing templates (paginated) | free |
GET /v1/videos/clip-templates/categories | Social-style editing template categories | free |
POST /v1/videos/clip-subtitles | Social-style editing subtitle recognition (synchronous) | per call (currently 0) |
Producing and polling use the same generic video endpoints from the media APIs; only the model and the body fields change. Each variation below comes with a complete example.
1. The avatar library#
POST /v1/videos/avatars#
Register an avatar from a front-facing photo (or a video of the person). This is async: you get a pending record straight away and can only produce video once it polls ready, typically 5–10 minutes upstream.
{
"name": "My presenter",
"source_url": "https://example.com/portrait.jpg",
"source_kind": "image"
}
| Field | Required | Notes |
|---|---|---|
name | yes | 1–20 characters, the avatar's name in your library |
source_url | yes | A publicly reachable direct http(s) link. Upstream fetches the material itself and we offer no upload endpoint — host it yourself (object storage, a CDN, any public direct link) |
source_kind | no | image (default) or video |
Response:
{
"id": "9f1c…",
"name": "My presenter",
"source_kind": "image",
"status": "pending",
"error": null,
"created_at": "2026-07-29T08:12:00+00:00"
}
That id is the avatar reference you'll use from now on — put it in the avatar field when producing video; the underlying upstream identifier is not your concern.
GET /v1/videos/avatars/{id}#
Poll the creation status, every 15–30 seconds.
{ "id": "9f1c…", "name": "My presenter", "status": "ready", "error": null, "created_at": "…" }
status has three states: pending / ready / failed. Failures are refunded in full automatically — the refund uses this record as its evidence, which is why deletion is blocked while it is pending.
GET /v1/videos/avatars#
Lists this account's avatars (up to 200, newest first).
DELETE /v1/videos/avatars/{id}#
Deletes an avatar. One still being created (pending) can't be deleted — wait until it succeeds or fails.
GET /v1/videos/avatars/presets#
The platform's built-in avatars, free to use directly with no registration:
{ "avatars": [ { "id": "…", "name": "Professional female presenter" }, … ] }
Drop any id from presets straight into the avatar field of a production request.
2. Digital-human video (dh-avatar)#
Make a ready avatar speak. The driving audio or script sets the length, and you're billed per second of finished video.
Option 1: drive with audio#
{
"model": "dh-avatar",
"avatar": "9f1c…",
"audio_url": "https://example.com/voice.mp3",
"duration": 32
}
Option 2: drive with text plus a voice (one step, no separate synthesis)#
{
"model": "dh-avatar",
"avatar": "9f1c…",
"voice": "<voice id>",
"text": "Hello everyone — today I want to introduce…",
"duration": 30
}
voice can be either:
- the id of a voice you cloned through
POST /v1/audio/voices, or - a platform preset voice id from the
presetsinGET /v1/audio/voices.
durationis required, in seconds. It's the basis for our cost hold — use the real length of the driving audio, or estimate from the script (Mandarin narration runs at roughlycharacters ÷ 3.3seconds). When the task ends we settle on the actual seconds upstream reports and refund the excess automatically; the hold also caps what this production can cost.
Submit and poll on the generic video endpoints:
curl https://qianyi.dflop.top/v1/videos/generations \
-H "Authorization: Bearer $GPUSHARE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"dh-avatar","avatar":"9f1c…","audio_url":"https://example.com/voice.mp3","duration":32}'
# → {"id":"…","status":"queued","model":"dh-avatar","created_at":1753…}
curl https://qianyi.dflop.top/v1/videos/generations/<id> \
-H "Authorization: Bearer $GPUSHARE_API_KEY"
# → {"id":"…","status":"succeeded","video_url":"https://…","expires_at":…}
3. Lip sync (dh-lipsync / -pro / -max)#
Swap the audio track on an existing video of a person and match the lips to it. The three tiers step up in quality and price.
{
"model": "dh-lipsync-pro",
"source_video_url": "https://example.com/source.mp4",
"audio_url": "https://example.com/new-voice.mp3",
"duration": 45
}
The finished length follows the driving audio. Both the source video and the audio must be publicly reachable direct links.
4. Motion transfer (dh-motion)#
Transfer the motion from a source video onto 1–7 portraits.
{
"model": "dh-motion",
"source_video_url": "https://example.com/dance.mp4",
"face_count": 2,
"resolution": "standard",
"content": [
{ "type": "image_url", "image_url": { "url": "https://example.com/person1.jpg" } },
{ "type": "image_url", "image_url": { "url": "https://example.com/person2.jpg" } }
],
"duration": 20
}
| Field | Notes |
|---|---|
source_video_url | The motion source video (public direct link) |
content[] | 1–7 portraits |
face_count | How many people are in frame, 1–7; should match the number of portraits |
resolution | fast / standard (default) / max — the tier sets the unit price; see the pricing table below |
duration | Required; use the source video's length |
The finished length follows the motion source video.
5. Social-style editing (clip-compose)#
Turn a video with clear speech into a finished, packaged piece: subtitle effects, keyword highlights, a title, a name card, a template style, background music and picture-in-picture inserts. It takes four steps: pick a template → recognise subtitles → submit the compose → poll for the result.
- The key's model allowlist must permit
clip-compose(the template, category and subtitle helper endpoints check the same thing); otherwise you get 403model_not_allowed. - The source video must be ≤ 5 minutes with clearly audible speech, at a publicly reachable http(s) direct link (the platform offers no upload endpoint).
- A finished video typically arrives in 20–60 seconds.
Step 1: pick a template#
# Template categories (six: 高级感 / 热门 / 简约 / 综艺感 / 本地引流 / 其他)
curl https://qianyi.dflop.top/v1/videos/clip-templates/categories \
-H "Authorization: Bearer $GPUSHARE_API_KEY"
# → {"list":[{"cate_id":"67d402f96574a9003050ea3a","cate_name":"高级感","sort":1}, …]}
# Templates (with cate_id: that category only; without: every template)
curl "https://qianyi.dflop.top/v1/videos/clip-templates?cate_id=67d402f96574a9003050ea3a" \
-H "Authorization: Bearer $GPUSHARE_API_KEY"
# → {"list":[{"style_id":"…","name":"…","cover_url":"https://…","demo_url":"https://…","cate_name":"","scene":""}, …],
# "sid":"","api_version":"old"}
The template list is not paginated: one call returns the whole category (or every template), and sid is always an empty string. demo_url is the template's sample video. Put the chosen template's style_id into the compose request's video_style_id. Both endpoints are free.
Subtitle effects, keyword highlights, the title and the name card are all rendered by the template: compose without a template and none of them appear — only the picture-in-picture inserts are overlaid. Always send
video_style_id. Only templates listed by this endpoint are accepted; astyle_idfrom anywhere else is rejected (400 "这套模板已经下架了").
Step 2: recognise subtitles#
curl https://qianyi.dflop.top/v1/videos/clip-subtitles \
-H "Authorization: Bearer $GPUSHARE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"video_url":"https://example.com/talk.mp4"}'
This is synchronous, usually 5–10 seconds; it waits at most 240 seconds and then returns 504 upstream_timeout. The response:
{
"model": "clip-subtitle",
"asr_id": "asr_…",
"api_version": "old",
"segments": [
{ "showRange": [0, 1750], "content": "很多人做事总纠结" },
{ "showRange": [1750, 2850], "content": "完美才开始" }
],
"sentences": [
{ "showRange": [0, 1750], "content": "很多人做事总纠结" },
{ "showRange": [1750, 2850], "content": "完美才开始" }
]
}
| Field | Notes |
|---|---|
asr_id | The id of this recognition — required when composing |
segments | The result by sentence: one sentence per item, showRange is [startMs, endMs], no punctuation |
sentences | The same as segments (kept for compatibility) |
A video with no recognisable speech returns 400.
Step 3: submit the compose#
curl https://qianyi.dflop.top/v1/videos/generations \
-H "Authorization: Bearer $GPUSHARE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "clip-compose",
"video_url": "https://example.com/talk.mp4",
"asr_id": "<asr_id from step 2>",
"video_style_id": "<style_id from step 1>",
"title": "Compound interest in three minutes",
"enable_title_effect": true,
"enable_caption_effect": true,
"enable_keyword_effect": true,
"name_card": { "name": "Ms Zhang", "description": "Financial planner" }
}'
# → {"id":"…","status":"queued","model":"clip-compose","created_at":1790…}
| Field | Required | Notes |
|---|---|---|
model | yes | Always clip-compose |
video_url | yes | The source video's direct link — the same one you ran subtitles on in step 2 |
asr_id | yes | The asr_id returned in step 2 |
enable_title_effect | no | Add a title effect; default false |
enable_caption_effect | no | Add subtitle effects; default true |
enable_keyword_effect | no | Highlight keywords; default true |
title | no | Title text, at most 30 characters (longer is truncated) |
video_style_id | no | A template's style_id (step 1). Send it: without a template the video gets no subtitles, title or name card |
music_url | no | A background music direct link (http(s)) |
name_card | no | A name card {"name": "…", "description": "…"}; name at most 20 characters, description at most 40 |
sentences | no | Only if you edited the subtitles — rules below; omit it to use step 2's original recognition as is |
pip_config | no | Picture-in-picture inserts, at most 20: [{"media_url": "https://…", "begin_time": 3000, "end_time": 6000}], times in milliseconds, end_time > begin_time |
sentences: edit the words, keep the lines#
Send sentences only when your user changed the subtitle text. The rule is one line for one line:
"sentences": [
{ "showRange": [0, 1750], "content": "好多人做事总纠结" },
{ "showRange": [1750, 2850], "content": "完美,才开始" }
]
- Start from step 2's
segments: same number of lines, same order, and change onlycontent. Lines may get longer or shorter and may gain punctuation. - Don't split, merge or delete lines. A different line count returns 400 telling you how many lines are expected. (Upstream doesn't reject such subtitles — it silently drops all your edits or cuts the end of the video — so the platform stops the request before it is submitted, and nothing is charged.)
- No line's
contentmay be empty. - Timing comes from step 2's recognition; any
showRangeyou send is ignored. - If nothing was edited, omit
sentencesentirely and the original recognition is used. asr_idmust be the one step 2 just returned; if an old recognition has expired you get 400 "字幕识别结果已经过期" — just run step 2 again.
Step 4: poll for the result#
Exactly like any other video task: poll GET /v1/videos/generations/{id}, every 5–10 seconds or so:
curl https://qianyi.dflop.top/v1/videos/generations/<id> \
-H "Authorization: Bearer $GPUSHARE_API_KEY"
# → {"id":"…","status":"succeeded","video_url":"https://…","expires_at":…}
Social-style editing pricing#
| Endpoint / model ID | Price | Notes |
|---|---|---|
clip-compose (compose) | 48 per task | A flat price per successful compose task, regardless of video length; failures are refunded in full automatically |
clip-subtitle (subtitle recognition) | per call, currently 0 | Charged only on success; failures and timeouts cost nothing |
| Templates / categories | free |
Pricing#
For the per-second SKUs, settlement uses the actual seconds upstream reports; duration sizes the hold on submit and the excess is refunded. clip-compose is a flat price per task and needs no duration.
| Model ID | Purpose | Price |
|---|---|---|
dh-avatar-create | Register an avatar | 220.11 each |
dh-avatar | Digital-human video | 3.96 / second |
dh-lipsync | Lip sync · standard | 4.04 / second |
dh-lipsync-pro | Lip sync · HD | 8.09 / second |
dh-lipsync-max | Lip sync · UHD | 12.13 / second |
dh-motion | Motion transfer | fast 4.04 / standard 8.09 / max 12.13 per second |
clip-compose | Social-style editing | 48 per task (regardless of length) |
The companion voice endpoints (synthesis and cloning) are in the media APIs.
Async and timeout conventions#
- Avatar registration, video production and social-style compose are all async (social-style subtitle recognition is synchronous): submitting returns immediately and you poll the status endpoint afterwards. Polling itself is free.
- A production task's
video_urlis a time-limited link, withexpires_atin the response as its expiry — copy it somewhere of your own if you need it long-term. - Failed tasks (an upstream error, a timeout, expiry) are refunded in full automatically; you need do nothing.
- The avatar record is the refund's evidence: calling
DELETEwhile it'spendingreturns 400, so wait for a final state.
Common errors#
| HTTP | code | Meaning |
|---|---|---|
| 400 | invalid_request_error | The avatar or voice reference doesn't exist, belongs to another account, or isn't ready yet; duration is missing; name is too long; source_url / video_url isn't http(s); subtitle recognition found no speech; pip_config start/end times are invalid |
| 401 | authentication_error | The key is invalid or disabled |
| 402 | quota_exceeded | Insufficient account balance |
| 403 | model_not_allowed | This key's model allowlist doesn't include that SKU |
| 404 | model_not_found | The model id is wrong, or that SKU isn't available yet |
| 503 | no_channel_available | No upstream is currently available for that SKU; retry later |
| 504 | upstream_timeout | Subtitle recognition didn't finish within 240 seconds (not charged); retry, or use a shorter video |
The error body matches every other endpoint — see Error codes.