← Back to Admin Dashboard

KYC Service API Documentation

KYC 实名认证微服务提供身份证 OCR 识别、人脸活体认证、短信验证、用户权限校验等能力。
作为独立微服务,通过 API Key 鉴权,可被 menhu 等业务系统集成调用。

Base URL:http://localhost:5122
所有接口均需通过 X-API-Key + X-API-Secret 请求头鉴权。

Authentication

所有 API 请求必须包含以下 HTTP 请求头:

HeaderRequiredDescription
X-API-KeyRequiredAPI Key, format: kyc_xxxx
X-API-SecretRequiredAPI Secret (SHA256 hashed internally)
Content-TypeRequiredapplication/json

API Key 在管理后台的「API Key」页面管理。每个 Key 拥有独立的权限范围(auth / check)和速率限制。

User Levels

KYC 系统定义了 4 个用户等级,不同等级可访问不同功能:

LevelDescriptionAccessAchieved By
L1DefaultBasic functions onlyRegistration
L2VerifiedAI generation, SeedanceFace + ID verification
L3AdvancedCustom trainingEnterprise cert (TBD)
L4EnterpriseFull access, discountEnterprise cert (TBD)

Capability Mapping

CapabilityRequired Level
seedance_videoL2
ai_video_generationL2
ai_picture_generationL2
custom_trainingL3
custom_portraitL4

Process Flow

Path A: Manual Input + Face Auth

1
identity/start
Input name + ID
2
H5 Face Auth
Open H5 URL
3
identity/result
Query result
4
check/user
Verify access

Path B: ID Card OCR + Face Auth

1
idcard/ocr
Upload photo
2
identity/start
Use OCR result
3
H5 Face Auth
Open H5 URL
4
identity/result
Query result

Error Codes

All responses follow a unified format:

{
  "success": true | false,
  "data": { ... },           // success case
  "error": {                  // error case
    "code": "ERROR_CODE",
    "message": "Description"
  }
}
CodeHTTPDescription
VALIDATION_ERROR400Missing or invalid parameters
AUTH_FAILED401Invalid API Key or Secret
NOT_FOUND404Record not found
ID_CARD_USED400ID card already registered
RATE_LIMIT429Too many requests
INTERNAL_ERROR500Internal server error

ID Card OCR

Upload an ID card photo for OCR recognition. Returns extracted name, ID number, and other fields. Supports front and back side detection with quality assessment.

POST /api/v1/auth/idcard/ocr

Request Body

FieldTypeRequiredDescription
app_idStringYesApplication ID
external_user_idStringYesExternal user identifier
image_base64StringOne of twoBase64 encoded image (supports data:image/... prefix)
image_urlStringOne of twoImage URL (max 8MB)

Response (Success)

{
  "success": true,
  "data": {
    "name": "Zhang San",
    "id_number": "110101199001011234",
    "gender": "Male",
    "ethnicity": "Han",
    "date_of_birth": "1990.01.01",
    "domicile": "Beijing ...",
    "issue_authority": "",      // back side only
    "valid_period": "",          // back side only
    "has_front": true,
    "has_back": false,
    "quality_codes": [0],
    "quality_labels": ["normal"],
    "has_risk": false,
    "has_validation_error": false
  }
}

Quality Codes

CodeLabelDescription
0normalNormal quality
10blurryBlurry image
20no_idcard_contentNo ID card detected
21idcard_incompleteID card incomplete
30tampered_or_fakeTampered / Fake
31photocopyPhotocopy detected
32screen_recaptureScreen recapture

Identity Start

Initiate face liveness authentication. Returns an H5 URL for the user to complete face verification. The URL is valid for 60 minutes.

POST /api/v1/auth/identity/start

Request Body

FieldTypeRequiredDescription
app_idStringYesApplication ID
external_user_idStringYesExternal user identifier
real_nameStringYesReal name (from ID card)
id_card_noStringYes18-digit ID card number
redirect_urlStringOptionalCustom callback URL after face auth

Response (Success)

{
  "success": true,
  "data": {
    "h5_url": "https://h5-v2.kych5.com?...",
    "byted_token": "2026041914...",
    "config_id": "uuid-...",
    "expires_in": 3600
  }
}
Note: If the user is already verified and not expired, returns "status": "already_verified" instead.

Identity Result

Query the result of a face authentication. Call this after the user completes face verification on the H5 page.

POST /api/v1/auth/identity/result

Request Body

FieldTypeRequiredDescription
app_idStringYesApplication ID
external_user_idStringYesExternal user identifier
byted_tokenStringYesToken from identity/start response

Response (Verified)

