> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gravitex.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# 자산 그룹 생성(실인물)

> POST /v1/visual-validate/session (liveness_face)

## 소개

실인물 자산 그룹(`group_type: liveness_face`)은 [자산 그룹 생성](/ko/api-reference/endpoint/seedance-2.0/create-asset-group)으로 **생성할 수 없습니다**. 먼저 이 엔드포인트를 호출하여 H5 생체 인증을 시작하세요. 사용자가 검증을 완료하면 게이트웨이가 그룹을 저장합니다.

| 라이브러리 | `group_type`    | 생성 방법                   |
| ----- | --------------- | ----------------------- |
| 가상    | `aigc`          | `POST /v1/asset-groups` |
| 실인물   | `liveness_face` | 이 엔드포인트를 통한 H5 검증       |

가상 및 실인물 라이브러리 각각 사용자당 최대 **100**개 그룹(별도 할당량). 검증 후 이미지/비디오/오디오 자산 추가는 [자산 생성](/ko/api-reference/endpoint/seedance-2.0/create-asset)을 통해 가상 라이브러리와 동일하게 작동합니다—**추가 얼굴 매칭 없음**(초기 그룹 생성 시에는 실인물 얼굴 검증 필요).

<Note>
  BytePlus `CreateVisualValidateSession`은 `name` 또는 `description`을 받지 않습니다. 업스트림 `GroupId`를 받은 후 게이트웨이가 `UpdateAssetGroup`을 호출하여 해당 필드를 BytePlus 콘솔에 다시 기록합니다.
</Note>

## 인증

<ParamField header="Authorization" type="string" required>
  Bearer Token, 예: `Bearer sk-xxxxxxxxxx`
</ParamField>

<ParamField header="Content-Type" type="string">
  `application/json`
</ParamField>

## 요청 본문

<ParamField body="name" type="string" required>
  자산 그룹 이름(저장되고 BytePlus 콘솔에 동기화됨)
</ParamField>

<ParamField body="description" type="string">
  설명; 생략하거나 비어 있으면 API 키 사용자 `username`이 기본값으로 사용됩니다([자산 그룹 생성](/ko/api-reference/endpoint/seedance-2.0/create-asset-group)과 동일)
</ParamField>

<ParamField body="channel_id" type="integer">
  업스트림 채널 ID; 생략 시 자동 선택
</ParamField>

## H5 검증 흐름

```
1. 클라이언트가 검증 시작  → POST /v1/visual-validate/session
   ↓ { h5_link, state, ... } 반환
2. 클라이언트가 팝업에서 h5_link 열기; 사용자가 검증 완료
   ↓ BytePlus가 게이트웨이 /asset-validate-callback.html?state=…&bytedToken=…&resultCode=10000으로 리디렉션
3. 콜백 페이지가 /v1/visual-validate/result를 가져옴; group_type=liveness_face 저장
   ↓ window.opener.postMessage({ type: 'gravitex-asset-validate-result', ok, group_id, … })
4. 클라이언트가 group_id 수신; POST /v1/assets(Image / Video / Audio)로 자산 업로드
```

애플리케이션은 `POST /v1/visual-validate/result`를 **직접 호출할 필요가 없습니다**. 게이트웨이 콜백 페이지가 `state`를 자동으로 전달합니다.

## 예제

```bash theme={null}
curl -X POST "https://api.gravitex.ai/v1/visual-validate/session" \
  -H "Authorization: Bearer sk-xxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"name": "Live person A"}'
```

## 응답

```json theme={null}
{
  "h5_link": "https://verify.byteplus.com/h5/?token=…&lang=zh-CN&lng=zh",
  "state": "<base64url>.<hmac>",
  "channel_id": 123,
  "byted_token": "bp-token-xxxxxxxx",
  "expires_in": 900
}
```

| 필드            | 설명                                                                                                             |
| ------------- | -------------------------------------------------------------------------------------------------------------- |
| `h5_link`     | BytePlus H5 생체 인증 URL; 게이트웨이가 기본값으로 `lang=zh-CN&lng=zh`를 추가                                                    |
| `state`       | `user` / `channel` / `group_name` / `byted_token`에 바인딩된 게이트웨이 발급 HMAC-SHA256 토큰; 콜백 페이지가 결과를 가져오는 데 사용         |
| `byted_token` | 이 검증 세션의 BytePlus 자격 증명; 콜백 시 `state` 내부 값과 대조 검증                                                              |
| `channel_id`  | 선택된 업스트림 채널                                                                                                    |
| `expires_in`  | **`state` 토큰 TTL(초)**, 고정값 `900`(15분). **H5 페이지 수명이 아님**—BytePlus H5 링크는 약 **120초** 동안 유효; 만료 후 이 엔드포인트를 다시 호출 |

<Warning>
  클라이언트는 일반적으로 팝업에서 `h5_link`를 열고 `window.message`를 수신하기만 하면 됩니다. H5 타임아웃 시 팝업을 닫고 리스너를 제거한 후 `POST /v1/visual-validate/session`을 다시 호출하여 새 링크를 받으세요. 클라이언트 측 타임아웃 약 **130초**를 대비책으로 고려하세요.
</Warning>

## 클라이언트 postMessage

콜백 페이지(`/asset-validate-callback.html`)가 `window.opener`에 메시지를 전송합니다(`targetOrigin = '*'`). 콜백 페이지와 부모가 다른 출처인 경우 `event.origin`만 의존하지 말고 `type`으로 메시지를 식별하세요.

**성공:**

```json theme={null}
{
  "type": "gravitex-asset-validate-result",
  "ok": true,
  "group_id": "group-20260512083014-zyxwv",
  "name": "Live person A",
  "channel_id": 123,
  "group_type": "liveness_face"
}
```

**실패:**

```json theme={null}
{
  "type": "gravitex-asset-validate-result",
  "ok": false,
  "result_code": "10003",
  "error": "Liveness validation failed: face does not match reference"
}
```

**최소 통합 예제:**

```js theme={null}
const popup = window.open(session.h5_link, 'asset-validate', 'width=480,height=720');

const listener = (event) => {
  const data = event.data;
  if (!data || data.type !== 'gravitex-asset-validate-result') return;

  window.removeEventListener('message', listener);
  if (data.ok) {
    console.log('Asset group created:', data.group_id);
  } else {
    console.error('Validation failed:', data.error, data.result_code);
  }
};
window.addEventListener('message', listener);
```

## 다음 단계

1. postMessage의 `group_id` 사용(**이** 엔드포인트의 동기 응답이 아님)하여 [자산 생성](/ko/api-reference/endpoint/seedance-2.0/create-asset) 호출
2. [자산 목록 조회](/ko/api-reference/endpoint/seedance-2.0/list-assets) 또는 [자산 조회](/ko/api-reference/endpoint/seedance-2.0/get-asset)로 `status: active`까지 폴링
3. [비디오 생성 작업 생성](/ko/api-reference/endpoint/seedance-2.0/create-video-generation)에서 `asset://`로 자산 참조

[자산 그룹 목록 조회](/ko/api-reference/endpoint/seedance-2.0/list-asset-groups)(`?group_type=liveness_face`)로 그룹 생성을 확인할 수도 있습니다.
