4.7 KiB
YINIAN Server Contract v0
Updated: 2026-04-26
Status: Draft contract for M2 integration
Client switch: setYINIAN_API_BASE_URLto enable HTTP mode. Without it, desktop uses mock mode.
1. Transport
- Base URL:
YINIAN_API_BASE_URL - Content type:
application/json - Auth header:
Authorization: Bearer <accessToken> - Desktop header:
X-YINIAN-App-Version: 0.1.0 - Timestamps: Unix milliseconds.
- Field casing: server should prefer
camelCase; desktop accepts keysnake_casealiases for M1/M2 migration.
2. Error Shape
Non-2xx responses should return:
{
"error": {
"code": "SESSION_EXPIRED",
"message": "Session expired"
}
}
The desktop currently surfaces error.message and falls back to YINIAN API request failed: <status>.
Recommended error codes:
INVALID_CREDENTIALSINVALID_SMS_CODESESSION_EXPIREDWORKSPACE_FORBIDDENCONFIG_UNAVAILABLESKILLS_MANIFEST_UNAVAILABLE
3. Device Payload
Login requests include:
{
"device": {
"device_id": "dev_local_electron",
"platform": "darwin",
"app_version": "0.1.0",
"machine_name": "YINIAN Desktop"
}
}
The exact device_id is a placeholder in M2 and should be replaced by a stable desktop installation id later.
4. Auth
POST /auth/login/sms
Request:
{
"phone": "13800000000",
"code": "123456",
"device": {}
}
Response:
{
"accessToken": "access_demo",
"refreshToken": "refresh_demo",
"accessTokenExpiresAt": 1777188600000
}
POST /auth/login/password
Request:
{
"account": "ops@example.com",
"password": "secret",
"device": {}
}
Response shape is the same as SMS login.
POST /auth/refresh
Request:
{
"refreshToken": "refresh_demo",
"device": {}
}
Response:
{
"accessToken": "access_refreshed",
"refreshToken": "refresh_rotated",
"accessTokenExpiresAt": 1777189500000
}
M2 desktop persists only refreshToken; accessToken remains memory-only.
GET /auth/me
Headers:
Authorization: Bearer access_demo
Response:
{
"user": {
"id": "user_ops_001",
"name": "王管理员",
"phone": "13800000000",
"email": "ops@example.com",
"avatar": "https://cdn.example.com/avatar.png"
},
"hotels": [
{
"id": "workspace_hangzhou_ops",
"name": "智念企业组织空间",
"brand": "智念"
}
],
"currentHotelId": "workspace_hangzhou_ops",
"accessTokenExpiresAt": 1777188600000
}
5. Config Sync
GET /config/sync?hotel_id=<hotelId>
Response:
{
"serverTime": 1777188000000,
"hotel": {
"id": "workspace_hangzhou_ops",
"name": "智念企业组织空间",
"brand": "智念"
},
"entitlements": [
{
"skillId": "daily-report",
"name": "日报生成助手",
"version": "1.0.0",
"enabled": true,
"category": "reporting",
"triggers": ["scheduled", "manual"],
"lastRunAt": 1777184400000
}
],
"notificationChannels": [
{
"id": "wechat_ops",
"kind": "wecom",
"label": "业务通知群",
"recipient": "room_001",
"enabled": true,
"source": "nianxx"
}
],
"featureFlags": {
"skillsSync": true,
"advancedSettings": false
},
"uiPolicy": {
"defaultPage": "today",
"showAdvancedSettings": false
}
}
6. Skills Manifest
GET /skills/manifest?hotel_id=<hotelId>
Response:
{
"serverTime": 1777188000000,
"hotelId": "workspace_hangzhou_ops",
"manifestVersion": "2026.04.26.1",
"skills": [
{
"skillId": "data-check",
"name": "数据检查助手",
"version": "1.2.0",
"enabled": true,
"bundleSha256": "sha256-demo",
"bundleUrl": "https://cdn.example.com/skills/data-check-1.2.0.tgz"
},
{
"skillId": "customer-reply-helper",
"name": "客户回复助手",
"version": "0.9.0",
"enabled": false,
"bundleSha256": "sha256-disabled"
}
]
}
M2 desktop consumes manifest metadata only. It does not download bundleUrl, verify signatures, or unpack bundles yet.
7. Client Normalization Rules
The desktop accepts:
camelCaseandsnake_casealiases for known fields.- Missing
user.nameas未命名用户. - Missing hotel fields with safe empty/default values.
- Unknown skill categories as
ops-automation. - Unknown trigger values are ignored.
- Missing
uiPolicy.defaultPagedefaults totoday. - Missing arrays default to
[].
Malformed server responses should not break the shell, but required auth fields still fail fast:
- Missing
accessTokenafter login or refresh throws服务端未返回 access token. - Authenticated config/skills calls without a session throw
请先登录.