# Digital human / smart edit API

> Avatar library, digital-human video, lip sync, motion transfer and smart editing — all on one sk-gpushare-* key

来源：https://zhonkemodel.dflop.top/en/docs/reference/digital-human-apis

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 cut a finished piece from a template.

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](./authentication.md). 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 |
| `GET /v1/videos/clip-templates` | List smart-edit templates | free |
| `GET /v1/videos/clip-templates/{id}` | A template's structure | free |
| `POST /v1/videos/generations` | Produce video (digital human / lip sync / motion transfer / smart edit) | **per second** |
| `GET /v1/videos/generations/{id}` | Poll a production task | free |

Producing and polling use the same generic video endpoints from the [media APIs](./media-apis.md); 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.

```json
{
  "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:

```json
{
  "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.

```json
{ "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:

```json
{ "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

```json
{
  "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)

```json
{
  "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 `presets` in `GET /v1/audio/voices`.

> **`duration` is 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 roughly `characters ÷ 3.3` seconds). 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:

```bash
curl https://zhonkezhonkeapi.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://zhonkezhonkeapi.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.

```json
{
  "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.

```json
{
  "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. Smart editing (`clip-realman` / `clip-mixcut` / `clip-news`)

Cut your assets into a finished piece using a platform template. **You must fetch a template id first and pass it as `style_id`.**

### Step 1: get a template

```bash
curl "https://zhonkezhonkeapi.dflop.top/v1/videos/clip-templates?scene=realMan" \
  -H "Authorization: Bearer $GPUSHARE_API_KEY"
```

Allowed values for `scene`:

| scene | What it does |
|---|---|
| `virtualman` | Virtual-presenter broadcast |
| `realMan` | Real talking head (`clip-realman`) |
| `oralMixCutting` | Narration mixcut (`clip-mixcut`) |
| `newsMixCutting` | News mixcut (`clip-news`) |

Each template in the response carries an `id`, a title, a cover and two capability flags:

- `has_title` — the template has a title layer, so you can pass title text;
- `has_persona` — the template has a persona layer, so you can pass persona text.

When a flag is `false` the matching input is ignored upstream, so don't bother sending it. For a template's full structure (canvas and layers), call `GET /v1/videos/clip-templates/{id}`.

> Both endpoints are free and server-side cached, so calling them every time your client opens is fine. **The key must be allowed at least one `clip-*` model** to reach the template catalogue.

### Step 2: submit the edit

```json
{
  "model": "clip-realman",
  "style_id": "<the template id from step 1>",
  "duration": 60
}
```

The remaining fields (assets, narration audio, title and persona text, and so on) depend on the template — consult the layer structure in its details.

---

## Pricing

For the per-second SKUs, **settlement uses the actual seconds upstream reports**; `duration` sizes the hold on submit and the excess is refunded.

| Model ID | Purpose | Price |
|---|---|---|
| `dh-avatar-create` | Register an avatar | **210.29 each** |
| `dh-avatar` | Digital-human video | 3.76 / 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-realman` | Smart edit · talking head | 4.04 / second |
| `clip-mixcut` | Smart edit · narration mixcut | 4.04 / second |
| `clip-news` | Smart edit · news mixcut | 2.43 / second |

The companion voice endpoints (synthesis and cloning) are in the [media APIs](./media-apis.md#post-v1audiospeech).

---

## Async and timeout conventions

- Avatar registration and video production are **both async**: submitting returns immediately and you poll the status endpoint afterwards. Polling itself is free.
- A production task's `video_url` is a **time-limited link**, with `expires_at` in 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 `DELETE` while it's `pending` returns 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` isn't http(s) |
| 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 |

The error body matches every other endpoint — see [Error codes](./errors.md).
