跳到主要内容

错误与限制

HTTP 状态​

状态code含义建议
400400006请求体或参数格式校验失败(缺失必填字段/参数、类型转换失败、非法枚举)修正参数后再重试
401400001缺少请求头、时间戳超出 ±300 秒窗口、应用不存在、凭证无效(如轮换后已过 24 小时宽限期的旧凭证)、签名不匹配或 nonce 重复检查签名原文、时钟和凭证;重试需换新 nonce
403400005应用未处于 ACTIVE(未发布、审核中、已停用)检查应用状态,见应用生命周期
403400007缺少必需的 Scope见「Scope 与 403」
403400008业务守卫拒绝:资源不属于当前应用、机器人未安装到目标、fileKey 无效或已过期检查资源归属与安装关系
403400101客服 V1:访客已停用见「业务错误」
404400100 / 400300 / 400401客服 V1:访客不存在 / 会话不存在或关闭失败 / 客服账号不存在见「业务错误」
406406001请求头 Accept 无法被满足(接口只返回 application/json)声明 Accept: application/json
409400400客服 V1:分配客服失败见「业务错误」
413413001请求体超过限制(普通请求约 256 KiB;机器人文件上传约 22 MiB)压缩或拆分请求
415415001请求体 Content-Type 不受支持(常见于 JSON 接口漏发 Content-Type: application/json)补上正确的 Content-Type
429429001应用配额(每分钟/每日)或并发超限稍后重试
500500000平台内部错误稍后重试;持续失败请携带 reqNo 联系支持