{
  "success": true,
  "data": {
    "status": "verified",
    "user_level": "L2",
    "safety_identifier": "SAF_xxxx",
    "device_risk_level": "low",
    "face_quality_score": 99.004,
    "expires_at": "2028-04-18T06:40:13.619Z"
  }
}

Response (Rejected)

{
  "success": true,
  "data": {
    "status": "rejected",
    "result_code": "50001"
  }
}

SMS Send

Send an SMS verification code to the specified phone number.

POST /api/v1/auth/sms/send

Request Body

FieldTypeRequiredDescription
app_idStringYesApplication ID
external_user_idStringYesExternal user identifier
phoneStringYesPhone number (e.g. 13800138000)
Note: SMS requires SMS provider configuration in .env (SMS_ACCESS_KEY, SMS_SECRET_KEY, etc.)

SMS Verify

Verify an SMS code. On success, marks the user's phone as verified.

POST /api/v1/auth/sms/verify

Request Body

FieldTypeRequiredDescription
app_idStringYesApplication ID
external_user_idStringYesExternal user identifier
phoneStringYesPhone number
codeStringYes6-digit verification code

Check User

Check if a user has the required KYC level to access a specific capability. This is the primary integration endpoint for business systems like menhu.

POST /api/v1/check/user

Request Body

FieldTypeRequiredDescription
app_idStringYesApplication ID
external_user_idStringYesExternal user identifier
capabilityStringOptionalCapability to check (see Level table)
client_ipStringOptionalClient IP for geo restriction check

Response (Allowed)

{
  "success": true,
  "data": {
    "allowed": true,
    "safety_identifier": "SAF_xxxx",
    "user_level": "L2",
    "cost_multiplier": 1.0
  }
}

Response (Denied)

{
  "success": true,
  "data": {
    "allowed": false,
    "reason": "LEVEL_REQUIRED",     // or KYC_EXPIRED, IP_RESTRICTED, VIOLATION_FROZEN
    "message": "Identity verification required",
    "required_level": "L2",
    "current_level": "L1"
  }
}

Integration Example (Node.js)

// menhu backend: check before allowing AI generation
async function checkKYC(userId, capability) {
  var resp = await fetch('http://localhost:5122/api/v1/check/user', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-API-Key': process.env.KYC_API_KEY,
      'X-API-Secret': process.env.KYC_API_SECRET
    },
    body: JSON.stringify({
      app_id: 'menhu',
      external_user_id: userId,
      capability: capability
    })
  });
  var data = await resp.json();
  return data.data.allowed;
}

Check Status

Query a user's current KYC status, level, and violation count.

GET /api/v1/check/status?app_id=xxx&external_user_id=xxx

Query Parameters

FieldTypeRequiredDescription
app_idStringYesApplication ID
external_user_idStringYesExternal user identifier

Response

{
  "success": true,
  "data": {
    "user_level": "L2",
    "kyc_status": "verified",
    "safety_identifier": "SAF_xxxx",
    "phone_verified": true,
    "real_name_masked": "Zhang *",
    "id_card_last4": "1234",
    "expires_at": "2028-04-18T06:40:13Z",
    "violations_count": 0
  }
}

App Config (Get)

Get your app's current callback configuration. Uses API Key authentication to identify the calling app.

GET /api/v1/check/config

Response

{
  "success": true,
  "data": {
    "app_id": "menhu",
    "app_name": "Points Aggregation Portal",
    "callback_url": "http://localhost:5120/api/v1/kyc/callback",
    "webhook_url": "http://localhost:5120/api/v1/kyc/webhook",
    "contact_name": "admin",
    "contact_email": "admin@lumi.com"
  }
}

App Config (Update)

Update your app's callback URLs. Your app can self-configure these without admin access.

PUT /api/v1/check/config

Request Body

FieldTypeRequiredDescription
callback_urlStringOptionalURL to receive kyc_verified events
webhook_urlStringOptionalURL to receive violation_created and alert_threshold events
contact_nameStringOptionalContact person name
contact_emailStringOptionalContact email

Integration Example

// App registers its callback URLs with KYC on startup
await fetch('http://kyc-service:5122/api/v1/check/config', {
  method: 'PUT',
  headers: {
    'Content-Type': 'application/json',
    'X-API-Key': KYC_API_KEY,
    'X-API-Secret': KYC_API_SECRET
  },
  body: JSON.stringify({
    callback_url: 'https://my-app.com/api/kyc/callback',
    webhook_url: 'https://my-app.com/api/kyc/webhook'
  })
});

Webhook

KYC 服务支持通过 Webhook 主动向对接方推送事件通知。在管理后台「API Key」中配置回调地址后,相关事件发生时 KYC 会向配置的 URL 发送 POST 请求。

