知识库
产品文档与帮助中心
客服系统开放 API 对接文档
# 客服系统开放 API 对接文档
> 更新日期:2026-10-08
## 1. 接口概述
开放 API 用于在第三方系统中创建客服会话、发送访客消息、获取 AI 或人工客服回复,以及关闭会话和提交满意度评价。
基础地址:
https://<客服系统域名>/api/v1/openapi/chat
正式联调时,请将本文中的 `https://<客服系统域名>` 替换为服务方提供的实际地址。
所有请求和响应均使用 UTF-8 编码。包含请求体的接口使用:
```http
Content-Type: application/json
```
## 2. 接入流程
1. 由客服系统管理员在“商户后台 → 渠道接入 → 开放 API”中创建 API Key。
2. 妥善保存创建时显示的完整 API Key。完整密钥仅在创建时展示一次。
3. 调用“校验密钥”接口确认地址、密钥和权限正确。
4. 使用第三方系统中的用户唯一标识创建或复用会话。
5. 使用返回的 `conversationId` 发送消息并接收回复。
6. 会话结束后调用关闭会话接口;如需评价,再调用满意度接口。
## 3. 身份认证
推荐通过 `X-API-Key` 请求头传递密钥:
X-API-Key: sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
也支持 Bearer 方式:
Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
请勿同时使用两种方式。若同时提供,系统优先读取 `X-API-Key`。
### 3.1 权限范围
| Scope | 说明 | 对应接口 |
| --- | --- | --- |
| `chat:read` | 读取会话和消息 | 会话列表、会话详情、消息列表 |
| `chat:write` | 创建和变更会话 | 创建会话、发送消息、关闭会话、提交满意度 |
`GET /me` 只要求 API Key 有效,不额外要求上述 Scope。
### 3.2 安全要求
- API Key 等同于账号密码,只能保存在服务端,禁止写入网页、小程序或 App 前端代码。
- 正式环境必须使用 HTTPS。
- 不要通过 URL 查询参数传递 API Key。
- 如怀疑密钥泄露,请立即在管理后台撤销旧密钥并创建新密钥。
## 4. 通用响应格式
成功响应的业务结构如下:
```json
{
"code": 200,
"message": "success",
"data": {}
}
```
说明:`code` 是响应体中的业务状态码。HTTP 状态码仍以实际响应为准;当前 POST 接口成功时通常返回 HTTP `201 Created`,GET、DELETE 接口成功时通常返回 HTTP `200 OK`。
请求失败时采用标准错误结构,例如:
```json
{
"statusCode": 401,
"message": "Invalid API key",
"error": "Unauthorized"
}
```
参数校验失败时,`message` 可能是字符串数组:
```json
{
"statusCode": 400,
"message": [
"page must not be less than 1"
],
"error": "Bad Request"
}
```
常见 HTTP 状态码:
| 状态码 | 含义 | 建议处理方式 |
| --- | --- | --- |
| `200` / `201` | 请求成功 | 读取响应体中的 `data` |
| `400` | 参数错误、会话已关闭等 | 检查请求参数,不要原样重复请求 |
| `401` | 密钥缺失、无效、过期、已撤销或权限不足 | 检查密钥和 Scope,必要时联系管理员 |
| `403` | 商户当前不可用 | 联系服务方确认商户状态 |
| `404` | 会话不存在,或不属于当前商户 | 检查 `conversationId` |
| `500` | 服务端异常 | 记录请求时间和响应内容后联系服务方 |
## 5. 数据对象
### 5.1 会话对象
```json
{
"id": "5f570631-cb74-4b86-8a82-f1e9d73ac001",
"merchantId": "merchant-id",
"customerId": "customer-id",
"customerName": "张三",
"externalUserId": "buyer_10086",
"source": "openapi",
"status": "waiting",
"createdAt": "2026-10-08T02:30:00.000Z",
"updatedAt": "2026-10-08T02:30:00.000Z"
}
```
会话状态:
| 值 | 说明 |
| --- | --- |
| `waiting` | 等待接待 |
| `active` | 接待中 |
| `closed` | 已关闭 |
### 5.2 消息对象
```json
{
"id": "e3924087-2034-4209-9558-cb813404b001",
"conversationId": "5f570631-cb74-4b86-8a82-f1e9d73ac001",
"type": "text",
"content": "你好,我想咨询订单问题",
"senderType": "customer",
"senderName": "用户",
"timestamp": "2026-10-08T02:31:00.000Z"
}
```
常见 `senderType`:
| 值 | 说明 |
| --- | --- |
| `customer` | 访客消息 |
| `ai` | AI 回复 |
| `agent` | 人工客服回复 |
| `system` | 系统消息 |
常见 `type` 包括 `text`、`image`、`ai_reply`、`system`。调用方应兼容新增类型,不要将未知类型直接视为错误。
时间字段均为 ISO 8601 格式。示例中的 `Z` 表示 UTC 时间。
## 6. 接口清单
| 方法 | 路径 | Scope | 说明 |
| --- | --- | --- | --- |
| GET | `/me` | 无额外要求 | 校验 API Key 并读取商户信息 |
| POST | `/conversations` | `chat:write` | 创建或复用会话 |
| GET | `/conversations` | `chat:read` | 获取会话列表 |
| GET | `/conversations/{id}` | `chat:read` | 获取会话详情 |
| GET | `/conversations/{id}/messages` | `chat:read` | 获取消息列表 |
| POST | `/conversations/{id}/messages` | `chat:write` | 发送访客消息 |
| POST | `/conversations/{id}/close` | `chat:write` | 关闭会话 |
| POST | `/conversations/{id}/satisfaction` | `chat:write` | 提交满意度 |
下文中的路径均相对于基础地址。
## 7. 接口详情
### 7.1 校验密钥
```http
GET /me
```
请求示例:
```bash
curl "https://<客服系统域名>/api/v1/openapi/chat/me" \
-H "X-API-Key: sk_live_xxx"
```
成功响应:
```json
{
"code": 200,
"message": "success",
"data": {
"key": {
"id": "key-id",
"name": "客户系统对接",
"keyPrefix": "sk_live_abcd",
"scopes": ["chat:read", "chat:write"],
"status": "ACTIVE",
"expiresAt": null,
"lastUsedAt": "2026-10-08T02:20:00.000Z",
"maskedKey": "sk_live_abcd..."
},
"merchant": {
"id": "merchant-id",
"name": "示例商户",
"status": "ACTIVE"
}
}
}
```
### 7.2 创建或复用会话
```http
POST /conversations
```
请求参数:
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `externalUserId` | string | 是 | 用户在调用方系统中的唯一标识,建议长期稳定 |
| `customerName` | string | 否 | 用户展示名称;首次创建客户时保存 |
| `customerPhone` | string | 否 | 用户手机号;首次创建客户时保存 |
| `source` | string | 否 | 来源标识,默认 `openapi`;仅保留小写字母、数字、`_`、`-`,最长 20 个字符 |
请求示例:
```bash
curl -X POST "https://<客服系统域名>/api/v1/openapi/chat/conversations" \
-H "Content-Type: application/json" \
-H "X-API-Key: sk_live_xxx" \
-d '{
"externalUserId": "buyer_10086",
"customerName": "张三",
"customerPhone": "13800000000",
"source": "erp"
}'
```
成功响应:
```json
{
"code": 200,
"message": "success",
"data": {
"id": "5f570631-cb74-4b86-8a82-f1e9d73ac001",
"merchantId": "merchant-id",
"customerId": "customer-id",
"customerName": "张三",
"externalUserId": "buyer_10086",
"source": "erp",
"status": "waiting",
"createdAt": "2026-10-08T02:30:00.000Z",
"updatedAt": "2026-10-08T02:30:00.000Z"
}
}
```
同一个商户、同一个 `externalUserId` 已存在 `waiting` 或 `active` 会话时,接口会直接返回该会话,不会重复创建。只有旧会话关闭后,再次调用才会创建新会话。
新会话创建时系统会自动写入欢迎消息。可通过消息列表接口读取该消息。
### 7.3 获取会话列表
```http
GET /conversations
```
查询参数:
| 参数 | 类型 | 必填 | 默认值 | 说明 |
| --- | --- | --- | --- | --- |
| `page` | integer | 否 | `1` | 页码,从 1 开始 |
| `pageSize` | integer | 否 | `20` | 每页条数,范围 1~100 |
| `status` | string | 否 | - | `waiting`、`active` 或 `closed` |
| `externalUserId` | string | 否 | - | 按调用方用户 ID 精确筛选 |
| `source` | string | 否 | - | 按来源筛选 |
请求示例:
```bash
curl "https://<客服系统域名>/api/v1/openapi/chat/conversations?page=1&pageSize=20&status=active" \
-H "X-API-Key: sk_live_xxx"
```
成功响应:
```json
{
"code": 200,
"message": "success",
"data": {
"items": [
{
"id": "5f570631-cb74-4b86-8a82-f1e9d73ac001",
"merchantId": "merchant-id",
"customerId": "customer-id",
"customerName": "张三",
"externalUserId": "buyer_10086",
"source": "erp",
"status": "active",
"createdAt": "2026-10-08T02:30:00.000Z",
"updatedAt": "2026-10-08T02:35:00.000Z"
}
],
"total": 1,
"page": 1,
"pageSize": 20
}
}
```
列表按 `updatedAt` 倒序排列。
### 7.4 获取会话详情
```http
GET /conversations/{id}
```
路径参数 `id` 为创建会话或会话列表接口返回的会话 ID。
```bash
curl "https://<客服系统域名>/api/v1/openapi/chat/conversations/5f570631-cb74-4b86-8a82-f1e9d73ac001" \
-H "X-API-Key: sk_live_xxx"
```
成功响应中的 `data` 为会话对象。
### 7.5 获取消息列表
```http
GET /conversations/{id}/messages
```
查询参数:
| 参数 | 类型 | 必填 | 默认值 | 说明 |
| --- | --- | --- | --- | --- |
| `page` | integer | 否 | `1` | 页码,从 1 开始 |
| `pageSize` | integer | 否 | `50` | 每页条数,范围 1~100 |
| `after` | string | 否 | - | 只返回该 ISO 8601 时间之后创建的消息 |
请求示例:
```bash
curl "https://<客服系统域名>/api/v1/openapi/chat/conversations/5f570631-cb74-4b86-8a82-f1e9d73ac001/messages?page=1&pageSize=50" \
-H "X-API-Key: sk_live_xxx"
```
成功响应:
```json
{
"code": 200,
"message": "success",
"data": {
"items": [
{
"id": "message-id-1",
"conversationId": "5f570631-cb74-4b86-8a82-f1e9d73ac001",
"type": "ai_reply",
"content": "您好,请问有什么可以帮您?",
"senderType": "ai",
"senderName": "AI助手",
"timestamp": "2026-10-08T02:30:00.000Z"
}
],
"total": 1,
"page": 1,
"pageSize": 50
}
}
```
消息按 `timestamp` 正序排列。被撤回的消息不会返回。
异步轮询时,建议保存上一轮最后一条消息的 `timestamp`,下一轮将其作为 `after` 参数:
```http
GET /conversations/{id}/messages?after=2026-10-08T02%3A30%3A00.000Z
```
### 7.6 发送消息
```http
POST /conversations/{id}/messages
```
请求参数:
| 字段 | 类型 | 必填 | 默认值 | 说明 |
| --- | --- | --- | --- | --- |
| `content` | string | 是 | - | 消息内容,不能是空字符串 |
| `type` | string | 否 | `text` | 支持 `text`、`image`;图片消息的 `content` 通常传可访问的图片 URL |
| `clientMessageId` | string | 否 | - | 调用方消息唯一 ID,用于短时间内防止重复提交 |
| `waitAi` | boolean | 否 | `true` | 是否等待 AI 处理完成并在本次响应中返回 AI 回复 |
同步模式请求示例:
```bash
curl -X POST "https://<客服系统域名>/api/v1/openapi/chat/conversations/5f570631-cb74-4b86-8a82-f1e9d73ac001/messages" \
-H "Content-Type: application/json" \
-H "X-API-Key: sk_live_xxx" \
-d '{
"content": "你好,我想查询订单进度",
"type": "text",
"clientMessageId": "msg_20261008_0001",
"waitAi": true
}'
```
同步模式成功响应:
```json
{
"code": 200,
"message": "success",
"data": {
"customerMessage": {
"id": "customer-message-id",
"conversationId": "5f570631-cb74-4b86-8a82-f1e9d73ac001",
"type": "text",
"content": "你好,我想查询订单进度",
"senderType": "customer",
"senderName": "用户",
"timestamp": "2026-10-08T02:31:00.000Z"
},
"aiMessages": [
{
"id": "ai-message-id",
"conversationId": "5f570631-cb74-4b86-8a82-f1e9d73ac001",
"type": "ai_reply",
"content": "请提供您的订单号,我来帮您查询。",
"senderType": "ai",
"senderName": "AI助手",
"timestamp": "2026-10-08T02:31:02.000Z"
}
],
"aiPending": false
}
}
```
异步模式将 `waitAi` 设置为 `false`。接口保存访客消息后立即返回:
```json
{
"code": 200,
"message": "success",
"data": {
"customerMessage": {
"id": "customer-message-id",
"conversationId": "5f570631-cb74-4b86-8a82-f1e9d73ac001",
"type": "text",
"content": "你好,我想查询订单进度",
"senderType": "customer",
"senderName": "用户",
"timestamp": "2026-10-08T02:31:00.000Z"
},
"aiMessages": [],
"aiPending": true
}
}
```
收到异步响应后,请调用消息列表接口获取后续 AI 或人工客服回复。
注意事项:
- 建议每条上行消息都传递全局唯一的 `clientMessageId`。
- 当前去重窗口为 30 秒:同一会话内,相同 `clientMessageId` 在 30 秒内重复提交时会返回原访客消息,不会再次触发 AI。
- `aiMessages` 可能为空,例如会话已由人工接管、AI 功能未启用或本次没有生成可发送的回复。调用方不应假设每条访客消息一定对应一条 AI 消息。
- 已关闭的会话不能继续发送消息。需要继续咨询时,应重新调用创建会话接口获取新会话 ID。
### 7.7 关闭会话
```http
POST /conversations/{id}/close
```
请求参数:
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `reason` | string | 否 | 关闭原因;未传时使用系统默认结束语 |
请求示例:
```bash
curl -X POST "https://<客服系统域名>/api/v1/openapi/chat/conversations/5f570631-cb74-4b86-8a82-f1e9d73ac001/close" \
-H "Content-Type: application/json" \
-H "X-API-Key: sk_live_xxx" \
-d '{
"reason": "用户已确认问题解决"
}'
```
成功响应中的 `data` 为会话对象,`status` 为 `closed`。系统同时写入一条结束系统消息。
### 7.8 提交满意度
```http
POST /conversations/{id}/satisfaction
```
请求参数:
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `score` | integer | 是 | 评分,范围 1~5 |
| `comment` | string | 否 | 评价内容 |
请求示例:
```bash
curl -X POST "https://<客服系统域名>/api/v1/openapi/chat/conversations/5f570631-cb74-4b86-8a82-f1e9d73ac001/satisfaction" \
-H "Content-Type: application/json" \
-H "X-API-Key: sk_live_xxx" \
-d '{
"score": 5,
"comment": "回复及时,问题已解决"
}'
```
成功响应:
```json
{
"code": 200,
"message": "success",
"data": {
"conversationId": "5f570631-cb74-4b86-8a82-f1e9d73ac001",
"score": 5,
"comment": "回复及时,问题已解决"
}
}
```
同一会话重复提交评价时,会更新原评价。
## 8. 推荐对接方式
### 8.1 同步方式
适合服务端能够等待 AI 回复的场景:
```text
创建/复用会话 → 发送消息(waitAi=true) → 直接读取 aiMessages
```
优点是实现简单。AI 生成需要一定时间,调用方应为该请求设置合理的超时时间。
### 8.2 异步轮询方式
适合前端聊天、消息队列或不希望长时间占用 HTTP 连接的场景:
```text
创建/复用会话
↓
发送消息(waitAi=false)
↓
保存 customerMessage.timestamp
↓
定时调用消息列表(after=<timestamp>)
↓
取得 AI 或人工客服回复
```
建议轮询间隔从 1~2 秒开始,并设置最大等待时间。达到最大等待时间后可在后台继续轮询,或提示用户“客服正在处理中”。
## 9. JavaScript 调用示例
以下代码应运行在调用方服务端,不要放在浏览器中:
```js
const baseUrl = 'https://<客服系统域名>/api/v1/openapi/chat';
const apiKey = process.env.CUSTOMER_SERVICE_API_KEY;
async function request(path, options = {}) {
const response = await fetch(`${baseUrl}${path}`, {
...options,
headers: {
'Content-Type': 'application/json',
'X-API-Key': apiKey,
...options.headers,
},
});
const result = await response.json();
if (!response.ok) {
throw new Error(`客服 API 调用失败:${response.status} ${JSON.stringify(result)}`);
}
return result.data;
}
async function chat(externalUserId, content) {
const conversation = await request('/conversations', {
method: 'POST',
body: JSON.stringify({ externalUserId, source: 'customer_system' }),
});
return request(`/conversations/${conversation.id}/messages`, {
method: 'POST',
body: JSON.stringify({
content,
type: 'text',
clientMessageId: crypto.randomUUID(),
waitAi: true,
}),
});
}
```
## 10. 联调检查清单
- 已获取正式环境基础地址和 API Key。
- `GET /me` 调用成功,返回的商户信息正确。
- API Key 同时具有实际需要的 `chat:read`、`chat:write` 权限。
- `externalUserId` 使用调用方稳定且唯一的用户 ID,而不是昵称。
- 保存了创建接口返回的 `conversationId`。
- 每条上行消息都生成不同的 `clientMessageId`。
- 已正确处理 HTTP 非 2xx 响应和网络超时。
- 已兼容 `aiMessages` 为空或包含多条消息的情况。
- 异步方式已实现增量轮询和最大等待时间。
- API Key 仅保存在服务端,日志中已对其脱敏。
## 11. 联调问题反馈信息
出现问题时,请提供以下信息,便于服务方排查:
- 请求时间(注明时区)。
- 请求方法和 URL;API Key 必须脱敏。
- 请求参数;涉及手机号等隐私信息时请脱敏。
- HTTP 状态码和完整响应体。
- `conversationId`、`clientMessageId`。
- 问题能否稳定复现以及复现步骤。