退款扩展点
当用户从交易的模板组件发起退款后,抖音开平交易系统会给向开发者的服务发起请求,用于通知开发者用户发起退款,开发者响应时需要返回必填的信息。详见交易系统接入流程。
接口说明
- 退款单的创建是在退款申请回调之前,退款申请回调请求开发者服务失败,也不会在 C 端展示错误,退款申请回调请求失败后会进行重试。
- 请务必确保退款申请回调请求能按照正确的格式和参数要求返回。
- 请求返回的外部退款单号也务必确保在同一小程序内不会重复,否则也会被认为请求失败。
- 开发者返回的 err_no 不为 0 也会认为请求失败,会进行重试,请确保请求成功,有拒绝退款的场景请在退款审核阶段拒绝退款。
- 如果一直请求开发者服务失败,退款单将无法被推进到退款审核阶段,请务必确保响应无问题。
- 回调重试频率:间隔2-5s,重试10次。10次后,重试间隔变为1h/次。系统会一直重试直到请求成功。
- 退款申请回调务必做好幂等处理,相同的系统退款单号重复请求应当被视为相同的一次退款。
- 退款结果通知地址优先级:发起退款/退款申请回调指定的notify_url > 解决方案配置-消息通知中指定的回调地址
基本信息
基本信息 | |
---|---|
HTTP URL | 参考解决方案使用指南中设置实现扩展点。 |
HTTP Method | POST |
权限要求 | 无 |
msg 说明 (msg 是 json 格式字符串)
名称 | 类型 | 是否必填 | 描述 | 示例 |
---|---|---|---|---|
app_id | string | 是 | 小程序的 appid | ttqweqw12312 |
open_id | string | 是 | 用户 openid | 123123 |
refund_id | string | 是 | 抖音开平侧退款单号 | ot1231313 |
order_id | string | 是 | 抖音开平侧订单号 | ot1231312 |
out_order_no | string | 是 | 开发者侧订单号 | 213123 |
refund_total_amount | int64 | 是 | 退款总金额,单位分 | 100 |
need_refund_audit | int8 | 是 | 是否需要退款审核: 1:需要退款审核 2:不需要退款审核 不需要退款审核,则无需再调用退款审核结果同步接口 | 1 |
refund_audit_deadline | int64 | 否 | 退款审核的最后期限,超过该期限无需商家审核,自动退款,13 位时间戳,单位毫秒 通常是3天(从退款发起时间开始算) | 151231321231 |
create_refund_time | int64 | 是 | 退款创建时间,13 位时间戳,单位毫秒 | 151231321230 |
refund_source | int8 | 是 | 退款来源: 1:用户发起退款 3:过期自动退 4: 抖音客服退款 5:预约失败自动退款 | 1 |
cp_extra | string | 否 | cp 自定义字段,不支持二进制,长度 <= 2048byte | cp_extra |
refund_reason | Array | 否 | 退款原因,退款原因有多个 | ["不喜欢"] |
refund_description | string | 否 | 退款补充说明 | 想退款 |
refund_item_detail | object | 否 | 退款商品单信息 |
refund_item_detail 说明
名称 | 类型 | 是否必填 | 描述 | 示例值 |
---|---|---|---|---|
item_order_quantity | int64 | 是 | 用户需要退款多少个商品单 | 1 |
item_order_detail | Array | 是 | 本次退款的商品单列表 |
item_order_detail 说明
名称 | 类型 | 是否必填 | 描述 | 示例值 |
---|---|---|---|---|
item_order_id | string | 是 | 抖音开平侧商品单号,商品单号在预下单接口同步给了开发者 | ot123134 |
refund_amount | int | 是 | 该商品单退款金额 | 100 |
交易系统退款单 msg 示例
{
"app_id": "ttqweqw12312",
"open_id": "123123",
"refund_id": "ot123133",
"order_id": "ot1231312",
"out_order_no": "213123",
"refund_total_amount": 100,
"need_refund_audit": 1,
"refund_audit_deadline": 151231321231,
"create_refund_time": 151231321230,
"refund_source": 1,
"refund_reason": ["不喜欢"],
"refund_description": "想退款",
"cp_extra": "cp_extra",
"refund_item_detail": {
"item_order_quantity": 1,
"item_order_detail": [
{
"item_order_id": "ot123134",
"refund_amount": 100
}
]
}
}
Q&A
当用户从交易的模板组件发起退款后,抖音开平交易系统会给向开发者的服务发起请求,用于通知开发者用户发起退款,开发者响应时需要返回必填的信息。详见交易系统接入流程。
使用限制
无
接口说明
-
退款单的创建是在退款申请回调之前,退款申请回调请求开发者服务失败,也不会在 C 端展示错误,退款申请回调请求失败后会进行重试。
-
请务必确保退款申请回调请求能按照正确的格式和参数要求返回。
-
请求返回的外部退款单号也务必确保在同一小程序内不会重复,否则也会被认为请求失败。
-
开发者返回的 err_no 不为 0 也会认为请求失败,会进行重试,请确保请求成功,有拒绝退款的场景请在退款审核阶段拒绝退款。
-
如果一直请求开发者服务失败,退款单将无法被推进到退款审核阶段,请务必确保响应无问题。
-
回调重试频率:间隔2-5s,重试10次。10次后,重试间隔变为1h/次。系统会一直重试直到请求成功。
-
退款申请回调务必做好幂等处理,相同的系统退款单号重复请求应当被视为相同的一次退款。
-
退款结果通知地址优先级:发起退款/退款申请回调指定的notify_url > 解决方案配置-消息通知中指定的回调地址
基本信息
基本信息HTTP URL参考解决方案使用指南中设置实现扩展点。HTTP MethodPOST权限要求无
请求头
参考
通用参数-平台请求公共参数。
请求参数
名称类型是否必填描述示例msgstring是退款单相关信息的 json 字符串ot1231231typestring是固定值:pre_create_refund 退款申请回调pre_create_refundversionstring是固定值:"2.0"。回调版本,用于开发者识别回调参数的变更2.0
msg 说明 (msg 是 json 格式字符串)
名称类型是否必填描述示例app_idstring是小程序的 appidttqweqw12312open_idstring是用户 openid123123refund_idstring是抖音开平侧退款单号ot1231313order_idstring是抖音开平侧订单号ot1231312out_order_nostring是开发者侧订单号213123refund_total_amountint64是退款总金额,单位分100need_refund_auditint8是是否需要退款审核:1:需要退款审核2:不需要退款审核不需要退款审核,则无需再调用退款审核结果同步接口1refund_audit_deadlineint64否退款审核的最后期限,超过该期限无需商家审核,自动退款,13 位时间戳,单位毫秒通常是3天(从退款发起时间开始算)151231321231create_refund_timeint64是退款创建时间,13 位时间戳,单位毫秒151231321230refund_sourceint8是退款来源:1:用户发起退款3:过期自动退4: 抖音客服退款5:预约失败自动退款1cp_extrastring否cp 自定义字段,不支持二进制,长度 <= 2048bytecp_extrarefund_reasonArray否退款原因,退款原因有多个["不喜欢"]refund_descriptionstring否退款补充说明想退款refund_item_detailobject否退款商品单信息
refund_item_detail 说明
名称类型是否必填描述示例值item_order_quantityint64是用户需要退款多少个商品单1item_order_detailArray是本次退款的商品单列表
item_order_detail 说明
名称类型是否必填描述示例值item_order_idstring是抖音开平侧商品单号,商品单号在预下单接口同步给了开发者ot123134refund_amountint是该商品单退款金额100
请求示例
curl --location --request POST 'https://xxxxxxx.net/api/v2/create_refund' --header 'Content-Type: application/json' --data-raw='{ "version": "2.0", "msg": "{"app_id":"ttqweqw12312","open_id":"123123","refund_id":"ot123133","order_id":"ot1231312","out_order_no":"213123","refund_total_amount":100,"need_refund_audit":1,"refund_audit_deadline":151231321231,"create_refund_time":151231321230,"refund_source":1,"refund_reason":["不喜欢"],"refund_description":"想退款","cp_extra":"cp_extra","refund_item_detail":{"item_order_quantity":1,"item_order_detail":[{"item_order_id":"ot123134","refund_amount":100}]}}", "type": "pre_create_refund" }'
交易系统退款单 msg 示例
{ "app_id": "ttqweqw12312", "open_id": "123123", "refund_id": "ot123133", "order_id": "ot1231312", "out_order_no": "213123", "refund_total_amount": 100, "need_refund_audit": 1, "refund_audit_deadline": 151231321231, "create_refund_time": 151231321230, "refund_source": 1, "refund_reason": ["不喜欢"], "refund_description": "想退款", "cp_extra": "cp_extra", "refund_item_detail": { "item_order_quantity": 1, "item_order_detail": [ { "item_order_id": "ot123134", "refund_amount": 100 } ] }}
响应参数
名称类型是否必填描述示例err_noint64是状态码 0 表示业务处理成功,具体错误码参见后文错误码章节0err_tipsstring是错误提示信息successdataobject是返回数据信息success
data 信息
名称类型是否必填描述示例out_refund_nostring是开发者侧退款单号,长度 <= 64 byte123213order_entry_schemaobject是退款单详情页跳转地址notify_urlstring否退款结果通知地址,必须是 https 类型。若不填,默认使用行业模板配置-消息通知中的退款回调地址。长度 <= 512 bytehttps://xxx
order_entry_schema 说明
名称类型是否必填描述示例值pathstring是订单详情页路径,没有前导的/,该字段不能为空,长度 <= 512bytepages/xxxindexxxxparamsstring否路径参数,自定义的 json 结构,序列化成字符串存入该字段,平台不限制,但是写入的内容需要能够保证生成访问订单详情的 schema 能正确跳转到小程序内部的订单详情页,长度 <= 512byte{"id":"xxxxxx"}
响应示例
order_entry_schema 说明
名称 | 类型 | 是否必填 | 描述 | 示例值 |
---|---|---|---|---|
path | string | 是 | 订单详情页路径,没有前导的/,该字段不能为空,长度 <= 512byte | pages/xxxindexxxx |
params | string | 否 | 路径参数,自定义的 json 结构,序列化成字符串存入该字段,平台不限制,但是写入的内容需要能够保证生成访问订单详情的 schema 能正确跳转到小程序内部的订单详情页,长度 <= 512byte | {"id":"xxxxxx"} |
Q&A
1.哪些情况下交易系统会回调开发者
**A: **用户发起、系统自动发起(如过期自动退)、客服发起的退款都会回调开发者。即,所有非开发者通过服务端 openAPI 发起的退款,在成功创建退款单后系统都会回调开发者。
2.开发者已经响应了退款申请回调,为什么系统还一直在重试
**A: **请按以下步骤排查,
响应体是否按照文档要求的返回了,检查每个字段是否符合要求。比如out_refund_no必须唯一,params字段必须是有效的json字符串。
可能是超时/网络原因导致,请保证接口幂等返回
3.若开发者未响应退款申请回调,系统会重试多久
**A: **系统会一直重试,直到成功。未回调成功的退款单会处于卡单状态,会触发系统告警。若对退款有疑问,请咨询行业运营。
4.为什么开发者未发起退款,但是收到了退款申请回调
**A:**除开发者发起外,还存在用户在退款组件发起、系统自动退款、抖音客服发起等场景,请通过查询退款接口查询订单的退款记录,并检查 refund_source 字段,可以获得具体的退款来源。
退款申请回调接口排查
若遇到退款单一直处于退款中、审核同步失败的 case,大多数情况是由于没有正确响应退款申请回调导致的。这里提供通用的排查方案,请按步骤执行。
退款申请回调接口超时时间为 2s,请确保你的服务响应在 2s 内
1.获取小程序配置的退款申请回调地址
参考发起退款,退款申请回调扩展点的设置,找到你配置的 https url 地址
2.检查退款回调地址能否调通
执行下面的 curl 命令,如果 http 响应不是 200,说明回调地址不通,请检查你的服务。
curl -X POST '你的退款申请回调地址' -H 'Content-Type:application/json' --data '{
"version": "2.0",
"msg": "",
"type": "pre_create_refund"
}'
如果确认你的回调地址是通的,再进行下一步响应参数检查
3.校验响应参数
a. copy 下面的 python 脚本,保存为 check_your_resp.py
b. copy 你的退款申请回调响应
c. 参考下面这个示例,把响应替换成你自己的,然后执行下面的命令
python check_your_resp.py '{
"err_no":0,
"err_tips":"success",
"data":{
"out_refund_no":"id12348473",
"order_entry_schema":{
"path":"page/refundDetail/xxx",
"params":"{"id":1}"
},
"notify_url":"https://www.abc.com"
}
}'
- 如果执行结果是“验证成功!”,说明响应参数是OK的
- 如果执行结果有误,请按照提示调整你的参数
python 校验脚本
# -- coding: utf-8 --
from jsonschema import validate, draft7_format_checker
from jsonschema.exceptions import SchemaError, ValidationError
import json
import sys
# schema 不要修改!!
schema = {
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "test demo",
"description": "validate result information",
"type": "object",
"properties": {
"err_no": {
"description": "error code",
"type": "integer"
},
"err_tips": {
"description": "error msg ",
"type": "string"
},
"data": {
"description": "response date",
"type": "object",
"properties": {
"out_refund_no": {
"type": "string","minLength": 1,"maxLength": 64
},
"notify_url": {
"type": "string",
"pattern":"^|^https://[a-zA-Z0-9\\.\\?/%-_]*
","minLength": 0,"maxLength": 512
},
"order_entry_schema": {
"type": "object",
"properties": {
"path": {
"type": "string","minLength": 1,"maxLength": 512
},
"params": {
"type": "string","minLength": 0,"maxLength": 512
}
}
}
},
"required": ["out_refund_no", "order_entry_schema"]
}
},
"required": [
"err_no", "err_tips", "data"
]
}
# 校验方法, 不要修改!!
def check_your_resp(resp):
try:
validate(instance=resp, schema=schema, format_checker=draft7_format_checker)
except SchemaError as e:
print("验证模式schema出错:\n出错位置:{}\n提示信息:{}".format(" --> ".join([i for i in e.path]), e.message))
except ValidationError as e:
print("json数据不符合schema规定:\n出错字段:{}\n提示信息:{}".format(" --> ".join([i for i in e.path]), e.message))
else:
params = resp.get("data",{}).get("order_entry_schema",{}).get("params","")
if len(params) > 0:
try:
obj = json.loads(params)
if type(obj) != dict or len(obj) < 1:
print("data-->order_entry_schema-->params字段必须是序列化后json字符串")
return
except:
print("data-->order_entry_schema-->params字段必须是序列化后json字符串")
return
print("验证成功!")
if name == 'main':
if len(sys.argv)!=2:
print("执行错误, 正确的命令为: python check_your_resp.py your_resp_json")
exit()
try:
resp = json.loads(sys.argv[1])
if type(resp) != dict:
print("执行错误, 输入参数必须是合法的json字符串")
exit()
check_your_resp(resp)
except:
print("执行错误, 输入参数必须是合法的json字符串")
curl --location --request POST 'http://dev-cn.your-api-server.com/api/v2/create_refund' \
--header 'Content-Type: application/json' \
--data-raw '{
"version": "2.0",
"msg": "{\"app_id\":\"ttqweqw12312\",\"open_id\":\"123123\",\"refund_id\":\"ot123133\",\"order_id\":\"ot1231312\",\"out_order_no\":\"213123\",\"refund_total_amount\":100,\"need_refund_audit\":1,\"refund_audit_deadline\":151231321231,\"create_refund_time\":151231321230,\"refund_source\":1,\"refund_reason\":[\"不喜欢\"],\"refund_description\":\"想退款\",\"cp_extra\":\"cp_extra\",\"refund_item_detail\":{\"item_order_quantity\":1,\"item_order_detail\":[{\"item_order_id\":\"ot123134\",\"refund_amount\":100}]}}",
"type": "pre_create_refund"
}'
{
"err_no": 0,
"err_tips": "123213",
"data": {
"out_refund_no": "89876867867087",
"order_entry_schema": {
"path": "page/refundDetail/xxx",
"params": "{\"id\": 1}"
},
"notify_url": "https://xxx"
}
}