微信小店客诉工单 platformkf 接入:超时未处理=默认判支持用户,reply_option 必填项要动态取
主文档:
纠纷单同步工单接口:
先分清三套东西:platformkf、commkf、纠纷单同步工单
这三者常在接入时被混在一起,边界如下:
- 客诉工单 platformkf:处理平台发起的合规工单,典型场景是订单发货超时、用户催发货后平台自动建单。接口路径统一在
/channels/ec/platformkf/*下,商家需在截止时间前提交处理方案,否则平台按规则自动判定。 - 商家客服 commkf:处理用户即时消息沟通,与 platformkf 的接口路径、功能、数据互不交叉。两者不是同一套消息体系,不要试图用 commkf 的会话数据去关联客诉工单。
- 纠纷单同步工单 mmecapi_syncworkorder:属于售后管理下的纠纷单模块,接口为
POST https://api.weixin.qq.com/channels/ec/aftersale/syncworkorder?access_token=ACCESS_TOKEN,做的是工单同步,且为全量覆盖式,不是增量同步。它和 platformkf 的工单列表、工单详情不是同一批数据。
接入前需要:
- 商家自研直接用 access_token;第三方服务商需拿到商家对权限集 ID:131 的授权,使用 authorizer_access_token。
- 配置消息推送回调 URL,本模块涉及两个事件:
ec_platform_kf_create_mch_ticket、ec_platform_kf_ticket_timeout。
工单类型:目前只有 9「催发货」
类型值 9,名称「催发货」,触发条件是订单发货超时且用户催发货。平台后续可能扩展更多类型,所以不要把类型集合写死在代码里,用 GetTicketClassConfig 动态拉取。
生命周期与状态值
[事件] 工单创建 ec_platform_kf_create_mch_ticket
↓
ticket_state=1 待商家处理
├─ 商家提交处理方案 → ticket_state=2 待平台处理 → 平台审核 → ticket_state=3 已完结
└─ 超时未处理 → [事件] 工单超时 ec_platform_kf_ticket_timeout → ticket_state=3 已完结
ticket_state 取值:
| 值 | 含义 |
|---|---|
| 1 | 待商家处理,工单已创建,等待商家在截止时间内处理 |
| 2 | 待平台处理,商家已提交处理方案,等待平台审核 |
| 3 | 已完结,平台审核完成或超时自动判定 |
platform_review_result 取值:
| 值 | 含义 |
|---|---|
| 1 | 审核通过,协商一致支持用户 |
| 2 | 审核不通过,默认判支持用户 |
| 3 | 平台介入处理,判支持商家 |
| 4 | 平台介入处理,判支持用户 |
| 5 | 平台关闭工单 |
三阶段接入
阶段一:取配置并缓存
调 GetTicketClassConfig 拿当前支持的工单类型和对应的回复选项。返回的选项包含 option_id、option_name,以及各字段是否必填的标识。
# 商家自研;第三方把 access_token 换成 authorizer_access_token
curl -s "https://api.weixin.qq.com/channels/ec/platformkf/getticketclassconfig?access_token=ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{}'
为什么必须缓存,而不是把选项硬编码:
- 平台会扩展工单类型,选项的
option_id与必填标识也会随配置变化。硬编码一份option_id → 必填字段的映射,平台一侧调整后,代码仍然按旧规则传参,处理请求会直接失败。 - 工单有
ticket_deal_end_time,处理窗口本来就短。每次处理前实时拉一次配置,等于在关键路径上多加一次外部调用和一次失败可能。定期拉取并缓存,处理时只读缓存。
缓存里保存的是「选项 ID → 是否需要 description、是否需要 confer_time」这层关系,业务代码只查表,不写死。
阶段二:收通知,再查详情
平台创建工单时,通过 ec_platform_kf_create_mch_ticket 推送到已配置的回调地址,通知里带 ticket_id。拿到 ticket_id 后调 GetMchTicketDetail 取完整信息,包括关联订单、用户描述、ticket_deal_end_time 等。
需要批量对账时用 GetMchTicketList,支持按状态、分类、时间范围筛选。
收到通知就应该把 ticket_deal_end_time 落库并设置告警,不要等到定时任务再扫。
阶段三:提交处理方案
OperateMchTicket 的入参:
ticket_idreply_option:回复选项 ID,来自GetTicketClassConfigdescription:补充说明,部分选项必填confer_time:协商时间,部分选项必填
以「催发货」为例:
| option_id | 选项 | 必填 |
|---|---|---|
| 1 | 3 天内能发货 | 补充说明、协商时间都不需要 |
| 2 | 和用户协商更晚发货(4–15 天) | confer_time 必填 |
| 3 | 无法发货 | description 必填 |
curl -s "https://api.weixin.qq.com/channels/ec/platformkf/operatemchticket?access_token=ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"ticket_id": "TICKET_ID",
"reply_option": 2,
"confer_time": "CONFER_TIME",
"description": ""
}'
confer_time 的取值格式按接口文档填写,上面只是字段位置示意。
必填判断的伪代码(必填标识的字段名以 GetTicketClassConfig 实际返回为准,这里的 required 只是示意结构):
// 缓存命中优先;未命中再拉一次并写缓存
$config = $cache->get('platformkf_ticket_class_config');
if (!$config) {
$config = callApi('/channels/ec/platformkf/getticketclassconfig', []);
$cache->set('platformkf_ticket_class_config', $config, 3600);
}
// 按工单类型定位选项集合,不要假设只有类型 9
$class = findClassById($config, $ticket['class_id']);
$option = findOptionById($class['options'], $payload['reply_option']);
if (!$option) {
throw new InvalidArgumentException('reply_option 不在当前配置的选项中');
}
if ($option['required']['description'] && empty($payload['description'])) {
throw new InvalidArgumentException('description 必填');
}
if ($option['required']['confer_time'] && empty($payload['confer_time'])) {
throw new InvalidArgumentException('confer_time 必填');
}
callApi('/channels/ec/platformkf/operatemchticket', [
'ticket_id' => $ticket['ticket_id'],
'reply_option'=> $payload['reply_option'],
'description' => $payload['description'] ?? '',
'confer_time' => $payload['confer_time'] ?? '',
]);
API 接口
| 接口 | 路径 |
|---|---|
| 查询工单分类配置 GetTicketClassConfig | POST /channels/ec/platformkf/getticketclassconfig |
| 获取商家工单列表 GetMchTicketList | POST /channels/ec/platformkf/getmchticketlist |
| 查询工单详情 GetMchTicketDetail | POST /channels/ec/platformkf/getmchticketdetail |
| 商户处理商家工单 OperateMchTicket | POST /channels/ec/platformkf/operatemchticket |
事件通知
| 事件 | 事件名 | 触发时机 |
|---|---|---|
| 工单创建通知 | ec_platform_kf_create_mch_ticket | 平台为商家创建工单时推送 |
| 工单超时通知 | ec_platform_kf_ticket_timeout | 商家工单处理超时时推送 |
本模块支持商家自研调用和第三方服务商代调用,权限集 ID:131。
超时未处理的实际后果
必须在 ticket_deal_end_time 前完成处理。超时后平台会做三件事:
- 推送工单超时通知
ec_platform_kf_ticket_timeout; - 按规则自动判定支持用户,对应
platform_review_result=2(审核不通过,默认判支持用户); - 对商家触发「缺货」违规处罚,影响店铺信用分。
也就是说,超时不是「工单挂着没人管」,而是直接落一个对商家不利的终态结果,并带处罚。接入时把 ticket_deal_end_time 作为告警项处理,比事后补偿更省事。
附:纠纷单同步工单接口要点
路径 POST https://api.weixin.qq.com/channels/ec/aftersale/syncworkorder?access_token=ACCESS_TOKEN,服务器端调用,不支持云调用,支持第三方平台代微信小店商家调用,权限集 id 131。同步为全量覆盖式,不是增量。
请求体:
complaint_id:纠纷单号,必填work_order_info:必填version:递增版本号,每次全量同步递增,必填items:工单列表,全量替换,必填work_order_id:工单 ID,必填status:1-创建工单,2-处理工单,3-工单完结desc:描述update_time:更新时间result_type:0-无结果(非终态),1-同意退款,2-拒绝退款,仅终态有效refund_amount:退款金额,终态且同意退款时有效,单位分media_list:图片/视频素材列表
因为 items 是全量替换,每次同步都要把该纠纷单下当前所有工单一起带上,version 递增,漏传就等于删掉。