概述
立刻智能体平台提供多组开放 HTTP API,覆盖 AI 会话、人工客服轮询、知识库写入、合作客商写入、服务绩效议题同步和推送通知。外部系统可按需选择接口,使用 API Key 鉴权发起请求;各接口的参数与响应以对应章节为准。
接入流程
Customer Code + API Key
确认所需权限
按接口填写参数
按接口解析结果
Base URL
https://agent.likelic.com/api/v1
认证方式
所有 API 请求必须在 HTTP Headers 中携带以下两个认证字段,且两个凭证必须属于同一企业:
| Header | 说明 | 格式要求 | 示例 |
|---|---|---|---|
X-Customer-Code |
客户唯一代码(由管理员分配) | 1-50 位字母、数字、下划线或短横线 | demo_company |
X-API-Key |
API 访问密钥(在控制台 API 设置中创建) | 以 sk- 开头,后跟 48 位十六进制字符 |
sk-a1b2c3d4e5f6... |
认证校验规则
| 校验项 | 说明 |
|---|---|
| 格式校验 | Customer Code 和 API Key 均需符合上述格式,否则返回 401 |
| 归属校验 | API Key 必须属于该 Customer Code 对应的企业,否则返回 403 |
| 有效期校验 | 如果 API Key 设置了过期时间,过期后将返回 403 |
| 状态校验 | API Key 被禁用后将返回 403 |
智能对话接口 Core
POST /api/v1/chat
向智能体发送问题并获取 AI 回答。支持指定提示词模板和流式/非流式输出模式。
请求参数 (JSON Body)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
question |
string | 必填 | 用户提出的问题内容。不可为空字符串,最大长度 800 个字符。 |
template_id |
string | 可选 | 指定提示词模板 ID(18-32 位字母数字组合)。不传或留空则使用用户后台设置的默认模板。可在控制台「提示词管理」中查看每个模板的 ID。 |
session_id |
string | 可选 | 会话 ID(最长 36 位)。传入相同的 session_id 可将多次连续对话归组为同一会话,在控制台「对话日志」中合并展示。非流式模式下,首次对话不传此参数,系统将自动生成并在响应中返回;流式模式下,若需记录连续会话,应在首次请求就传入,客户端自行生成 UUID,因为流式返回的内容不包含 session_id。 |
stream |
boolean | 可选 | 是否启用流式输出。默认 false。设为 true 时以 SSE (Server-Sent Events) 格式逐字返回。 |
关键词转人工(企业微信)
若企业已在控制台配置「企业微信 → 人工客服转接」(开启转人工推送并填写群机器人 Webhook、触发词),则开放 API 与网页组件、控制台 Chat 共用同一套触发词:当用户 question 中包含任一条触发词时,本次请求不会调用大模型,而是创建/续接人工会话,并向企微群推送卡片。
- session_id:首条转人工请求可不传,响应中的
session_id须保存;后续用户与人工沟通过程中请继续传入同一session_id,追问会推送到同一企微群线程。 - 响应:
data.human_mode === true表示已进入人工模式;data.answer为提示文案;data.human_session_db_id为内部会话主键(与群内卡片「会话记录ID」一致,供排障或对接工单)。 - 退出人工:用户发送结束类话术(与控制台人工会话一致)且传入当前
session_id时,可结束会话并回到 AI。 - 流式:转人工在流式、非流式下均在调用模型之前判定;命中转人工时返回普通 JSON(非 SSE)。
- 按 API Key 控制:专业版及以上在「API 设置 → 管理密钥权限」中可关闭某密钥的转人工,或指定仅使用某条企微「人工客服转接」配置(多配置时避免串线)。基础版(Lite)无企业微信菜单,亦不展示该项,开放 API 侧沿用默认转人工策略(若企业未配企微则不会命中)。
非流式输出 (stream: false)
完整等待模型生成后一次性返回结果,适用于后台任务、批处理等场景。
请求示例(首次对话)
curl -X POST https://agent.likelic.com/api/v1/chat \
-H "Content-Type: application/json" \
-H "X-Customer-Code: your_customer_code" \
-H "X-API-Key: sk-your-api-key-here" \
-d '{
"question": "你们的退货政策是什么?",
"template_id": "Abc123Def456GhiJkl789Mnop"
}'
请求示例(多轮对话,续接会话)
curl -X POST https://agent.likelic.com/api/v1/chat \
-H "Content-Type: application/json" \
-H "X-Customer-Code: your_customer_code" \
-H "X-API-Key: sk-your-api-key-here" \
-d '{
"question": "那退款需要多长时间到账?",
"template_id": "Abc123Def456GhiJkl789Mnop",
"session_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}'
响应示例
{
"success": true,
"data": {
"answer": "根据我们的退货政策,您可以在收到商品后 7 天内申请无理由退货...",
"session_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"sources": [
{
"question": "退货政策有什么规定?",
"score": 0.92
}
],
"model": "qwen-plus",
"tokensUsed": 486,
"responseTime": 1523
}
}
响应字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
success | boolean | 请求是否成功 |
data.answer | string | AI 生成的回答内容 |
data.session_id | string | 会话 ID。首次对话由系统自动生成,后续对话请回传此值以续接同一会话 |
data.sources | array | 命中的知识库条目及匹配分数 |
data.model | string | 本次使用的模型名称 |
data.tokensUsed | number | 本次消耗的 Token 总量 |
data.responseTime | number | 端到端响应时间 (毫秒) |
data.human_mode | boolean | 可选。为 true 时表示本请求已走关键词转人工,未调用大模型 |
data.human_session_db_id | number | 可选。人工会话在系统中的主键 ID,与企微卡片「会话记录ID」一致 |
data.session_ended | boolean | 可选。用户结束人工会话时为 true |
流式输出 (stream: true)
以 SSE (Server-Sent Events) 格式实时推送生成内容,适用于前端实时展示打字效果等交互场景。
session_id(客户端自行生成 UUID),因为流式返回的内容不包含 session_id,无法像非流式那样从响应中获取。
请求示例(流式 + 首次会话,需传入 session_id 以记录连续对话)
curl -X POST https://agent.likelic.com/api/v1/chat \
-H "Content-Type: application/json" \
-H "X-Customer-Code: your_customer_code" \
-H "X-API-Key: sk-your-api-key-here" \
-d '{
"question": "如何申请退款?",
"template_id": "Abc123Def456GhiJkl789Mnop",
"session_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"stream": true
}'
流式响应格式
响应 Content-Type 为 text/event-stream,数据以 SSE 格式逐行推送:
data: {"content":"根据"}
data: {"content":"我们"}
data: {"content":"的退货"}
data: {"content":"政策,"}
data: {"content":"..."}
data: [DONE]
data: 行包含一个 JSON 对象,其中 content 字段为增量文本片段。当收到 data: [DONE] 时表示生成完毕。
JavaScript 流式调用示例
// 若需记录连续会话,流式首次请求需传入 session_id(流式响应不包含 session_id)
const sessionId = crypto.randomUUID();
const response = await fetch('https://agent.likelic.com/api/v1/chat', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Customer-Code': 'your_customer_code',
'X-API-Key': 'sk-your-api-key-here'
},
body: JSON.stringify({
question: '如何申请退款?',
template_id: 'Abc123Def456GhiJkl789Mnop',
session_id: sessionId,
stream: true
})
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
let result = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
const lines = chunk.split('\n');
for (const line of lines) {
if (line.startsWith('data: ') && line !== 'data: [DONE]') {
const json = JSON.parse(line.slice(6));
result += json.content;
console.log(json.content); // 实时输出
}
}
}
Python 调用示例
import requests
import json
url = "https://agent.likelic.com/api/v1/chat"
headers = {
"Content-Type": "application/json",
"X-Customer-Code": "your_customer_code",
"X-API-Key": "sk-your-api-key-here"
}
# 非流式调用(首次对话,不传 session_id)
resp = requests.post(url, headers=headers, json={
"question": "你们的退货政策是什么?",
"template_id": "Abc123Def456GhiJkl789Mnop"
})
data = resp.json()["data"]
session_id = data["session_id"] # 保存用于后续多轮对话
print(data["answer"])
# 多轮对话(传入首次返回的 session_id)
resp = requests.post(url, headers=headers, json={
"question": "那退款需要多长时间到账?",
"template_id": "Abc123Def456GhiJkl789Mnop",
"session_id": session_id
})
print(resp.json()["data"]["answer"])
# 流式调用(若需记录连续会话,首次请求需传入 session_id,因流式响应不包含 session_id)
import uuid
stream_session_id = str(uuid.uuid4())
resp = requests.post(url, headers=headers, json={
"question": "还有其他注意事项吗?",
"template_id": "Abc123Def456GhiJkl789Mnop",
"session_id": stream_session_id,
"stream": True
}, stream=True)
for line in resp.iter_lines():
if line:
decoded = line.decode("utf-8")
if decoded.startswith("data: ") and decoded != "data: [DONE]":
data = json.loads(decoded[6:])
print(data["content"], end="", flush=True)
人工客服回复轮询 HUMAN
GET /api/v1/human-replies
在 human_mode 为 true 且拿到与 /chat 相同的 session_id 后,可用本接口轮询企微群内回复。鉴权与 Chat 一致:X-Customer-Code、X-API-Key。human_mode 的触发方式见 AI 会话接口「关键词转人工(企业微信)」。
查询参数
| 参数 | 说明 |
|---|---|
session_id | 必填,与对话接口一致,最长 36 字符 |
since_id | 可选,默认 0。仅返回 id > since_id 的消息(与控制台/组件 human-replies 行为一致) |
响应 data.messages[]
| 字段 | 说明 |
|---|---|
id | 消息主键,下次请求作 since_id |
content | 正文 |
wechat_from_user | 企微侧发送者标识;系统提示(如会话超时结束)为 __system__。前端展示建议:人工客服 {wechat_from_user}:{content},系统消息可仅展示 content |
created_at | 创建时间 |
请求示例
curl -G "https://agent.likelic.com/api/v1/human-replies" \
-H "X-Customer-Code: your_customer_code" \
-H "X-API-Key: sk-your-api-key-here" \
--data-urlencode "session_id=a1b2c3d4-e5f6-7890-abcd-ef1234567890" \
--data-urlencode "since_id=0"
知识库写入接口 KB
POST /api/v1/knowledge/entries
从外部系统向本企业知识库新增一条问答对,鉴权与 Chat 相同(X-Customer-Code + X-API-Key)。校验通过后先写入 MySQL并立即返回成功;向量嵌入与 Qdrant 同步在后台异步执行(与控制台 Excel 批量导入的第二阶段一致),稍后在智能对话中即可检索到该条。
category 必须是贵企业知识库中已存在且未停用的分类名称,本接口不会自动创建分类;请先在控制台「知识库 → 分类管理」中建好分类,再用该分类名调用。若方案不支持配图,请勿传 answer_image。
请求参数 (JSON Body)
本接口请求体上限 512 KB(大于通用 v1 的 100 KB)。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
question |
string | 必填 | 问题内容,trim 后非空,最大 800 字符。 |
answer |
string | 必填 | 答案正文,trim 后非空,最大 5000 字符。 |
category |
string | 必填 | 分类名称,最大 20 字符。必须是贵企业分类目录中已存在且未停用的分类名(与控制台「分类管理」一致);对不上或该分类已停用时返回 400,并在 data.existing_categories 中附带当前可用的分类名列表。本接口不会新建分类。 |
answer_image |
string | 可选 | 答案配图,须为可访问的 http(s) 图片 URL,最大 2048 字符。仅专业版及以上支持;基础版传入将返回 403。 |
keywords |
string | 可选 | 关键词,多个关键词用英文逗号 , 分隔(不可用中文逗号)。整段字符串最大 200 字符;单个关键词最长 20 字符;最多 10 个关键词。 |
created_by |
string | 可选 | 对接方自定义的创建人标识(如对方系统用户名),最大 100 字符;便于与控制台「创建人」列对齐审计。 |
成功响应示例
{
"success": true,
"data": {
"id": 12345,
"category": "产品说明",
"created_by": "crm_sync",
"updated_by": null,
"vector_sync": "queued",
"message": "Entry saved to database. Vector embedding sync runs asynchronously; ..."
}
}
配额不足示例(403)
{
"success": false,
"message": "Knowledge base entry limit reached for your plan (...)",
"data": { "limit": 10000, "current": 10000, "remaining": 0 }
}
分类名对不上示例(400)
category 在分类目录中不存在、或该分类已停用时返回:
{
"success": false,
"message": "category \"未知分类\" does not exist as an enabled category in this customer's category catalog. Use one of data.existing_categories, or create the category in the console first.",
"data": {
"existing_categories": ["默认", "产品说明"]
}
}
请求示例
curl -X POST https://agent.likelic.com/api/v1/knowledge/entries \
-H "Content-Type: application/json" \
-H "X-Customer-Code: your_customer_code" \
-H "X-API-Key: sk-your-api-key-here" \
-d '{
"question": "如何重置密码?",
"answer": "请在登录页点击「忘记密码」并按邮件指引操作。",
"category": "账户与安全",
"keywords": "password,reset,login",
"answer_image": "https://example.com/help/screenshot.png"
}'
更新单条知识(PUT)
PUT /api/v1/knowledge/entries/:id
使用创建接口返回的 data.id 作为路径参数 :id,更新同一条问答。请求体字段与 POST 相同,但 created_by 会被忽略(创建人不可改,响应回库中原值);请用可选字段 updated_by(最大 100 字符)作为本次修改人标识。若不传 answer_image,则保留该条原有配图。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
updated_by |
string | 可选 | 本次更新的操作者标识,最大 100 字符。 |
更新成功响应示例
{
"success": true,
"data": {
"id": 12345,
"category": "产品说明",
"created_by": "crm_sync",
"updated_by": "operator_a",
"vector_sync": "queued",
"message": "Entry updated. Vector embedding sync runs asynchronously; ..."
}
}
curl -X PUT https://agent.likelic.com/api/v1/knowledge/entries/12345 \
-H "Content-Type: application/json" \
-H "X-Customer-Code: your_customer_code" \
-H "X-API-Key: sk-your-api-key-here" \
-d '{
"question": "如何重置密码?",
"answer": "请在登录页点击「忘记密码」并按邮件指引操作。",
"category": "账户与安全",
"keywords": "password,reset",
"updated_by": "operator_a"
}'
合作客商写入 WEWORK PARTNER
POST /api/v1/wework/partner-companies/import
从外部系统批量写入合作客商主数据,鉴权与 Chat 相同(X-Customer-Code + X-API-Key)。按 (租户, company_code) upsert:company_code 已存在则合并更新,不存在则新增。行为与控制台「导入合作公司」Excel 导入完全一致。
403。控制台 Excel 导入不受此开关影响。
company_code 再次写入会覆盖销售、跟踪人、状态等已维护字段。无软删/版本机制,请确保来源数据准确。
请求参数 (JSON Body)
顶层字段 rows 为数组,非空且不超过 5000 行;每行字段如下:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
company_code |
string | 必填 | 租户内唯一键,最大 64 字符。用于 upsert 定位:同一代码再次导入即更新该条。 |
company_name |
string | 必填 | 公司全称,最大 255 字符。 |
company_short_name |
string | 可选 | 公司简称,最大 128 字符。 |
sales_name |
string | 可选 | 销售,最大 128 字符。 |
tracker_name |
string | 可选 | 跟踪人,最大 128 字符。 |
company_status |
string | 可选 | 合作状态。取中文 已合作 / 试用中 / 已过期,或枚举 cooperating / trial / expired;留空为未标记。传入非法值则该行被跳过。 |
行级校验
缺少 company_code 或 company_name、或 company_status 非法的行会被跳过并计入 data.skipped,跳过原因逐条列在 data.errors(不影响其余有效行写入)。
请求示例
curl -X POST https://agent.likelic.com/api/v1/wework/partner-companies/import \
-H "Content-Type: application/json" \
-H "X-Customer-Code: your_customer_code" \
-H "X-API-Key: sk-your-api-key-here" \
-d '{
"rows": [
{
"company_code": "C1001",
"company_name": "示例科技有限公司",
"company_short_name": "示例科技",
"sales_name": "张三",
"tracker_name": "李四",
"company_status": "已合作"
},
{
"company_code": "C1002",
"company_name": "另一家公司",
"company_status": "trial"
}
]
}'
成功响应示例
{
"success": true,
"data": {
"inserted": 1,
"updated": 1,
"skipped": 0,
"errors": []
}
}
含跳过行的响应示例
{
"success": true,
"data": {
"inserted": 2,
"updated": 0,
"skipped": 1,
"errors": ["第 3 行:缺少公司代码"]
}
}
错误示例
// 未启用 wework_partner,或调用方 Key 未获授权 → 403
{ "success": false, "message": "开放 API「合作客商写入」未在系统设置中启用" }
{ "success": false, "message": "当前 API Key 未被授权调用「合作客商写入」接口" }
// rows 缺失/非数组,或超过 5000 行 → 400
{ "success": false, "message": "缺少 rows 数组" }
{ "success": false, "message": "单次最多导入 5000 行" }
服务绩效议题同步 WEWORK QA
GET /api/v1/wework/qa/issues
供外部系统(如部门管理系统)轮询拉取已评分的绩效议题,写入自有业务库。鉴权与 Chat / 知识库相同(X-Customer-Code + X-API-Key),无需 IP 白名单。
channel 字段区分入账。
现有对接方会开始收到 QQ 议题。若仍按「全部是企微群议题」入账,或用 company_name 关联客户,可能错账或关联不上。
增量游标拉不到上线前已评分的 QQ 议题:这些议题的 sync_at 早于对接方当前游标,增量轮询补不回这批历史记录,只有全量重拉(不传 sync_since)才能补齐。
code 不变,程序判断请以状态码与 code 为准,勿匹配文字。套餐:仅旗舰版(Ultra)且已开通「服务绩效」的租户可用。开通 QQ 服务绩效的租户同时返回 QQ 群议题。仅返回已有评分的议题(
assess_status 为 success 或 failed 均返回);数据范围与控制台绩效看板一致(保留期内)。
查询参数(列表)
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
sync_since |
string | 可选 | 增量游标:返回 sync_at >= sync_since 的议题。格式 YYYY-MM-DDTHH:mm:ss、YYYY-MM-DD HH:mm:ss 或 YYYY-MM-DD(当天 00:00:00)。不传则全量分页拉取。 |
page |
int | 可选 | 页码,从 1 开始,默认 1。 |
limit |
int | 可选 | 每页条数,默认 50,最大 100。 |
列表按 sync_at ASC, id ASC 排序,便于增量游标推进。响应 meta 含 page、limit、total、retention_from(生效保留起始日);传入 sync_since 时另回显 meta.sync_since。
列表响应 data[] 字段
| 字段 | 类型 | 说明 |
|---|---|---|
id | number | 议题唯一 ID,建议作为对方系统 source_id 做幂等 upsert |
channel | string | wework 企微群 / qq QQ 群 |
company_name | string \| null | 群所属公司全称;若未维护则回退为群名称。QQ 群可在群管理里绑定合作公司;没绑定的 QQ 议题仍回退为 QQ 群名 |
company_status | string \| null | 客户合作状态:已合作 / 试用中 / 已过期(未设置时为 null)。QQ 议题没绑定公司时为 null |
summary | string \| null | 议题摘要 |
start_time | string | 议题在群聊中的开始时间 |
customer_name | string \| null | 客户展示名 |
status | string | open / resolved / timeout |
score_total | number \| null | 综合质量分 0–100;评分失败时为 null |
assess_status | string | success / failed |
primary_staff_name | string \| null | 主责员工姓名(有效回复数最高;并列取第一个) |
staffs | array | 参与员工:name、effective_reply_count |
created_at | string | 议题入库时间(可作对方系统创建时间) |
sync_at | string | 增量游标:末次值得同步的变化时间(状态变更 / 首次评分 / 人工重评) |
列表响应示例
{
"success": true,
"data": [
{
"id": 12345,
"channel": "wework",
"company_name": "示例科技有限公司",
"company_status": "已合作",
"summary": "客户反馈产品无法登录",
"start_time": "2026-06-24T10:30:00",
"customer_name": "张三",
"status": "resolved",
"score_total": 85,
"assess_status": "success",
"primary_staff_name": "李四",
"staffs": [
{ "name": "李四", "effective_reply_count": 3 },
{ "name": "王五", "effective_reply_count": 1 }
],
"created_at": "2026-06-24T10:35:00",
"sync_at": "2026-06-24T10:40:00"
}
],
"meta": {
"page": 1,
"limit": 50,
"total": 128,
"retention_from": "2026-05-25",
"sync_since": "2026-06-24T10:00:00"
}
}
推荐同步流程
- 首次全量:不传
sync_since,按page分页直至data为空;每条以idupsert。 - 增量轮询(建议 5–15 分钟):
sync_since = 上次 max(sync_at) - 1 分钟(重叠防漏);同一id再次出现则 UPDATE。 - 停服恢复:沿用旧
sync_since即可补回期间变更。 - 多页:同一
sync_since下若total > limit,继续page=2,3,...直至拉完本批。
请求示例(增量拉取)
curl -G "https://agent.likelic.com/api/v1/wework/qa/issues" \
-H "X-Customer-Code: your_customer_code" \
-H "X-API-Key: sk-your-api-key-here" \
--data-urlencode "sync_since=2026-06-24T10:00:00" \
--data-urlencode "page=1" \
--data-urlencode "limit=100"
单条详情 GET /api/v1/wework/qa/issues/:id
GET /api/v1/wework/qa/issues/:id
返回字段与列表项相同,用于按 ID 补拉或校验。路径参数 :id 为议题 ID。
curl "https://agent.likelic.com/api/v1/wework/qa/issues/12345" \
-H "X-Customer-Code: your_customer_code" \
-H "X-API-Key: sk-your-api-key-here"
成功返回 { "success": true, "data": { ... } };不存在、未评分或超出保留期返回 404。
推送通知 OUTBOUND
推送通知让你的业务系统(ERP、CRM、计费系统等)通过开放 API,经企微机器人或 QQ 机器人向客户所在的企微群 / QQ 群发送通知,例如「贵司服务将于 30 天后到期」。业务系统只管提交,平台负责找到目标群、按时段排队、控制发送节奏,并提供逐群回执。本能力共四个接口:
| 接口 | 用途 |
|---|---|
GET /api/v1/rooms | 接口一:查询群清单(可作为通知目标的企微群与 QQ 群) |
POST /api/v1/notifications | 接口二:下发通知(受理后返回 202,后台排队发送) |
GET /api/v1/notifications/{biz_msg_id} | 接口三:查询回执(逐群发送结果与整条聚合状态) |
POST /api/v1/notifications/{biz_msg_id}/cancel | 接口四:撤回通知(取消尚未发出的群,已发出的不可撤回) |
403 plan_required。
适用场景
- 合同 / 服务到期前的续费提醒(如到期前 30 / 15 / 7 / 1 天各提醒一次)。
- 账单、发货、单证等业务状态变化时通知客户群。
- 需要在消息里 @ 对接人(如「如需续费请联系@张三 」)。
只发群,不发私聊;支持纯文本,以及最多 3 个附件(图片、文件、链接卡片);一次请求提交一条通知,不支持批量或修改;尚未发出的部分可以撤回。
启用方式
403 scope_disabled。
- 准备 API 密钥:在控制台「外部拓展 → API 设置」创建一个
sk-开头的密钥,建议单独给推送通知使用。密钥只能放在你自己的后端,切勿写进前端代码。 - 授权 Key:在「系统设置 → 开放 API 权限」中打开「推送通知」,并勾选允许调用的 API Key,保存。
- 设置允许推送时段(可选):在「系统设置 → 允许推送时段」中配置(北京时间)。默认 09:00–11:00 与 14:00–17:00 两段;清空全部时段表示不限时段、随时可发。
- 绑定群与公司(按公司发送时需要):在「合作管理 → 群管理」给客户群填上公司代码(可先导入合作公司再自动匹配)。只按群 ID 发送时可跳过这一步。
- QQ 群需群主开通主动推送:群主在群内打开「机器人主动在群聊内发言」,否则发往该群的通知会被跳过。
之后若在系统设置里关闭「推送通知」,已受理但还没发出的通知也会一并停止发送(回执中落 failed,原因 scope_disabled),重新开启后不会自动恢复,需要业务系统重新下发。
通用约定
| 项目 | 约定 |
|---|---|
| 接口地址 | https://agent.likelic.com/api/v1 |
| 鉴权 | 与其他开放 API 相同,Header 携带 X-Customer-Code(企业唯一代码)与 X-API-Key(sk- 开头,须已在「推送通知」中被授权) |
| 请求体 | JSON(Content-Type: application/json) |
| 响应格式 | 成功为 { "success": true, "data": ..., "meta": ... }(meta 仅列表接口有);失败为 { "success": false, "message": "...", "code": "..." }。请按 HTTP 状态码 + code 联合判断,message 是给人看的说明,可能调整,不要用于程序分支。参数校验失败(400)时另带 field 指明出错字段 |
| 时间 | 所有时刻都是带 +08:00 偏移的 ISO 8601 字符串(北京时间),如 2026-10-24T09:37:00.000+08:00,无论调用方在哪个时区都能直接解析。「当天」「次日」一律按北京自然日计 |
| 分页 | 列表接口用 page(从 1 开始,默认 1)与 limit(默认 20,最大 200),响应的 meta 为 { page, limit, total } |
接口一:查询群清单 GET /api/v1/rooms
GET /api/v1/rooms
拉取本企业全部可作为通知目标的企微群与 QQ 群。常用于:① 在自己系统里做「客户 ↔ 群」绑定(用于按群 ID 发送);② 核对哪些群还没绑公司、哪些群当前推不出去。
查询参数(均可选)
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
channel | string | 可选 | wework 或 qq |
company_code | string | 可选 | 只看绑定了该公司代码的群 |
push_state | string | 可选 | ready、blocked 或 unknown |
page | int | 可选 | 页码,从 1 开始,默认 1 |
limit | int | 可选 | 每页条数,默认 20,最大 200 |
取值非法时返回 400 validation_error,不会静默忽略。结果固定按 channel → room_name → room_id 升序排列,翻页不会漏项或重复。没有任何群时返回 200、data 为空数组、meta.total 为 0。
请求示例
curl -G "https://agent.likelic.com/api/v1/rooms" \
-H "X-Customer-Code: your_customer_code" \
-H "X-API-Key: sk-your-api-key-here" \
--data-urlencode "company_code=ACME01" \
--data-urlencode "page=1" \
--data-urlencode "limit=20"
响应示例
{
"success": true,
"data": [
{
"channel": "wework",
"instance_id": 3,
"instance_name": "售后企微机器人",
"room_id": "10696049xxxxxxxxx",
"room_name": "艾克米物流售后群",
"member_count": 12,
"company_code": "ACME01",
"company_name": "艾克米物流",
"company_match_status": "auto",
"push_state": "ready",
"push_blocked_reason": null
}
],
"meta": { "page": 1, "limit": 20, "total": 1 }
}
响应 data[] 字段
企微群与 QQ 群字段完全一致,只靠 channel 区分;没有值的字段返回 null,不会省略。
| 字段 | 类型 | 说明 |
|---|---|---|
channel | string | wework 或 qq |
instance_id | number | 机器人实例 ID(数字) |
instance_name | string | null | 机器人实例名称 |
room_id | string | 群 ID(按群发送时使用) |
room_name | string | null | 群名称 |
member_count | number | null | 群成员数 |
company_code / company_name | string | null | 绑定的公司代码 / 全称,未绑定为 null |
company_match_status | string | null | 公司匹配方式:auto(自动匹配)、manual(人工填写)、pending(匹配待定,尚未绑定)或 null |
push_state | string | 可推送状态,见下表 |
push_blocked_reason | string | null | push_state 为 blocked 时的原因,其余为 null |
可推送状态 push_state
| push_state | push_blocked_reason | 含义 | 发通知会怎样 |
|---|---|---|---|
ready | null | 可正常推送 | 正常排队发送 |
unknown | null | 仅 QQ 群:还没试发过,不知道群主是否开通主动推送 | 正常排队、照常尝试 |
blocked | instance_offline | 机器人实例离线(企微掉线 / 登录失效,QQ 实例被停用),人工处理后可恢复 | 照常受理,排队等实例恢复 |
blocked | bot_not_in_room | 曾因机器人不在群而发送失败 | 跳过,直至运营检测后清除 |
blocked | proactive_push_disabled | 仅 QQ 群:群主未开通主动推送 | 跳过,直至群主开通并检测 |
push_state 与是否绑定公司无关:未绑公司但可推送的群仍是 ready,可以按群 ID 直接发送。已删除的机器人实例下的群不会出现在清单里。
接口二:下发通知 POST /api/v1/notifications
POST /api/v1/notifications
提交一条通知。平台当场解析目标群、生成逐群投递单并返回 202;实际发送由平台按时段与节奏在后台完成,本接口不返回发送结果,请用接口三查询回执。
请求参数 (JSON Body)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
biz_msg_id | string | 必填 | 业务幂等键,1~128 个字符,不能全为空白,不能以 console-probe- 开头(系统保留)。比较时不区分大小写、忽略尾随空格,见下文「幂等与重复提交」 |
target | object | 必填 | 发给谁,四种形态恰好选一种,见下表 |
text | string | 条件必填 | 通知正文,纯文本;不带 attachments 时必填,带附件时可省略。去掉首尾空白后不能为空,且不超过 1000 个字符(按 Unicode 字符计,一个汉字或一个 emoji 都算 1 个)。首尾空白会被去掉 |
attachments | array | 可选 | 附件,1~3 项;每项 type 为 image、file 或 link,字段见下文「附件」 |
urgent | boolean | 可选 | 默认 false。true 表示紧急通知,不受允许推送时段限制,见下文「推送时段与排期」 |
target 的四种形态
| 形态 | 写法 | 说明 |
|---|---|---|
| 按公司代码 | { "company_code": "ACME01" } | 发到绑定了该公司代码的全部群(如售前群、售后群都会收到)。可另加 "channel": "wework" 或 "qq" 只发一个渠道,不加则两个渠道都发 |
| 按公司全称 | { "company_name": "艾克米物流" } | 按合作公司全称精确匹配后,同样发到该公司的全部群;也可另加 channel |
| 按群 | { "channel": "qq", "instance_id": 12, "room_id": "..." } | 三个字段须同时提供,取自接口一的返回项;只发这一个群 |
| 按会话串 | { "conversation": "R:{群ID}@{成员ID}" } | 直接指定群,并可在消息开头 @ 成员,见下文「会话串定位与开头 @」 |
- 同时给了两种形态,或一种都没给 →
400validation_error。 - 按公司全称匹配到多家同名公司时不会自动挑选,返回
409company_name_ambiguous并在data.candidates列出每家的company_code与company_name,请改用公司代码重发。 - 同一个群被多个机器人收录时只发一次:按公司发送时,平台按群去重,同一个企微群(或 QQ 群)即使被本企业多个机器人实例收录,也只生成一条投递单,由其中推送状态最好的实例发送。
附件(attachments)
一条通知最多带 3 个附件,写在请求体的 attachments 数组里;带附件时 text 可省略(无正文也无附件则返回 400 validation_error,field 为 text)。每项按 type 取下列字段:
| type | 字段 | 说明 |
|---|---|---|
image | url 或 base64(二选一)、file_name(可选) | 图片;url 为不超过 1024 个字符的 http(s) 地址;file_name 最长 100 个字符,缺省时按「图片 序号.扩展名」补齐 |
file | url 或 base64(二选一)、file_name(必填) | 文件;file_name 最长 100 个字符,QQ 里下载得到的文件名就是它 |
link | title(必填,≤ 64 个字符)、url(必填,≤ 1024 个字符)、description(可选,≤ 200 个字符)、image_url(可选,≤ 1024 个字符) | 链接卡片;回执里给出的是实际目标地址 |
image/file的url与base64不能同时给、也不能都不给,否则400validation_error(field形如attachments[1].url)。- 平台在受理时把图片与文件转存到自己的存储再发送;
url须能被公网访问,转存时的抓取最多等待 30 秒。 - 图片支持
jpg/jpeg/png/gif/webp/bmp,单个不超过 10MB;文件支持pdf/doc/docx/xls/xlsx/ppt/pptx/txt/csv/zip/rar,单个不超过 20MB。 - 类型按文件实际内容判定,改扩展名无效;可执行文件(Windows / Linux / macOS 可执行程序、带解释器声明的脚本)一律拒绝。
附件被拒绝时返回 400 attachment_rejected,并带 index(第几个附件,从 0 计)与 reason;被拒绝的请求不占用 biz_msg_id,修正后可用同一个键重新提交。
reason | 含义 |
|---|---|
fetch_failed | 按 url 抓取失败(无法访问、返回错误状态等) |
fetch_timeout | 抓取超时 |
unsafe_url | 地址不被允许(内网地址、非 http(s) 等) |
too_large | 超过大小上限(图片 10MB、文件 20MB) |
type_not_allowed | 实际类型不在白名单内,或与声明的类型不符 |
executable | 识别为可执行文件 |
附件在两个渠道里的呈现
- 企微群:正文在前,然后逐条发出原生的图片、文件和链接卡片。
- QQ 群:正文与全部附件合成一条消息——图片与文件写成下载链接,链接卡片写成「标题:链接」;下载得到的文件名为你给的
file_name。 - QQ 合成长度校验:目标含 QQ 群时,平台按合成后的纯文本计算长度,超过 2000 字受理时即返回
400qq_message_too_long(带实际长度length与上限limit),不截断正文、不丢附件,也不占用biz_msg_id;目标只含企微群时不做此校验。 - 部分送达(例如企微里正文已发出、后面的附件失败)按失败处理,回执里
parts_delivered/parts_total记录送达进度;重投或续发只补发未送达的部分。
带附件的完整请求示例
curl -X POST https://agent.likelic.com/api/v1/notifications \
-H "Content-Type: application/json" \
-H "X-Customer-Code: your_customer_code" \
-H "X-API-Key: sk-your-api-key-here" \
-d '{
"biz_msg_id": "renew-ACME01-2026-10-24-d7",
"target": { "company_code": "ACME01" },
"text": "贵司服务将于 7 天后到期,续费资料见附件。",
"attachments": [
{ "type": "file", "url": "https://example.com/quote.pdf", "file_name": "续费报价单.pdf" },
{ "type": "link", "title": "在线续费", "url": "https://example.com/renew" }
]
}'
会话串定位与开头 @(target.conversation)
除按公司、按群外,还可以用会话串直接指定群,并在消息开头 @ 成员:
- 企微群:
R:{群ID}@{成员ID}@{成员ID} - QQ 群:
{group_openid}@{成员ID}(不带R:前缀)
示例(均为占位 ID,请换成你自己的):{ "conversation": "R:1078xxxxxxxxxxxx@1688xxxxxxxxxxxx" }。规则:
- 平台按格式标记判定渠道(有
R:为企微,无前缀为 QQ);可以另给channel,但与格式矛盾时报错。 - 成员最多 20 个;成员之间不能有空段、重复或空白;总长不超过 512。非法写法(如
R:1078@a@@b、显式给了channel: "qq"却以R:开头、21 个成员)返回400validation_error,field为target.conversation。没写channel时,以R:开头一律按企微群处理:把 QQ 群串误加了R:会被当成企微群查找,通常返回404room_not_found,而不是400。 conversation与公司代码、公司全称、按群三种定位方式互斥,同时出现返回400。- 该群在本企业所有未删除的实例下都没有收录时返回
404room_not_found;实例由平台按群自动定位。
会话串里的成员会在正文那一条消息的开头依次被 @(企微在群内 @,QQ 按出站提及格式),之后紧接正文,只发一条。正文里的 @姓名 照常解析,同一成员只 @ 一次;成员 ID 不在群内时消息照常发送,并在回执 warnings 里记一条;QQ 实例关闭 markdown 时放弃提及。带附件时 @ 只附在正文那一条上,没有正文时开头只含 @。
请求体大小与并发限制
- 下发接口的请求体上限为 85MB(带
base64附件时留意体积),超限返回413payload_too_large。 - 同一租户同时处理的大请求(超过 2MB)最多 4 个,超出返回
429too_many_large_requests,请稍后重试。 - 同一个
biz_msg_id并发提交时,后到的请求可能返回409notification_in_progress,稍等片刻用接口三查询回执即可。
以上 400 / 413 / 429 都表示整条不受理,不生成投递单,也不占用 biz_msg_id。
请求示例
curl -X POST https://agent.likelic.com/api/v1/notifications \
-H "Content-Type: application/json" \
-H "X-Customer-Code: your_customer_code" \
-H "X-API-Key: sk-your-api-key-here" \
-d '{
"biz_msg_id": "renew-ACME01-2026-10-24-d30",
"target": { "company_code": "ACME01" },
"text": "您好,贵司的 XXX 服务将于 2026 年 10 月 24 日到期,您请看是否安排续费,如需续费请联系@张三 ,谢谢您的支持!"
}'
首次受理响应示例(202)
{
"success": true,
"data": {
"notification_id": 1024,
"biz_msg_id": "renew-ACME01-2026-10-24-d30",
"duplicate": false,
"summary": { "total": 2, "queued": 1, "skipped": 1 },
"deliveries": [
{
"delivery_id": 5001,
"channel": "wework",
"instance_id": 3,
"room_id": "10696049xxxxxxxxx",
"room_name": "艾克米物流售后群",
"company_code": "ACME01",
"company_name": "艾克米物流",
"status": "pending",
"skip_reason": null,
"scheduled_at": "2026-09-28T09:37:00.000+08:00"
},
{
"delivery_id": 5002,
"channel": "qq",
"instance_id": 12,
"room_id": "C9F3A2xxxxxxxxxxxxxxxxxxxxxxxxxx",
"room_name": "艾克米物流服务群",
"company_code": "ACME01",
"company_name": "艾克米物流",
"status": "skipped",
"skip_reason": "proactive_push_disabled",
"scheduled_at": null
}
]
}
}
summary满足queued + skipped = total;deliveries固定按delivery_id升序。- 受理时即可判定发不进去的群(
bot_not_in_room、proactive_push_disabled)直接落skipped,不会进入发送队列;实例离线不算跳过,照常排队。 - 全部目标群都被跳过时返回
409all_targets_skipped,data.deliveries逐条列出群与skip_reason,本次不受理、不占用biz_msg_id——群主开通或机器人重新进群、并在合作管理中完成检测后,可用同一个biz_msg_id重新提交。 - 任何 4xx 都表示整条不受理,一条投递单都不会生成,修正后重发即可。
推送时段与排期
- 受理时若当前时刻(北京时间)落在允许推送时段内,
scheduled_at即为当前时刻;若在时段外,则排到下一个时段内的随机时刻(按分钟),同一批通知的发送时刻会被自然打散,不会半夜打扰客户,也不会在同一时刻集中发出。 urgent: true时不受时段限制,scheduled_at为受理时刻;但每日发送上限等保护照常生效——urgent只放宽「什么时候发」,不放宽「能不能发」。- 平台会在同一个机器人的相邻两条消息之间自动留出间隔,并与消息群发共用企微实例的每日发送上限。当天额度用完、或时段配置变更后已不在时段内时,投递单保持
pending,scheduled_at顺延到之后的时段,不会因此失败。因此scheduled_at是计划时刻,可能随排队情况后移。
幂等与重复提交
biz_msg_id在本企业内唯一。重复提交相同的biz_msg_id返回200、duplicate: true,并回吐首次生成的notification_id与投递单当前状态(字段同接口三的deliveries),不会新建投递单,也不会用本次请求的其他字段覆盖首次内容。并发重复提交同样只会受理一次。summary为首次受理时的快照(排队 / 跳过计数不随投递进展变化),不能用来判断是否已发出;实时状态以deliveries[].status或接口三GET /api/v1/notifications/{biz_msg_id}为准。biz_msg_id比较时不区分大小写、忽略尾随空格:例如Order-a1与order-A1视为同一个键。请不要依赖大小写或尾随空格来区分不同的通知,否则后一条会被当作重复提交而不会发出。- 建议用「业务对象 + 业务日期 + 提醒轮次」拼出稳定的键,例如
renew-ACME01-2026-10-24-d30;重试或跑批重复执行时沿用同一个键即可,客户不会收到两条相同提醒。
@ 提及的书写约定
正文里写 @姓名 可以在群里 @ 到对应的人(被 @ 的人会收到提醒),常用于「如需续费请联系@张三 」:
@姓名后必须加一个空格(或换行),如请联系@张三 ,谢谢。平台取@到下一个空白之间的整段文字作为姓名、并要求完全相等,所以@张三,谢谢、@张三您好这类连写不会被识别;群里同时有「张三」和「张三丰」时,@张三只会 @ 到「张三」。@可以出现在正文任意位置。找不到这个人、或本群有多个同名的人时,平台不会乱 @,@姓名按纯文本原样发出,消息照常送达,并在该投递单的warnings中说明。- 优先匹配本企业员工(员工需在控制台「成员与权限」绑定企微 / QQ 身份),其次匹配群成员;被 @ 的人必须在该群内。
- 不支持
@所有人,不支持按手机号或工号 @ 人。
QQ 群的额外限制(渠道差异,不是故障):
- QQ 只能 @ 在本群有发言记录的人。QQ 实例默认的「仅 @ 回复」模式下,机器人只收到 @ 它的消息,所以只有在本群 @ 过机器人的人才 @ 得到,命中率低;把实例改为「全量消息作上下文,仅 @ 回复」后命中率会明显提升。
- 客户看到的是对方的 QQ 群昵称,不是正文里写的姓名。
- 员工的 QQ 身份按机器人绑定,换一个 QQ 机器人须重新绑定。
- 链接后面紧跟文字时,平台会在链接末尾自动补一个空格,否则 QQ 会把后面的文字并入链接、点开是错误地址。这是正文「原样发出」的唯一例外。
- 行首缩进不会显示;带
?&#等参数的链接可能无法点击,但文字逐字正确、可以复制。
接口三:查询回执 GET /api/v1/notifications/{biz_msg_id}
GET /api/v1/notifications/{biz_msg_id}
用下发时的 biz_msg_id 查询这条通知发到了哪些群、是否发出(biz_msg_id 放进 URL 路径时请做 URL 编码)。biz_msg_id 在本企业下不存在时返回 404 notification_not_found。
请求示例
curl "https://agent.likelic.com/api/v1/notifications/renew-ACME01-2026-10-24-d30" \
-H "X-Customer-Code: your_customer_code" \
-H "X-API-Key: sk-your-api-key-here"
响应示例
{
"success": true,
"data": {
"notification_id": 1024,
"biz_msg_id": "renew-ACME01-2026-10-24-d30",
"target_kind": "company_code",
"target_value": "ACME01",
"text": "您好,贵司的 XXX 服务将于 2026 年 10 月 24 日到期,您请看是否安排续费,如需续费请联系@张三 ,谢谢您的支持!",
"urgent": false,
"accepted_at": "2026-09-27T20:15:03.000+08:00",
"attachments": [],
"cancelled_at": null,
"cancel_source": null,
"cancel_reason": null,
"status": "sent",
"summary": { "total": 2, "queued": 0, "sent": 1, "failed": 0, "skipped": 1, "cancelled": 0 },
"deliveries": [
{
"delivery_id": 5001,
"channel": "wework",
"instance_id": 3,
"instance_name": "售后企微机器人",
"room_id": "10696049xxxxxxxxx",
"room_name": "艾克米物流售后群",
"company_code": "ACME01",
"company_name": "艾克米物流",
"status": "sent",
"skip_reason": null,
"scheduled_at": "2026-09-28T09:37:00.000+08:00",
"sent_at": "2026-09-28T09:37:04.000+08:00",
"attempts": 0,
"parts_total": 1,
"parts_delivered": 1,
"last_error_code": null,
"warnings": null,
"retry_of_delivery_id": null,
"source": "open_api"
},
{
"delivery_id": 5002,
"channel": "qq",
"instance_id": 12,
"instance_name": "QQ 服务机器人",
"room_id": "C9F3A2xxxxxxxxxxxxxxxxxxxxxxxxxx",
"room_name": "艾克米物流服务群",
"company_code": "ACME01",
"company_name": "艾克米物流",
"status": "skipped",
"skip_reason": "proactive_push_disabled",
"scheduled_at": null,
"sent_at": null,
"attempts": 0,
"parts_total": 1,
"parts_delivered": 0,
"last_error_code": null,
"warnings": null,
"retry_of_delivery_id": null,
"source": "open_api"
}
]
}
}
响应 data 字段
| 字段 | 说明 |
|---|---|
notification_id | 平台生成的通知 ID |
biz_msg_id | 首次提交时的业务幂等键 |
target_kind | company_code、company_name、room 或 conversation |
target_value | 定位值;按群发送时为 渠道:实例ID:群ID,按会话串发送时为原会话串 |
text | 通知正文 |
urgent | 是否紧急通知 |
accepted_at | 受理时刻 |
attachments | 通知的附件列表,每项 { seq, type, file_name, title, description, url, thumb_url, size }(不适用的字段为 null);图片与文件的 url 为平台转存后的地址,链接卡片的 url 为实际目标地址;无附件为空数组 |
cancelled_at / cancel_source / cancel_reason | 撤回时刻、来源(open_api 或 console)与原因;未撤回均为 null |
status | 整条通知的聚合状态,见下文「聚合状态与轮询」 |
summary | { total, queued, sent, failed, skipped, cancelled } |
deliveries | 全部投递单(含控制台重投产生的),按 delivery_id 升序 |
deliveries[] 每项字段
| 字段 | 说明 |
|---|---|
delivery_id | 投递单 ID |
channel / instance_id / instance_name | 渠道与发送所用的机器人实例 |
room_id / room_name | 目标群 |
company_code / company_name | 公司 |
status | pending(排队中,含发送中)、sent(已发送)、failed(失败)、skipped(已跳过)、cancelled(已撤回) |
parts_total / parts_delivered | 分段送达进度:企微每条消息(正文、每个附件)算一段,QQ 恒为 1 段;受理时 parts_delivered 为 0 |
skip_reason | status 为 skipped 时必有值:bot_not_in_room 或 proactive_push_disabled;其余为 null |
scheduled_at | 计划发送时刻(skipped 为 null) |
sent_at | 实际发送时刻,未发送为 null |
attempts | 已计次的重试次数 |
last_error_code | status 为 failed 时的失败码,见下文「失败码」;其余为 null |
warnings | 提醒数组(如某个 @ 未命中),没有为 null;有提醒不代表失败 |
retry_of_delivery_id | 由控制台重投产生时,指向被重投的那条;否则为 null |
source | 来源:open_api(开放 API 下发)、mcp(经 MCP 工具 send_notification 下发)、console_retry(控制台重投)、console_probe(控制台检测) |
群名、实例名、公司名记录的是发送当时的名称,之后改名不影响回执。pending 不区分排队原因(等时段、等间隔、当天额度已满、实例离线、发送中都是 pending),但 scheduled_at 会反映顺延后的时刻。
聚合状态与轮询
整条通知的 status 与 summary 以每个目标群的最终结果为单位统计:同一个群被控制台重投过时只看最后一次投递,console_probe 来源的投递单不参与统计。summary.total 等于目标群数(重投不增加),恒有 queued + sent + failed + skipped + cancelled = total。
| status | 条件 |
|---|---|
pending | 还有群在排队(queued > 0) |
sent | 全部群都已发送 |
partially_sent | 部分群发送成功(其余为失败、跳过或已撤回) |
failed | 没有任何群发送成功,且存在失败的群 |
cancelled | 没有任何群发送成功、没有失败的群,且存在已撤回的群(撤回前已被跳过的群不影响) |
status 不是 pending 即可停止轮询。时段外受理的通知要到下一个时段才会发出,请据 scheduled_at 安排查询时间,避免无意义的高频轮询。每条投递单自创建起最长 72 小时内一定会有结果(发出、或落 failed)。若之后运营在控制台手工重投,整条通知会回到 pending 并重新收敛。
指令头 status 按以下顺序判定:queued > 0 → pending;全部已发送 → sent;有群已发送 → partially_sent;有失败 → failed;有已撤回 → cancelled;其余 → failed。因此只有在没有任何群发送成功时,才会与 v11 的判定结果不同(撤回后为 cancelled)。
例如一条通知命中群 A、群 B,A 发送成功、B 失败:status 为 partially_sent,summary 为 { total: 2, queued: 0, sent: 1, failed: 1, skipped: 0, cancelled: 0 };运营重投 B 且成功后,deliveries 共 3 条,status 变为 sent,summary 为 { total: 2, queued: 0, sent: 2, failed: 0, skipped: 0, cancelled: 0 }。
失败码(last_error_code)
投递单为 failed 时,last_error_code 必为以下 11 个值之一:
| 失败码 | 含义 | 建议 |
|---|---|---|
bot_not_in_room | 机器人不在群内 | 把机器人重新拉进群,运营在合作管理中检测后重投或重新下发 |
proactive_push_disabled | QQ 群主未开通主动推送 | 请群主开通,检测后重投或重新下发 |
room_not_found | 发送前发现目标群记录已不存在 | 核对群清单 |
instance_deleted | 目标群所属的机器人实例已删除 | 换其他实例所在的群 |
qq_api_error | QQ 返回了业务错误 | 联系运营查看投递记录中的原因 |
wework_api_error | 企微机器人返回了业务错误 | 联系运营查看投递记录中的原因 |
send_result_unknown | 请求已发出但未得到明确结果,可能已送达 | 平台不会自动重发,以免客户收到两条;请先到群里核实,确未收到再由运营重投 |
scope_disabled | 发送前发现「推送通知」已被关闭 | 重新开启后由业务系统重新下发 |
plan_required | 发送前发现套餐已不支持推送通知 | 升级套餐后重新下发 |
retry_exhausted | 可重试的错误多次重试后仍失败 | 稍后重新下发,或联系运营 |
retry_window_expired | 超过重试时限仍未发出(如实例长时间离线) | 恢复实例后重新下发或由运营重投 |
机器人实例临时掉线、平台限流等可恢复的情况不会直接判失败,投递单保持 pending 并自动延后重试。
跳过原因(skip_reason)
| 跳过原因 | 含义 |
|---|---|
bot_not_in_room | 该群此前因机器人不在群而发送失败,平台不再往该群发,直至运营在合作管理 → 群管理对该群执行「后续检测」或「实时检测」,或该群收到新的消息 |
proactive_push_disabled | 该 QQ 群此前因群主未开通主动推送被拒,直至群主开通、运营检测后才会再发 |
skipped 是终态,平台不会自动补发。阻塞解除后,可由运营在投递记录中重投,或业务系统用新的 biz_msg_id 重新下发。
在控制台查看与重投
运营可在控制台「合作管理 → 投递记录」按公司名、群名或 biz_msg_id 查看每个群的投递结果,并对失败或已跳过的记录手工重投:
- 重投新建一条投递单(
source为console_retry,retry_of_delivery_id指向原记录),原记录保留不变,会同时出现在回执的deliveries中;同一条记录只能重投一次。 - 重投按允许推送时段排队,不继承
urgent。 - 重投后整条通知的回执
status会回到pending,直至新投递单有结果;带附件的通知重投时只补发未送达的部分。 - 运营点某行的小眼睛可打开通知预览(正文、附件、各群投递与送达进度、撤回记录),并在预览里撤回整条通知;已撤回通知的失败行显示「不可重投」,重投会返回
409notification_cancelled。 - 运营在群管理对 QQ 群做「实时检测」时发出的测试消息属于控制台检测(
console_probe),不会出现在开放 API 的回执中。
接口四:撤回通知 POST /api/v1/notifications/{biz_msg_id}/cancel
POST /api/v1/notifications/{biz_msg_id}/cancel
撤回一条通知尚未发出的部分。只取消排队中的群,已发出的群无法撤回;撤回即整条作废,不可恢复——其中失败的群也不能再由控制台重投。biz_msg_id 放进 URL 路径时请做 URL 编码;本企业下不存在时返回 404 notification_not_found。
请求参数 (JSON Body)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
reason | string | 可选 | 撤回原因,去掉首尾空白后不超过 200 个字符,空串视为未填;超长返回 400 validation_error,field 为 reason |
请求示例
curl -X POST "https://agent.likelic.com/api/v1/notifications/renew-ACME01-2026-10-24-d7/cancel" \
-H "Content-Type: application/json" \
-H "X-Customer-Code: your_customer_code" \
-H "X-API-Key: sk-your-api-key-here" \
-d '{ "reason": "客户已续约,通知作废" }'
响应示例(200)
{
"success": true,
"data": {
"biz_msg_id": "renew-ACME01-2026-10-24-d7",
"status": "partially_sent",
"cancelled_at": "2026-09-28T10:05:00.000+08:00",
"cancelled_count": 1,
"results": [
{ "delivery_id": 5001, "channel": "wework", "room_id": "10696049xxxxxxxxx", "room_name": "艾克米物流售后群", "outcome": "cancelled" },
{ "delivery_id": 5002, "channel": "qq", "room_id": "C9F3A2xxxxxxxxxxxxxxxxxxxxxxxxxx", "room_name": "艾克米物流服务群", "outcome": "sent" }
]
}
}
status是撤回后按上文规则重新聚合的整条通知状态;cancelled_count为本次实际撤回的群数。- 幂等:对已撤回的通知再次撤回返回
200,cancelled_count为 0 并带message: "无可撤回项",撤回时刻与原因保持第一次的记录。 - 部分送达的投递被撤回后保留已送达进度(
parts_delivered不变),状态为cancelled。 - 撤回后用同一个
biz_msg_id再次提交下发,只会返回原来的回执,不会重新发送;要重发请换一个新的biz_msg_id。
results[].outcome | 含义 |
|---|---|
cancelled | 本次撤回成功,该群不会再发送 |
sent | 已发出,无法撤回 |
sending | 正在发送中,结局以最终发送结果为准,无法撤回 |
already_final | 原本就是失败、已跳过或已撤回,本次不处理 |
错误码(推送通知)
| HTTP | code | 出现在 | 含义 |
|---|---|---|---|
400 | validation_error | 接口一、二、四 | 参数不合法,field 与 message 指明字段 |
400 | attachment_rejected | 接口二 | 附件被拒绝,index 指明第几个附件,reason 见「附件」一节;不占用 biz_msg_id |
400 | qq_message_too_long | 接口二 | 目标含 QQ 群且合成纯文本超过 2000 字,带 length 与 limit;不占用 biz_msg_id |
403 | plan_required | 全部 | 套餐不支持推送通知(基础版) |
403 | scope_disabled | 全部 | 未开启「推送通知」,或当前 Key 未被授权 |
404 | company_not_found | 接口二 | 按公司代码或全称找不到该合作公司 |
404 | room_not_found | 接口二 | 按群或会话串发送时,该群不存在、不属于本企业或所属实例已删除 |
404 | notification_not_found | 接口三、四 | 本企业下没有该 biz_msg_id |
409 | company_name_ambiguous | 接口二 | 存在多家同名公司,data.candidates 列出候选 |
409 | company_unmatched | 接口二 | 公司存在,但还没有绑定任何可推送的群 |
409 | all_targets_skipped | 接口二 | 目标群全部被跳过,本次不受理,data.deliveries 列出原因 |
409 | notification_in_progress | 接口二 | 同一 biz_msg_id 的另一个请求正在受理,稍后用接口三查询回执 |
413 | payload_too_large | 接口二 | 请求体超过 85MB |
429 | too_many_large_requests | 接口二 | 同一租户同时处理的大请求(超过 2MB)已达 4 个,稍后重试 |
500 | internal_error | 全部 | 服务端异常,可稍后用同一个 biz_msg_id 重试 |
以下情况发生在进入本能力之前,响应不带 code,与其他开放 API 一致:401(缺少鉴权 Header 或格式错误)、403 且无 code(Key 无效、已停用、已过期或与企业代码不匹配)、429(超过该 Key 的速率限制)、400 / 413(请求体不是合法 JSON 或超过大小限制;下发接口超过 85MB 时例外,返回带 code 的 payload_too_large)。
错误响应示例
// 按公司全称匹配到多家同名公司 → 409
{
"success": false,
"code": "company_name_ambiguous",
"message": "...",
"data": {
"candidates": [
{ "company_code": "ACME01", "company_name": "艾克米物流" },
{ "company_code": "ACME02", "company_name": "艾克米物流" }
]
}
}
错误码说明
| 状态码 | 错误信息 | 说明 |
|---|---|---|
400 | Question is required and must be a string | 请求体缺少 question 字段或类型不是字符串 |
400 | Question cannot be empty | question 为空字符串或仅包含空白字符 |
400 | Question exceeds maximum length of 800 characters | 问题内容超过 800 字符上限 |
400 | Invalid template_id format | template_id 格式不正确,应为 18-32 位字母数字组合 |
400 | Invalid session_id format | session_id 格式不正确,应为字符串且最长 36 位 |
400 | Invalid template_id | 指定的 template_id 不存在 |
400 | Template does not belong to this customer | 该模板不属于当前企业 |
401 | Missing API Key or Customer Code in headers | 请求头缺少 X-API-Key 或 X-Customer-Code |
401 | Invalid API Key format | API Key 格式不正确,应以 sk- 开头后跟 48 位十六进制字符 |
401 | Invalid Customer Code format | Customer Code 格式不正确,仅允许字母、数字、下划线和短横线(1-50位) |
403 | Invalid or disabled API Key | API Key 无效或已被禁用 |
403 | API Key has expired | API Key 已过有效期,请在控制台重新创建 |
403 | API Key does not match Customer Code | API Key 与 Customer Code 不属于同一企业 |
429 | Too many requests | 请求频率超过当前 API Key 设定的速率限制,请稍后重试 |
400 | question / answer / category / keywords … | 知识库写入接口字段校验失败(类型、长度、关键词分隔符、配图 URL 等),见 message |
403 | Knowledge base entry limit reached … | 当前方案知识库条数已满,data.remaining 为 0 |
400 | category "…" does not exist as an enabled category … | category 不在分类目录中或已停用,请使用 data.existing_categories 中的名称,或先在控制台建好该分类 |
403 | … does not support answer images … | 当前方案不支持知识库配图,请去掉 answer_image 或升级版本 |
400 | 非法的 sync_since(…) | 服务绩效议题列表的 sync_since 格式不正确 |
400 | 无效的议题 id | 详情路径参数 :id 不是正整数 |
403 | 当前套餐未开通服务绩效 | 非旗舰版或未开通服务绩效能力 |
404 | 议题不存在、未评分或已超出保留期 | 详情接口未找到可同步的议题 |
403 | 开放 API「合作客商写入」未在系统设置中启用 / Key 未被授权 | 合作客商写入未启用,或调用方 Key 不在授权列表 |
400 | 缺少 rows 数组 / 单次最多导入 5000 行 | 合作客商写入 rows 缺失、非数组或超过上限 |
400 | validation_error | 推送通知:参数不合法,field 指明出错字段 |
403 | plan_required / scope_disabled | 推送通知:套餐不支持(基础版),或未开启「推送通知」/ 当前 Key 未被授权 |
404 | company_not_found / room_not_found / notification_not_found | 推送通知:找不到合作公司 / 目标群 / 该 biz_msg_id 的通知 |
409 | company_name_ambiguous / company_unmatched / all_targets_skipped / notification_in_progress | 推送通知:同名公司多家 / 公司未绑定可推送的群 / 目标群全部被跳过(本次不受理)/ 同一 biz_msg_id 正在受理 |
400 | attachment_rejected / qq_message_too_long | 推送通知:附件被拒绝 / QQ 合成后超过 2000 字(均不占用 biz_msg_id) |
413 / 429 | payload_too_large / too_many_large_requests | 推送通知:请求体超过 85MB / 同一租户大请求并发已达 4 个 |
500 | Internal server error | 服务端内部异常,请联系管理员(推送通知接口此时带 code 为 internal_error) |
推送通知接口的失败响应另带 code 字段,请按 HTTP 状态码 + code 联合判断;各 code 出现在哪个接口、投递失败码与跳过原因见 推送通知 · 错误码。
错误响应格式
{
"success": false,
"message": "具体错误描述"
}
频率限制
为保障服务稳定性,每个 API Key 拥有独立的频率限制配置。系统在认证通过后,根据该 Key 的设定进行限流:
限流规则
| 限制维度 | 限额 | 说明 |
|---|---|---|
| 平台全局上限 | 1000 次/分钟 | 所有 API Key 不可超过此上限 |
| 单 Key 速率限制 | 按 Key 配置 | 创建 API Key 时可设置,默认 1000 次/分钟。实际生效值 = min(Key 配置值, 1000) |
| 请求体大小 | 100 KB(通用)/ 512 KB(POST /api/v1/knowledge/entries) | 单次请求 JSON Body 的最大字节数 |
| 问题长度 | 800 字符 | question 字段的最大字符数 |
限流响应头
每次 API 请求的响应中都会包含以下 Headers,方便客户端感知当前额度:
| Header | 说明 |
|---|---|
RateLimit-Limit | 当前 Key 在本窗口内允许的最大请求数 |
RateLimit-Remaining | 当前窗口内剩余可用请求数 |
RateLimit-Reset | 当前窗口重置的 Unix 时间戳(秒) |
RateLimit-Remaining 响应头,在剩余额度不足时主动降速,避免触发 429 限流。如需调整限额,可在控制台「API 密钥管理」中修改对应 Key 的速率设置。
最佳实践
安全建议
| 建议 | 说明 |
|---|---|
| 使用后端代理 | 切勿将 API Key 暴露在前端代码、移动端应用包或公开仓库中,通过后端服务转发请求 |
| 定期轮换密钥 | 建议每 90 天轮换一次 API Key,旧密钥在过渡期后及时禁用或删除 |
| 最小权限原则 | 为不同业务场景创建独立的 API Key,便于权限管控和用量追踪 |
| 设置过期时间 | 为临时集成或外部合作场景的 API Key 设置合理的过期时间 |
| 监控异常调用 | 关注控制台中的 API 调用日志,及时发现异常流量或未授权的调用行为 |
调用建议
| 建议 | 说明 |
|---|---|
| 指定模板 ID | 不同业务场景使用不同提示词模板,获取更精准的回答效果 |
| 利用多轮会话 | 首次对话保存返回的 session_id,后续追问时传入该值,同一会话的所有对话将在控制台中合并展示,便于追踪和复盘 |
| 启用流式输出 | 面向用户的实时交互场景建议使用流式模式,提升用户体验 |
| 错误重试 | 网络异常(5xx)时建议实现指数退避重试机制,最多重试 3 次。注意:400/401/403 错误无需重试 |
| 限流感知 | 读取响应头中的 RateLimit-Remaining 字段,在剩余额度不足时主动降速 |
| 超时设置 | 非流式请求建议设置 30 秒超时,流式请求建议 60 秒 |
| 输入预处理 | 发送前对用户问题进行 trim 处理,去除首尾空白字符,减少无效 Token 消耗 |
| 议题增量同步 | 以 id 幂等 upsert;增量用 sync_since(建议回拨 1 分钟重叠);轮询间隔 5–15 分钟;停服恢复后沿用旧游标即可补数据 |