# Real-person liveness flow

Real-person liveness is the gate for unlocking XRToken's digital-human capability: once an end user scans a QR and completes Volcengine's liveness capture, the resulting `AssetGroup` is bound to the caller's user account, and video-generation requests can then reference that person via `asset://<groupId>`.

The full flow is just the two Volcengine request endpoints below — call them in order.

## Prerequisites

Calling these endpoints requires:

| Condition | Source |
|---|---|
| Account has **trusted_creator** tier | Apply from the console |
| Account has **enterprise verification** | Submit enterprise docs in the console |

These are platform-side reviews, done once — no need to repeat them on every call.

## Steps

### 1. Open a scan session

```bash
curl -X POST -H "Authorization: Bearer tr-xxx" \
  https://api.xrtoken.ai/v1/asset-groups/validate-session
```

```json
{
  "BytedToken": "eyJhbGci...",
  "RedirectURL": "https://openspeech.bytedance.com/ark/liveness?...",
  "QRCodeDataURL": "data:image/png;base64,iVBOR...",
  "ExpiresIn": 120
}
```

Drop `QRCodeDataURL` straight into an `<img src>`. The end user scans it on their phone and completes the liveness capture on Volcengine's H5.

### 2. Poll for the result

Using the `BytedToken` from step 1, poll **every 5 s** until a terminal state or the 120 s timeout:

```bash
curl -X POST -H "Authorization: Bearer tr-xxx" \
  -H "Content-Type: application/json" \
  -d '{"bytedToken":"eyJhbGci..."}' \
  https://api.xrtoken.ai/v1/asset-groups/validate-result
```

Three terminal outcomes:

| Outcome | Response body |
|---|---|
| Success | contains `GroupId` + `status: "active"` |
| Failure | contains `ResponseMetadata.Error` |
| Still pending | no `GroupId`, keep polling |

Once you see `GroupId`, the real-person group is already bound to the caller's user. Subsequent `POST /v1/videos/generations` calls can reference it via `asset://<GroupId>`.

If one API key serves many end-users, send the same `external_user_id` on both the session and every poll. Request examples: [Asset library · external_user_id](/docs/asset-library#external-user-id).

## Common errors

| Code | Cause | Fix |
|---|---|---|
| 403 `tier_insufficient` | Trusted-creator not enabled | Apply in the console |
| 403 `enterprise_required` | Enterprise verification missing | Submit docs |
| 502 `upstream_error` | Volcengine transient failure | Retry |