配置方式

在管理后台 API Key 编辑中配置两个 URL:

FieldDescriptionTriggered Events
callback_urlCallback URLkyc_verified
webhook_urlWebhook Notification URLviolation_created, alert_threshold

Request Format

KYC service sends POST request to configured URL:

POST {callback_url | webhook_url}
Content-Type: application/json

{
  "event": "kyc_verified",
  "app_id": "menhu",
  "timestamp": "2026-04-24T05:00:00.000Z",
  "data": { ... }
}

Response

Return HTTP 200 with JSON body. KYC will log the response status but won't retry on failure (fire-and-forget).

{
  "success": true,
  "received": "kyc_verified"
}

Webhook Events

kyc_verified

Triggered when a user completes identity verification. Sent to callback_url.

{
  "event": "kyc_verified",
  "app_id": "menhu",
  "timestamp": "2026-04-24T...",
  "data": {
    "external_user_id": "69db6282...",
    "safety_identifier": "SAF_xxxx",
    "user_level": "L2",
    "expires_at": "2028-04-24T..."
  }
}

violation_created

Triggered when a violation is created (manually or auto). Sent to webhook_url.

{
  "event": "violation_created",
  "data": {
    "safety_identifier": "SAF_xxxx",
    "level": "P3",
    "type": "content_violation",
    "action_taken": "warning",
    "source": "auto_alert",
    "description": "Auto-created: 3 pending alerts"
  }
}

alert_threshold

Triggered when a user's content alerts reach the configured threshold. Sent to webhook_url.

{
  "event": "alert_threshold",
  "data": {
    "safety_identifier": "SAF_xxxx",
    "alert_count": 3,
    "threshold": 3,
    "violation_level": "P3"
  }
}

Receiver Example (Node.js)

// menhu: /api/v1/kyc/callback
router.post('/callback', function(req, res) {
  var { event, data } = req.body;
  if (event === 'kyc_verified') {
    console.log('User verified:', data.external_user_id);
    // Update local user record...
  }
  res.json({ success: true });
});

// menhu: /api/v1/kyc/webhook
router.post('/webhook', function(req, res) {
  var { event, data } = req.body;
  if (event === 'violation_created') {
    console.log('Violation:', data.safety_identifier, data.level);
    // Freeze user, send notification...
  }
  res.json({ success: true });
});

Integration Guide

KYC 服务通过 safety_identifier 实现内容溯源。以下是三种接入场景的集成方式。

Scene A: menhu Direct (Portal Call Seedance)

menhu 自身调用 Seedance API 时,先通过 KYC 获取 safety_identifier,再传入视频生成请求。

// Step 1: Check KYC & get safety_identifier
var kycResult = await kycClient.checkUser('menhu', userId, 'seedance_video');

// Step 2: Pass to Seedance API
var body = {
  model: "doubao-seedance-2-0-260128",
  content: [{ type: "text", text: "..." }],
  safety_identifier: kycResult.safety_identifier  // "SAF_xxxx"
};

Scene B: Downstream Tool (via OAuth)

通过 menhu 工具市场接入的下游工具,在 OAuth 授权后调用 userinfo 即可获得 safety_identifier。

// Step 1: User OAuth → Tool gets access_token

// Step 2: Get userinfo (includes safety_identifier)
GET /oauth/userinfo
Authorization: Bearer <access_token>

// Response:
{
  "user_id": "...",
  "nickname": "...",
  "safety_identifier": "SAF_xxxx",  // from KYC
  "kyc_status": "verified",
  "user_level": "L2"
}

// Step 3: Pass safety_identifier to upstream AI API

Scene C: Standalone Tool (direct KYC)

Independent tool with its own KYC API Key. Directly calls KYC service.

// Tool registers with KYC admin → gets api_key + api_secret

// Call check/user to verify and get safety_identifier
POST /api/v1/check/user
Headers:
  X-API-Key: <tool_api_key>
  X-API-Secret: <tool_api_secret>
Body:
{
  "app_id": "my_video_tool",
  "external_user_id": "user_12345",
  "capability": "ai_video_generation"
}

// Response:
{
  "allowed": true,
  "safety_identifier": "SAF_xxxx",
  "user_level": "L2"
}

safety_identifier Properties

PropertyValue
FormatSAF_ + 16-char hex hash
Length20 characters (within Seedance 64-char limit)
UniquenessUnique per verified user
PrivacyNon-reversible hash, no PII exposed
Validity2 years from verification date
TraceabilityKYC admin can trace via /admin/trace/:safetyId
KYC Service v1.0 · API Test Page