• OpenAPI 简介
  • 小程序 OpenAPI SDK 总览
  • 签名算法
  • 基础能力
  • 触达与营销
  • 支付
  • 评价
  • 交易工具
  • 交易系统
  • 通用交易系统
  • 通用参数
  • 进件
  • 标签
  • 订单
  • 生成下单参数与签名
  • 查询CPS信息
  • 查询订单信息
  • 支付结果回调
  • 退款
  • 履约
  • 结算
  • 提现
  • 获取对账单
  • 行业交易系统
  • 担保支付(即将下线)
  • 抖店绑定
  • 运营
  • 生活服务
  • 垂直行业
  • 其它
  • 订单支付成功/取消时,抖音开放平台交易系统会向开发者的服务发起请求,将支付结果通知到开发者服务端。

    使用限制

    接入接口前请先查看接入前准备是否完成,否则会出现收不到支付回调的问题。

    接口说明

      由于网络波动等原因,可能会产生重复的通知消息,接入方需要做好幂等,正确处理。
      回调可能存在延时,若实时性要求高,开发者可以通过主动请求查询订单信息,确认支付结果。
      支付回调一定要做验签处理,防止收到假通知,可参考下文验签示例代码
      在开发者服务端收到回调且处理成功后,需要按以下正常返回示例返回并且 HTTP 响应状态码设为 200,否则会认为通知失败进行重试。重试频率为 12s/12s/33s/1m/2m/3m/4m/5m/6m/7m - 共约29m。
      JS API 下单 有 payNotifyUrl 字段,如果在下单传了该字段,则会优先使用下单的 payNotifyUrl 回调地址,否则使用解决方案配置的回调地址。
    注意
    无论是否使用 payNotifyUrl 都需要配置解决方案的支付回调地址,否则即使下单传入 payNotifyUrl 也不会生效,详见接入前准备

    基本信息

    基本信息
    HTTP URL
    在解决方案配置-消息通知中指定的回调地址,配置方式参考解决方案配置文档
    HTTP Method
    POST

    请求头

    参考 通用参数

    请求参数

    参数名称
    类型
    是否必填
    描述
    示例值
    msg
    string
    订单相关信息的 json 字符串
    见请求示例
    type
    string
    回调类型(支付结果回调为 payment):payment(支付成功/支付取消)
    payment
    version
    string
    固定值:"3.0"。回调版本,用于开发者识别回调参数的变更
    "3.0"

    msg 字段

    字段名
    类型
    是否必填
    描述
    示例值
    app_id
    string
    小程序 app_id
    ttcfdbb96650e33350
    out_order_no
    string
    开发者系统生成的订单号,与抖音开放平台交易单号 order_id 唯一关联,长度 <= 64byte
    "ext_order_123"
    order_id
    string
    抖音开放平台侧订单id,长度 <= 64byte
    "motb52726742593307630520652"
    status
    string
    支付结果状态,目前有两种状态:
    "SUCCESS" (支付成功 )
    "CANCEL" (支付取消)
    "SUCCESS"
    total_amount
    int64
    订单总金额,单位分支付金额为 = total_amount - discount_amount
    1000
    discount_amount
    int64
    订单优惠金额,单位分,接入营销时请关注这个字段
    0
    pay_channel
    int32
    支付渠道枚举(支付成功时才有):1:微信 2:支付宝 10:抖音支付 20:抖音钻石
    1
    channel_pay_id
    string
    渠道支付单号,如微信/支付宝的支付单号,长度 <= 64byte
    注:status="SUCCESS"时一定有值
    "2iu2082897r9hflquf"
    merchant_uid
    string
    该笔交易的卖家商户号
    注:status="SUCCESS"时一定有值
    "1231123"
    message
    string
    该笔交易取消原因,如:"USER_CANCEL":用户取消"TIME_OUT":超时取消
    "USER_CANCEL"
    event_time
    int64
    用户支付成功/支付取消时间戳,单位为毫秒
    1692775192000
    user_bill_pay_id
    string
    对应用户抖音账单里的"支付单号"
    注:status="SUCCESS"时一定有值
    "DPTS202312120312301231"

    请求示例

    curl --location --request POST 'https://xxxxxxx.net/api/v2/result_callback?timestamp=1345678901234&nonce=iuy987q4htafreqw' \ --header 'Content-Type: application/json' \ --data-raw='{ "version": "3.0", //本次固定为3.0, 通过版本信息识别,用不同的结构体去解析上述关键参数 "msg": "{\"app_id\":\"tt07e371xxxxxxx\",\"status\":\"SUCCESS\",\"order_id\":\"motb52726742593307630520633\",\"item_id\":\"xxxxx\",\"seller_uid\":\"xxxxxx\",\"pay_channel\":1,\"message\":\"\",\"extra\":\"{\\\"cps_info\\\":\\\"poi\\\",\\\"share_amount\\\":\\\"299\\\"}\",\"event_time\":1643185090000,\"out_order_no\":\"ext_order_no_1643185079529\",\"total_amount\":1}", "type": "payment" }'

    msg 字段内容示例

    //支付成功回调示例 { "app_id": "tt07e371xxxxxxx", "out_order_no": "ext_order_123", "order_id": "motb52726742593307630520652", "status": "SUCCESS", "total_amount": 1, "discount_amount": 0, "pay_channel": 1, "channel_pay_id": "2iu2082897r9hflquf", "merchant_uid": "1231123", "message": "", "event_time": 1692775192000, "user_bill_pay_id": "DPTS12031230128124421", } //支付取消回调示例 { "app_id": "tt07e371xxxxxxx", "out_order_no": "ext_order_123", "order_id": "motb52726742593307630520652", "status": "CANCEL", "total_amount": 1, "discount_amount": 0, "merchant_uid": "1231123", "message": "", "event_time": 1692775192000 }

    响应参数

    参数名称
    类型
    描述
    示例值
    err_no
    int64
    错误码
    0
    err_tips
    string
    错误提示
    success

    正常示例

    //正常返回响应且http状态码为200 //注意: //正常返回时一定要保证err_no和err_tips为下面标准返回方式,不然都认为失败,将会重试 { "err_no": 0, "err_tips": "success" }

    异常示例

    //异常响应或http状态码为非200, //字节服务端会不断重试 { "err_no": 1, //非0 "err_tips": "system error" //非success }

    验签示例代码

    JAVA
    /** * 为方便开发者快速接入验签机制,以下提供了解析请求数据和验签的示例代码 @see verifySignature * 请开发者注意,该示例代码仅提供验签核心部分, * 在验签通过且完成业务逻辑处理后,需按上文响应参数规范进行接口响应 */ public class ReqInfo { public String body; public String timestamp; public String nonce; public String signature; } /** * @param reqInfo 通过@see resolveReq方法解析出来的请求体数据 * @param publicKey 平台公钥, 注意验签应使用平台公钥,而非应用公钥 */ public boolean verifySignature(ReqInfo reqInfo, String publicKey) throws Exception { StringBuffer buffer = new StringBuffer(); buffer.append(reqInfo.timestamp).append("\n"); buffer.append(reqInfo.nonce).append("\n"); buffer.append(reqInfo.body).append("\n"); String message = buffer.toString(); Signature sign = Signature.getInstance("SHA256withRSA"); sign.initVerify(string2PublicKey(publicKey)); // 注意验签时publicKey使用平台公钥而非应用公钥 sign.update(message.getBytes(StandardCharsets.UTF_8)); return sign.verify(Base64.getDecoder().decode(reqInfo.signature.getBytes(StandardCharsets.UTF_8))); } public ReqInfo resolveReq(HttpServletRequest req) { log.info("receive payNotify"); String body = getRequestBodyParamsStr(req); String timestamp = req.getHeader("Byte-Timestamp"); String nonce = req.getHeader("Byte-Nonce-Str"); String signature = req.getHeader("Byte-Signature"); log.info("body:%s, timestamp:%s, nonce:%s, signature:%s", body, timestamp, nonce, signature); ReqInfo reqInfo = new ReqInfo(); reqInfo.body = body; reqInfo.timestamp = timestamp; reqInfo.nonce = nonce; reqInfo.signature = signature; return reqInfo; } public String getRequestBodyParamsStr(HttpServletRequest request) { BufferedReader br; String str, wholeStr = ""; try { br = request.getReader(); while ((str = br.readLine()) != null) { wholeStr += str; } wholeStr = wholeStr.replaceAll(" ", ""); log.info(wholeStr); } catch (IOException e) { e.printStackTrace(); log.error(String.valueOf(e)); } return wholeStr; } public PublicKey string2PublicKey(String publicKey) throws Exception{ byte[] decoded = Base64.getDecoder().decode(publicKey); return KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded)); }