-
Notifications
You must be signed in to change notification settings - Fork 64
客服系统 API 文档(draft)
所有 API 以 /api/{version}
开头,目前的 version 为 2,使用的 Base URL 是在 LeanCloud 控制台绑定的云引擎域名。
API 详细参数与返回值请参考对应部署的 /docs/{version}
页面。本文重点在描述 API 的用法。
除了公开的资源(分类、知识库),所有接口都需要登录,通过 X-LC-Session
Header 鉴权。登录方式(session 的获取)参见下文用户部分。
目前仅「自定义表单」功能支持多语言。计划将来分类、知识库等所有可配置的内容都支持多语言。
在客户端视角,在请求的 Accept-Language
header 中指定语言的优先级即可。目前支持的语言有 zh-CN
, zh-TW
, zh-HK
, en
, ja
, ko
, id
, th
, de
, fr
, ru
, es
, pt
, tr
。
使用 JWT HMAC RS256 算法与给定的私钥对用户登录信息进行签名。登录信息 payload 包含两个内置字段 sub 与 name。其中 sub 为用户唯一标识为必选(用户 ID),如果同一个厂商在不同产品中使用同一个 ID 即可打通用户。name 仅用于展示为可选,每次有效登录时,name 会覆盖当前值。
Request body:
{
"jwt": "JWT token"
}
其中 JWT token 的 payload 形如:
{
"sub": "1234567890",
"name": "John Doe"
}
返回的 session
既在鉴权部分提到的 X-LC-Session
header 值:
{
"sessionToken": "random session token"
}
为了防止重放攻击,服务端在签发 JWT token 时应带上 jti
、exp
等保留字段。
随机生成一个 UUID 并构造以下结构的 authData
即可实现游客登录,该方式适用于用户还没有 / 无法登录您应用的情况下提交与追踪工单的进展:
{
"anonymousId": "random UUID"
}
Response:
{
"sessionToken": "random session token"
}
客户端应在本地持久化该匿名 ID,如果该 ID 丢失,用户将无法追踪之前提交的工单。
分类(Category)是工单系统的核心,是用户接触到的第一个概念,其他所有的概念都是围绕分类组织的。
分类是一个树形结构,可以在后台分类设置中直观的看到一颗或多颗分类树。树的根节点是一种特殊的分类,称为产品(Product)。不同的产品之间从用户视角看是独立的,一个用户(哪怕在产品之间通过 ID 对应为一个用户)在某个产品的用户端只会看到某个产品下的分类,查到某个产品下的工单列表,收到某个产品下的未读提醒。同时从客服的视角不同的产品之间是互通的,不同产品的分类可以共享客服、知识库、自动化流程等各种资源。
「产品」是一个很具体的名词,但其实这是一个虚拟的概念,用「产品」这个名字命名仅仅是为了方便理解。实际上除了真正的产品,其他维度,只要它们需要在客户端有不同的分类方式,都可以抽象为「产品」来区分。比如不同的平台可以是不同的「产品」,不同的地区也可以是不同的「产品」。
我们可以通过 GET /api/2/products/{pid}/categories
获取某个产品下的分类列表。分类的 schema 请参照 API 文档。需要指出的是,这个 API 返回的是一个拍平的数组,需要通过分类的 parentId
与 position
来构造树。
因为需要构建树,这个 API 不支持分页。在不加参数的情况下默认会返回所有的分类,包括已禁用的,如果只需要启用状态的分类可以加上 active=true
参数。但是考虑到用户的历史工单中可能存在已被禁用的分类,建议用户端获取所有的分类作为全局状态存储,在展示分类列表时再过滤掉禁用的分类。
工单的 schema 请参见 API 文档。其中最重要的属性是工单状态。工单状态有以下可选值。
ENUM | 值 | 描述 |
---|---|---|
NEW |
50 | 新工单,还没有客服回复 |
WAITING_CUSTOMER_SERVICE |
120 | 等待客服回复 |
WAITING_CUSTOMER |
160 | 等待用户回复 |
TO_BE_CONFIRMED |
220 | 待用户确认解决(客服点击「认为已解决」时会设置该状态) |
FULFILLED |
250 | 已解决 |
CLOSED |
280 | 已关闭 |
工单的完整状态机描述如下。其中「用户确认解决」(TO_BE_CONFIRMED / FULFILLED 两个状态)是可选的,我们推荐让用户来确认问题解决并关闭工单,但如果确实不需要该功能可以无视这两个状态,简化为只用 CLOSED 状态。
虽然状态众多,但在用户端从用户的视角这些状态可以分为三类:
-
[0, 150)
: 等待客服跟进,无需关注 -
[150, 240)
: 需要用户关注,提供更多信息或确认解决 -
>=240
: 流程结束,无需关注
建议给不同类型的状态使用不同的视觉设计以区分。
创建工单的 API POST /api/2/tickets
请参见 API 文档。
创建工单时支持不同的分类展示不同的表单。我们可以通过 GET api/2/categories/{id}/fields
获取到需要后台配置的自定义表单字段。
字段的数据结构参见 API 文档中的 TicketField
schema。
表单字段有以下 6 种类型:
Type | 描述 |
---|---|
text |
单行文本 |
multi-line |
多行文本 |
dropdown |
下拉选择 |
multi-select |
多选 Radio |
radios |
单选 Radia |
file |
文件上传 |
不支持类型扩展,如果想要支持特殊类型控件,可以在在字段名称中约定特殊标记,客户端根据此标记渲染特殊控件。
除了需要用户提交的字段,有时候我们会想要上报一些用户不可见的数据,比如设备相关的信息。可以在后台创建「客户不可见」的自定义字段,然后在创建工单时自动填充带上。
一个工单的详情页面的内容主要由以下几部分信息组成。
其中基本必须要展示的有:
- 工单基本信息
GET /api/2/tickets/{id}
,包括了 ID、标题、详细描述、状态、分类、评价等 - 回复
可选展示的信息有:
- 操作记录
- 用户提交的字段
GET /api/1/ticket-fields?ids={ids}&includeVariant=true&locale={locale}
(这个 API 待迁移到 v2)
以下待更新
GET /api/2/tickets
支持通过页码分页:通过 page
(默认值: 1) 和 page_size
(默认值: 10) 控制页数和每页的数量。
也支持通过工单的创建时间作为条件向后翻页(即加载更多模式)。
通过 q.created_at
分页, 一次最多返回 500 条数据
获取创建时间晚于 2021-05-06T05:00:00.000Z
的操作日志:
GET /api/1/tickets/{id}/ops-log?q=created_id:>2021-05-06T05:00:00.000Z
值 | 描述 |
---|---|
selectAssignee |
系统分配负责人 |
changeCategory |
修改分类 |
changeAssignee |
修改负责人 |
replyWithNoContent |
客服认为当前工单无需回复 |
replySoon |
客服认为处理工单需要时间, 稍后再回复 |
resolve |
用户或客服认为工单已解决 |
close |
用户或客服关闭了工单 |
reject |
已弃用, 用户或客服关闭了工单 |
[
{
"id": "日志ID",
"action": "selectAssignee",
"operator_id": "xxx",
"assignee_id": "xxx",
"category_id": "xxx",
"created_at": "2021-05-06T05:35:54.441Z"
}
]
字段 | 类型 | 描述 |
---|---|---|
assignee_id |
string | 更新工单负责人, 仅客服可用 |
category_id |
string | 更新工单分类, 仅客服可用 |
organization_id |
string | 更新工单所属组织, 设置为空字符串来取消关联。仅客服可用 |
tags |
{ key: string; value: string } | 仅客服可用 |
private_tags |
{ key: string; value: string } | 仅客服可用 |
evaluation |
{ star: 0 | 1; content: string, selections: string[] } | selections 是评价的选项,仅工单作者可用 |
subscribed |
boolean | 仅客服可用 |
unread_count |
0 | 将未读操作数量置空 |
{}
值 | 描述 |
---|---|
replyWithNoContent |
无需回复 |
replySoon |
稍后回复 |
resolve |
设置为已解决 |
close |
关闭工单 |
reopen |
重新打开工单 |
{
"action": "replyWithNoContent"
}
{}
工单更新通知追踪用户创建或关注的工单是否有更新,因此以下所有 API 都需要登录状态。
返回 boolean 类型的 true / false,主要用于显示小红点。
{
unread: 1 | undefined; // 是否只返回未读的通知
before: string; // ISO 时间戳,配合返回值中的 latestActionAt 翻页
limit: number; // 每页条数,默认 25
includeTicketMetaKeys: string[]; // 需要在返回值中携带的工单 metaData 字段
}
{
id: string; // 通知 id
ticket: Ticket;
unreadCount: number;
latestAction: "reply" |
"changeStatus" |
"changeAssignee" |
"ticketEvaluation" |
"newTicket"; // 最近一次更新操作的类型,对于用户侧只需要关心前两个
latestActionAt: string; // 最后一次更新的时间,配合 before 参数可实现翻页
}
在用户点击进入工单详情页后,请求工单详情 API 会自动将该工单通知的已读状态改为已读,也可以通过下面这个 API 批量将所有未读通知标为已读:
POST /api/2/notifications/read-all
{
objectId: string,
ticket: Pointer<Ticket>, // 所回复的工单
content: string,
content_HTML: string
author: Pointer<User>, // 提交该回复的用户
isCustomerService: boolean, // 提交该回复的用户是否为客服
createdAt: string, // UTC timestamp
updatedAt: string, // UTC timestamp
}
{
"content": "回复内容",
"file_ids": ["回复附件 ID"]
}
{
"id": "回复 ID",
"created_at": "2021-05-06T05:38:26.126Z"
}
通过 q.created_at
分页, 一次最多返回 500 条数据
获取创建时间晚于 2021-05-06T05:00:00.000Z
的回复:
GET /api/1/tickets/{id}/replies?q=created_at:>2021-05-06T05:00:00.000Z
[
{
"id": "回复 ID",
"nid": "回复 Number ID",
"author_id": "回复作者 ID",
"author": {
// 回复作者的详细信息
},
"content": "回复内容",
"content_HTML": "回复内容 (HTML 格式)",
"file_ids": ["回复附件 ID"],
"files": [
// 回复附件
],
"is_customer_service": true, // 该回复作者是否是由客服
"created_at": "2021-05-06T05:36:22.415Z"
}
]
这部分已经重新设计,请参考: https://demo.leanticket.cn/docs/2/#/Knowladge%20base
文件需要通过对应平台的存储 SDK 上传(推荐直接使用客户端 SDK,也提供服务端 SDK 上传)。SDK 的安装与用法参见 LeanCloud 文档: