会话心跳:缺 sessionId 开新会话(sessions.api_key_id 归账)并回 sessionId;在册触碰 last_seen_at;meta 白名单(零留存);配置失效订阅:请求可携客户端 configVersion,响应恒回带服务端 configVersion 与 configStale(不一致=true → 重拉 /t1/config;未携恒 false);请求签名三头可选(在场恒校验);configVersion/bundleEtag 与 /t1/config 同径同档同锚——令牌径按 x-tansr-client-features 声明档计(客户端须三径同携同值,否则 configStale 恒真),owner 双头径恒全量单一 etag、漏头不 stale;在册会话心跳 = 续租恒走并发守门 acquire——窗内零变化,出窗会话重入与新会话同律判限(enforce 429 plan_concurrency_exceeded / shadow 计 would_reject),判限先于 last_seen_at 刷新;已归档会话(DELETE /t1/sessions/{id} 后)恒 410 session_archived(detail.sessionId;不复活、不入位;SDK 停该会话心跳、下轮 exchange 开新会话)
const url = 'https://api.tansr.com/t1/heartbeat';const options = { method: 'POST', headers: { 'x-tansr-key-id': '<x-tansr-key-id>', 'x-tansr-key': '<x-tansr-key>', 'Content-Type': 'application/json' }, body: '{"sessionId":"example","client":"cli","configVersion":"example","meta":{"clientVersion":"example","platform":"example"}}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://api.tansr.com/t1/heartbeat \ --header 'Content-Type: application/json' \ --header 'x-tansr-key: <x-tansr-key>' \ --header 'x-tansr-key-id: <x-tansr-key-id>' \ --data '{ "sessionId": "example", "client": "cli", "configVersion": "example", "meta": { "clientVersion": "example", "platform": "example" } }'Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Header Parameters
Section titled “Header Parameters”客户端可理解的可选扩展词表(逗号分隔,大小写不敏感,未知词忽略;与服务端 features 反向同形)。词表:platform-audio = 可理解 bundle 音频两面加法键(capabilities.platform.speechToText/textToSpeech、platformModels.speechToText/textToSpeech 与 media.asr/tts)。分档只施于 app_user 令牌径(十王修案 FX-A-05,分册 A S3:分档只保护已发布 .strict() 的旧 SDK,而 SDK 恒走令牌径):令牌径仅对声明者下发五键 / 四键 / 音频两面,缺头恒三键 / 两键,正文与 ETag 按档重算(响应 Vary 本头),同一客户端须在 /t1/config、/t1/handshake、/t1/heartbeat 同携同值,否则 configEtag/bundleEtag 与 bundle 异档、configStale 恒真;owner 径(AK/SK 双头 / 装置键 / PAT)恒全量、单一 ETag,本头为 no-op
签名时间戳(unix 秒,十进制串;T-A34):与服务器时钟偏差 >300s → 401 signature_invalid
签名随机数(≥16 字符;T-A34):同 keyId 600s 窗内重现 → 401 nonce_replayed
请求签名(hex 小写;T-A34):HMAC-SHA256(K=sha256(SK 明文) 原始摘要, TWP1-HMAC-SHA256\n{METHOD}\n{path+query}\n{ts}\n{nonce}\n{sha256hex(rawBody)});三头须同现,在场恒校验;app signRequired 或 TANSR_API_TWP_REQUIRE_SIGNATURE=1 时未签名恒 401 signature_invalid
Request Bodyrequired
Section titled “Request Bodyrequired”Responses
Section titled “Responses”心跳受理
object
服务端当前 configVersion(内容稳定指纹)
配置已失效(不一致=true;请求未携 configVersion 恒 false)
此刻 GET /t1/config 的 ETag(不带引号;= configVersion 同源;sdk 比对缓存条目 etag,不同即失效重拉)
Harness 许可状态提示位(O-A0 冻结;O-A3 起下发)
能力协商位(与 handshake 同词表 TWP_FEATURES;未知串恒忽略)
Examplegenerated
{ "sessionId": "example", "serverTime": "example", "configVersion": "example", "configStale": true, "bundleEtag": "example", "licenseStatus": "example", "features": [ "example" ]}App_key_invalid / signature_invalid / nonce_replayed(T-A34)
object
object
错误码注册表单源派生(src/http/errors.ts ERROR_CODES;码稳定,消费方按码翻译)
object
Example
{ "error": { "code": "adjudicator_not_authorized" }}Not_found(未知/他人会话)
object
object
错误码注册表单源派生(src/http/errors.ts ERROR_CODES;码稳定,消费方按码翻译)
object
Example
{ "error": { "code": "adjudicator_not_authorized" }}Session_archived(已归档会话;detail.sessionId;终态——开新会话)
object
object
错误码注册表单源派生(src/http/errors.ts ERROR_CODES;码稳定,消费方按码翻译)
object
Example
{ "error": { "code": "adjudicator_not_authorized" }}Plan_concurrency_exceeded(enforce:新会话首见 / 出窗会话重入达硬帽;Retry-After 30)/ rate_limited
object
object
错误码注册表单源派生(src/http/errors.ts ERROR_CODES;码稳定,消费方按码翻译)
object
Example
{ "error": { "code": "adjudicator_not_authorized" }}Plan_gate_unavailable(enforce 守门 Redis 故障;在册窗内会话为唯一放行例外)
object
object
错误码注册表单源派生(src/http/errors.ts ERROR_CODES;码稳定,消费方按码翻译)
object
Example
{ "error": { "code": "adjudicator_not_authorized" }}本文是否有帮助?
感谢反馈,我们会持续改进这篇文章。