注意三点:

  1. Content-Type 与接口要求不符时返回 415 + 415001,不是 400 也不是 500。最典型的踩坑:JSON 接口只发了 X-Open-* 签名头而漏发 Content-Type: application/json,此时 curl --data-binary(未显式指定该头)会默认发出 application/x-www-form-urlencoded,于是命中 415。拿到 415 请先查请求头,不要怀疑签名。

    响应 message 形如:

    不支持的 Content-Type: application/x-www-form-urlencoded;charset=UTF-8,
    支持: [application/json, application/octet-stream, application/xml, application/*+json,
    text/plain, text/xml, application/x-www-form-urlencoded, application/*+xml,
    multipart/form-data, */*]

    ⚠️ 前半句「不支持的 X」(X 是本次实际收到的类型)可信,后半句「支持: [...]」不可信:这份清单是服务端已注册的消息转换器全局能力(末尾还有 */* 兜底),会把刚刚判为不支持的类型原样列进去,与本次请求是否被接受无关。不要按它判断该改成什么,也不要在代码里解析它——本接口只接受 Content-Type: application/json,直接补上即可。

  2. 缺少必填的查询参数(如 GET /api/open/v1/agent/status 不带 agentId)由 Spring 参数绑定层拦截,返回 400 + 400006,此时响应体为平台自有文案,message 形如 Required String parameter 'agentId' is not present。

  3. multipart 上传缺少必需分片(如 POST /api/open/v2/bot/files 不带 file 字段)返回 400 + 400006,message 形如「缺少必需的上传分片: file」。

  4. 500 + 500000 不一定是平台故障。 有一处业务判断也走通用兜底:更新卡片时 version 与当前版本不一致(乐观锁冲突),返回的是 500 + 500000,message 只有「服务内部错误,请稍后重试」,无法与真正的内部错误区分。见卡片消息 → 更新已发送的卡片。

请求路径或 HTTP 方法写错时,返回的是容器默认的 404 页面({timestamp,status,error,path}),不是 ApiResult 结构。若解析 code 失败,先确认路由是否正确。

统一响应结构​

开放 API(/api/open/v1/**、/api/open/v2/**)的失败响应统一为 ApiResult:

{
"code": "500000",
"message": "服务内部错误,请稍后重试",
"value": null,
"reqNo": "9f1c2d3e4a5b4c6d8e7f0a1b2c3d4e5f"
}

成功与否请以 code == "000000" 判定,不要依赖 message 的文案。失败响应中 value 为 null。reqNo 是排障的唯一凭据,应写入日志,联系支持时一并提供。

完整错误码​

code默认 HTTP含义
400001401签名或凭证校验失败(缺请求头、时间戳超窗、应用不存在、凭证无效、签名不匹配、nonce 重复)
400005403应用未激活(非 ACTIVE)
400006400参数或请求体无效(含 multipart 请求缺少必需分片、上传文件超过 20 MiB)
400007403缺少必需的 Scope
400008403资源不属于当前应用,或业务守卫拒绝(如「机器人未安装到此目标」「fileKey 无效或已过期」)
400100404客服 V1:访客不存在
400101403客服 V1:访客已禁用
400300404客服 V1:会话不存在,或关闭会话失败
400400409客服 V1:分配客服失败
400401404客服 V1:客服账号不存在
406001406请求头 Accept 无法被满足
413001413请求体超过限制
415001415请求体 Content-Type 不受支持
429001429应用配额或并发超限
500000500平台内部错误

400002(时间戳过期)、400003(nonce 重复)、400004(IP 不在白名单)为服务端内部保留码,当前对外统一以 400001 返回,接入方无需单独处理。

下列码在服务端有定义但不会作为响应 code 出现,接入方不必为其编写分支:

  • 400200(消息内容为空):空白 content 在参数绑定阶段就被 @NotBlank 拦成 400 + 400006,轮不到业务层;
  • 400201(消息重复):重复消息走幂等成功路径,返回 code 000000 且 isDuplicate: true;
  • 429002(访客消息频率超限):当前仅按应用维度限流,未启用访客维度的独立配额。

业务错误​

客服 V1 的业务失败一律以 4xx + 业务码 返回,响应体仍是 ApiResult,成败判据是 code == "000000"。

接口触发条件实际返回
POST /api/open/v1/visitor/auth应用不存在401 + 400001、message「应用不存在」
GET /api/open/v1/visitor/info访客不存在404 + 400100、message「访客不存在」
POST /api/open/v1/message/send访客不存在404 + 400100、message「访客不存在」
POST /api/open/v1/message/send、agent/message/send访客已停用(status 为 0)403 + 400101、message「访客已禁用」
POST /api/open/v1/agent/message/send客服账号不存在404 + 400401、message「客服账号不存在」
POST /api/open/v1/session/create访客不存在404 + 400100、message「访客不存在」
GET /api/open/v1/session/info会话不存在,或 sessionId 非数字404 + 400300、message「会话不存在」
POST /api/open/v1/session/close会话不存在、不属于当前应用,或 sessionId 非数字404 + 400300、message「关闭会话失败」
POST /api/open/v1/agent/assign会话不存在、不属于当前应用,或 sessionId 非数字409 + 400400、message「分配客服失败」
各 JSON 接口请求体必填字段缺失或为空400 + 400006,message 为字段级文案(如「消息内容不能为空」)
各接口必填查询参数缺失或为空400 + 400006,message 形如 Required String parameter 'agentId' is not present

sessionId 传非数字(如 "abc")不会返回 400006:服务层把它当作「查不到该会话」处理,落到上表对应的 404/409。

以下三种「查无此人」不是失败,返回 HTTP 200 + code 000000 的成功信封,用响应字段区分:

接口触发条件实际返回
GET /api/open/v1/agent/status客服不存在code 000000、exists:false、online:false、agentName:null
GET /api/open/v1/message/list访客不存在code 000000、records 为空数组、total:0
POST /api/open/v1/message/send、agent/message/sendthirdMsgId 重复code 000000、isDuplicate:true

控制台接口(/api/open/console/**)是另一套契约:凭证错误或缺参返回 Spring 默认错误体({timestamp,status,error,message,path}),不是 ApiResult,见客服开通接口。

与旧版契约的差异(破坏性变更)​

客服 V1 此前把所有业务失败都压在 HTTP 200 上:控制器 return 的业务码(400100、400300、400400)是 200 + 业务 code,服务层 throw 出的失败被兜底成 200 + code 500000(业务码如 400101 被吞掉,不出现在响应里)。现在两者都改为对应的 4xx + 真实业务码,只有上表「查无此人」三种情形仍走 200。

已在联调的接入方需要相应调整:

  1. 判据统一为 code == "000000",HTTP 状态码只作辅助。 原先「HTTP 200 即成功」的判断会漏掉失败;原先依赖「500000 即平台故障」做退避告警的逻辑,现在会收到 400/401/403/404/409。
  2. 4xx 不要盲目重试。 上表的失败几乎都是前置条件不满足(访客未开通、访客被停用、会话不属于本应用),应先满足前置条件再重发;只有 500000 与 429001 适合退避重试。
  3. agent/status 与 message/list 的行为未变,仍是 200 + code 000000,不要为它们改判定逻辑。

Scope 与 403​

缺少 Scope 时返回 403,code 为 400007:

{
"code": "400007",
"message": "所需的开放平台Scope未被授权",
"value": null,
"reqNo": "9f1c2d3e4a5b4c6d8e7f0a1b2c3d4e5f"
}

接口 ↔ 必需 Scope 完整映射​

客服 V1

接口必需 Scope
POST /api/open/v1/visitor/authcustomer.visitor.manage
GET /api/open/v1/visitor/infocustomer.visitor.manage
POST /api/open/v1/message/sendcustomer.message.send
GET /api/open/v1/message/listcustomer.message.read
POST /api/open/v1/agent/message/sendcustomer.message.send
POST /api/open/v1/session/createcustomer.session.manage
POST /api/open/v1/session/closecustomer.session.manage
GET /api/open/v1/session/infocustomer.session.manage
POST /api/open/v1/agent/assigncustomer.session.manage
GET /api/open/v1/agent/statuscustomer.agent.read

机器人 V2

接口必需 Scope
POST /api/open/v2/bot/filesbot.message.send
POST /api/open/v2/bot/messagesbot.message.send
POST /api/open/v2/bot/messages/{messageId}/replybot.message.reply
PUT /api/open/v2/bot/messages/{messageId}/cardbot.message.send
DELETE /api/open/v2/bot/messages/{messageId}/cardbot.message.send
GET /api/open/v2/bot/appsbot.installation.read
GET /api/open/v2/bot/installationsbot.installation.read

小程序 V2

接口必需 Scope
POST /api/open/v2/miniapp/session无(仅校验应用签名)

事件订阅

事件不通过接口 Scope 控制,而是在订阅时单独申请下列 Scope,订阅成功且授权后平台才会投递对应事件:

Scope订阅的事件类型
event.bot.messageim.message.receive_v1
event.customer.message客服消息事件
event.customer.session客服会话事件
event.customer.agent客服状态事件

card.interaction(卡片交互)不通过 Scope 控制:只要卡片消息由本应用发送并完成绑定,用户交互就会投递,无需申请额外 Scope。

Scope 说明​

Scope名称默认授予风险级
customer.agent.read读取客服状态✅低
bot.profile.read读取机器人资料✅低
bot.installation.read读取机器人安装✅低
customer.visitor.manage管理客服访客❌高
customer.session.manage管理客服会话❌高
customer.message.send发送客服消息❌高
customer.message.read读取客服消息❌高
bot.message.send发送机器人消息❌高
bot.message.reply回复机器人消息❌高
event.bot.message订阅机器人消息❌高
event.customer.message订阅客服消息事件❌高
event.customer.session订阅客服会话事件❌高
event.customer.agent订阅客服状态事件❌低

Scope 需按应用类型配置:机器人应用的能力(如 bot.message.reply)不会因给客服类型的应用授权而获得,反之亦然。bot.profile.read 当前仅用于资料读取,未在接口层强制校验。

请求限制​

配额与并发​

平台在鉴权通过后按应用维度限流,超限返回 429 + 429001:

限制项默认值
每分钟请求数6000
每日请求数100000
并发请求数20

具体数值可能按应用单独配置,以控制台展示为准。收到 429 后请退避重试,并复用同一 clientMessageId/thirdMsgId 保证幂等。

请求体大小​

场景上限超限返回
普通开放 API 请求体约 256 KiB413 + 413001
POST /api/open/v2/bot/files(文件上传)约 22 MiB413 + 413001
单个上传文件(机器人)20 MiB400 + 400006
卡片 JSON(msgType=card)64 KiB400 + 400006

卡片结构限制​

卡片消息在发送、更新时都会做结构校验,任一项不满足都返回 400 + 400006 并附具体原因:

项上限
组件总数200
卡片 JSON 体积64 KiB
组件嵌套层级body.elements 之下最多再嵌 8 层子数组(最深第 9 层)
组件 tag必须在白名单内

嵌套层级按子数组层数计:column_set → columns → column → elements 一次消耗两级, 完整规则、组件白名单与全部错误文案见卡片消息。

时效限制​

项值
签名时间戳窗口±300 秒
nonce 有效期300 秒(签名校验通过即消费)
机器人 fileKey 有效期600 秒(10 分钟)
小程序登录 code 有效期120 秒(一次性)
控制台 Access Token 有效期7200 秒(2 小时)