• OpenAPI 简介
  • 小程序 OpenAPI SDK 总览
  • 签名算法
  • 基础能力
  • 触达与营销
  • 支付
  • 评价
  • 交易工具
  • 交易系统
  • 通用交易系统
  • 通用参数
  • 进件
  • 标签
  • 订单
  • 生成下单参数与签名
  • 查询CPS信息
  • 查询订单信息
  • 支付结果回调
  • 退款
  • 履约
  • 结算
  • 提现
  • 获取对账单
  • 行业交易系统
  • 担保支付(即将下线)
  • 抖店绑定
  • 运营
  • 生活服务
  • 垂直行业
  • 其它
  • 生成下单参数与签名
    收藏
    我的收藏

    接口说明

    该文档对tt.requestOrder接口中,服务端如何生成 data 和 byteAuthorization 参数进行说明。

    使用说明

      开发者按照文档说明构造data,其结果为string类型,且必须符合json格式
      开发者基于data生成签名,并按文档说明构造byteAuthorization,其结果为string类型

    data

    属性名
    类型
    默认值
    必填
    说明
    skuList
    SkuList[]
    SkuList说明见下文
    下单商品信息
    注意:目前只支持传入一项
    outOrderNo
    string
    外部订单号
    totalAmount
    number
    订单总金额
    单位:分
    payExpireSeconds
    number
    支付超时时间,单位秒,例如 300 表示 300 秒后过期;不传或传 0 会使用默认值 300,不能超过48小时。
    payNotifyUrl
    string
    支付结果通知地址,必须是 HTTPS 类型,传入后该笔订单将通知到此地址。
    注:开发者需先按照接入前准备,配置并发布一个默认回调地址。
    merchantUid
    string
    开发者自定义收款商户号
    orderEntrySchema
    Schema
    Schema说明见下文
    订单详情页
    limitPayWayList
    number[]
    屏蔽的支付方式,当开发者没有进件某个支付渠道,可在下单时屏蔽对应的支付方式。如:[1, 2]表示屏蔽微信和支付宝
    枚举说明:
    1-微信
    2-支付宝

    SkuList

    属性名
    类型
    默认值
    必填
    说明
    skuId
    string
    外部商品id,如:号卡商品id、会员充值套餐id、某类服务id、付费工具id等
    price
    number
    价格
    单位:分
    quantity
    number
    购买数量
    0 < quantity <= 100
    title
    string
    商品标题,长度 <= 256字节
    imageList
    string[]
    商品图片链接,长度 <= 512 字节
    注意:目前只支持传入一项
    type
    number
    商品类型,详见此处的商品类型枚举值
    示例:
      号卡商品:传101
      剧集: 传404
    tagGroupId
    string
    交易规则标签组
    点此查看对应商品类型的标签组ID
    注意:根据接入规范,选择适合的标签组ID传入,该标签组对应标签将会在用户收银台展示。
    entrySchema
    Schema
    Schema说明见下文
    商品详情页链接
    skuAttr
    string
    商品信息:需要将不同商品类型定义的具体结构,转换成json string
    号卡类商品必填,即当前商品类型 type in [101、102、103、104、105、106、107]的商品必填,内部结构请详见下文 ”skuAttr“ 小节说明。
    示例:
    { "package_cost": //14.50元/2月 { "amount": 1450,//总价14.50元 "time_len": 2, //时长2 "unit": "month" //时长单位:月 }, "call_duration": 1000, //通话时长:1000分钟 "traffic_bundle": 50,//流量包大小50G "telecom_operator_type": "official" }
    内容消费:当前商品类型 type in [402、403、404、405、406]的商品必填,内部结构请详见下文 ”skuAttr“ 小节“内容消费”小节说明。
    402 会员示例
    { "member_type": "VIP", "member_name": "会员", "benefit_time": { "num_of_year": 0, "num_of_month": 1, "num_of_day": 0 } }

    skuAttr

    号卡类

    属性名
    类型
    默认值
    必填
    示例值
    说明
    package_cost
    Json Object
    { "amount": 1450, "time_len": 2, "unit": "month" }
    号卡商品套餐详情,具体字段说明详见下文”package_cost字段说明“小结
    call_duration
    number
    否,call_duration与traffic_bundle至少需要填一个
    1000
    套餐包含的通话时长,单位:分钟,
    traffic_bundle
    number
    50
    套餐包含的流量包大小,单位:G
    telecom_operator_type
    string
    official
    提供套餐的运营方性质,枚举值
    official:官方
    private:私营

    package_cost字段说明

    属性名
    类型
    默认值
    必填
    示例值
    说明
    amount
    number
    1450
    套餐售价,单位:分
    time_len
    number
    2
    套餐时长
    unit
    string
    month
    时长单位,枚举值
    year:年
    month:月
    day:天

    内容消费

    会员商品-402
    属性名
    类型
    默认值
    必填
    示例值
    说明
    member_name
    string
    会员
    会员名称
    member_type
    string
    会员类型
    请固定填写 VIP(此字段用于未来扩展会员类型)
    benefit_time
    object
    参考BenefitTime对象
    会员对应的权益时长
    虚拟币商品-403
    属性名
    类型
    默认值
    必填
    示例值
    说明
    coin_name
    string
    K币
    虚拟币名称
    coin_type
    string
    COIN
    请固定填写 COIN(此字段用于未来扩展虚拟币类型)
    amount
    number
    10
    虚拟币数量
    can_expire
    bool
    FALSE
    TRUE
    是否存在过期时间(如果存在过期时间,则一定要填写TRUE)
    benefit_time
    object
    参考BenefitTime对象
    如果can_expire=true时,对应权益时长
    content_promotion_coins
    list<object>
    参考ContentPromotionCoin对象
    赠送的虚拟币,是一个列表,列表中的每个元素参考ContentPromotionCoin对象,如果无赠送虚拟币,不需要传递该值
    ContentPromotionCoin
    属性名
    类型
    默认值
    必填
    示例值
    说明
    coin_name
    string
    K币
    虚拟币名称
    coin_type
    string
    COIN_GIFT
    目前请固定填写 COIN_GIFT(标识该虚拟币是赠送所得)
    amount
    number
    10
    虚拟币数量
    can_expire
    bool
    FALSE
    TRUE
    是否存在过期时间(如果存在过期时间,则一定要填写TRUE)
    benefit_time
    object
    参考BenefitTime对象
    如果can_expire=true时,对应权益时长
    剧集商品-404
    属性名
    类型
    默认值
    必填
    示例值
    说明
    album_name
    string
    权利游戏
    剧名称
    album_id
    string
    7324950105420005914
    剧ID(抖音的剧ID)
    episode_id_list
    []string
    [7324950105420005915,7324950105420005916]
    集ID列表(抖音的集ID)
    can_expire
    bool
    FALSE
    TRUE
    是否存在过期时间(如果存在过期时间,则一定要填写TRUE)
    benefit_time
    object
    参考BenefitTime对象
    如果can_expire=true时,对应权益时长
    整剧商品-405
    属性名
    类型
    默认值
    必填
    示例值
    说明
    album_name
    string
    权利游戏
    剧名称
    album_id
    string
    7324950105420005914
    剧ID(抖音的剧ID)
    can_expire
    bool
    FALSE
    TRUE
    是否存在过期时间(如果存在过期时间,则一定要填写TRUE)
    benefit_time
    object
    参考BenefitTime对象
    如果can_expire=true时,权益时长
    券商品-406
    属性名
    类型
    默认值
    必填
    示例值
    说明
    coupon_type
    string
    EPISODE_COUPON
    券类型,目前仅支持剧集券,请固定传 EPISODE_COUPON 值
    episode_coupon_info
    object
    当券类型为EPISODE_COUPON时,必填
    参考EpisodeCouponInfo定义
    剧集券的信息
    can_expire
    bool
    FALSE
    TRUE
    是否存在过期时间(如果存在过期时间,则一定要填写TRUE)
    benefit_time
    object
    参考BenefitTime对象
    如果can_expire=true时,权益时长
    EpisodeCouponInfo
    属性名
    类型
    默认值
    必填
    示例值
    说明
    album_use_type
    number
    1
    剧集券的使用范围
    1-可兑换所有剧的剧集
    2-仅支持兑换部分剧的剧集
    episode_nums
    number
    1
    剧集券兑换的集数
    1-表示可兑换1集
    2-表示可兑换2集
    part_albums
    list<object>
    参考Album的定义
    如果album_use_type=2,需要传递该值表明可在哪些剧进行兑换,列表长度不超过50,每一个元素是一个album结构
    all_album_episode_range
    string
    1-9999
    可兑换集的范围(对全剧生效),如果全集可兑换,默认传1-9999即可
    如果album_use_type=2,该值不会生效,传递1-9999作为默认即可
    如果只能兑换第1集,传递1
    如果可兑换1-3集,传递1-3
    如果可兑换第1集和第3集,传递1|3
    Album
    属性名
    类型
    默认值
    必填
    示例值
    说明
    album_id
    string
    7262626
    剧id
    episode_range
    string
    1-9999
    此剧可兑换集的范围(对单剧生效),如果全集可兑换,默认传1-9999即可
    如果只能兑换第1集,传递1即可
    如果可兑换1-3集,传递1-3
    如果可兑换第1集和第3集,传递1|3
    BenefitTime对象
    属性名
    类型
    默认值
    必填
    示例值
    说明
    num_of_year
    number
    0
    1
    1年会员
    num_of_month
    number
    0
    2
    2月会员
    num_of_day
    number
    0
    3
    3天会员
    num_of_hour
    number
    0
    4
    4小时会员
    num_of_minute
    number
    0
    5
    5分钟会员
    备注:num_of_year , num_of_month , num_of_day ,num_of_hour,num_of_minute 只能有一个有效(只有一个值大于 0 的,另外四个为 0),不能同时按照年,月,日,小时,分钟定义权益时长,不然会报参数错误。

    Schema:

    名称
    类型
    是否必传
    描述
    正确示例
    错误示例
    path
    string
    小程序xxx详情页跳转路径,没有前导的“/”路径后不可携带query参数,路径中不可携带『?: & *』等特殊字符,路径只可以是『英文字符、数字、_、/ 』等组成,长度<=512byte
    page/path/index
    page/path/index?id=1234page/path:hello/index
    params
    string
    xx情页路径参数,自定义的json结构,内部为k-v结构,序列化成字符串存入该字段,平台不限制,但是写入的内容需要能够保证生成访问xx详情的schema能正确跳转到小程序内部的xx详情页,长度须<=512byteparams内key不可重复
    '{"id":1234, "name":"hello"}'
    {"id":1234,"id":2334,"name":hello}

    结果示例:

    {"skuList":[{"skuId":"657","price":1,"quantity":1,"title":"test_title","imageList":["https://xxxx.com/xxxxx.jpg"],"type":401,"tagGroupId":"tag_group_7272625659888041996"}],"outOrderNo":"test_out_order_no","totalAmount":1,"payExpireSeconds":300,"orderEntrySchema":{"path":"","params":""},"payNotifyUrl":"https://xxxxx/xxx"}

    byteAuthorization

    推荐开发者基于代码示例进行开发。
    第一步:构造待签名串。
    待签名串一共有五行(且必须严格按照以下顺序),每一行必须以 \n(换行符,ASCII 编码值为 0x0A)结束。
    POST\n/requestOrder\n请求时间戳\n请求随机串\ndata\n
    第二步:计算签名值。
    使用「应用私钥」对待签名串进行SHA256-RSA2048签名,并对签名结果进行Base64编码得到签名值。
    第三步:生成 byteAuthorization。
    以下为具体格式:
    SHA256-RSA2048 应用appid,请求随机串nonce_str,请求时间戳timestamp,公钥版本key_version,签名值signature
    示例:
    SHA256-RSA2048 appid=tt8629f0941xxxxxxxx,nonce_str=7CC7D26A52F05BA5CFD,timestamp=1698916641,key_version=1,signature=jz1+pplJX2IRcS24lsdsFFOF7+Wky3KiQhOMUz58u7n5VEDNr/axPLzm8+i232Aw4vxjoxavI77n8iUSaGcjHOXS1e4pkdJEHE1qQkQ1bNGsT1X2yXOMB5t8gceGiBJimwQkTSeq+KK/OzYTlCRaNuE784Mx7wtUdXCnBDKZDMxWBxu6R7L2eZ8mC5v67lV+oJcu7tRD10PePRXH1z+9zaX1CSwEg3K0IkLFxHqgrpsER7OeVBE8w9glsxjvuc2Gg==

    代码示例

    JAVA
    GO
    PHP
    import java.security.PrivateKey; import java.security.Signature; import java.nio.charset.StandardCharsets; import java.util.Base64; import java.security.KeyFactory; import java.security.spec.PKCS8EncodedKeySpec; import java.util.UUID; public class DYSign { public static void main(String []args) { // 请求时间戳 long timestamp = System.currentTimeMillis()/1000L; // 开发者填入自己的小程序app_id String appId = "testAppId"; // 随机字符串 String nonceStr = UUID.randomUUID().toString(); // 应用公钥版本,每次重新上传公钥后需要更新,可通过「开发管理-开发设置-密钥设置」处获取 String keyVersion = "1"; // 应用私钥,用于加签 重要:1.测试时请修改为开发者自行生成的私钥;2.请勿将示例密钥用于生产环境;3.建议开发者不要将私钥文本写在代码中 String privateKeyStr = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCZSHNcFfthd/bV\nYexEJWOBVEjjDcXjfr1fYevuraNFfMmLPKV836BbvCiUSWHzJYEpkJ934e/j28NB\nEcEbPDLiGlLTd6AVwR22TkUwpLr41oQprz0HKFwhVPZ0HQCGIv0pVMA53TFSitIq\niqbNLmgm5yzSNqNy1t/0X/RfqEtA6Eoxw9u/Sx57i+pBFuLlZYanlm57+b7t1khg\n9JHvF0ulo7DScyJ4qgrD7oQf0RIQB0rqCFIeYuYO1cfvnxb9x4DPodEyVoAM4i9Y\ndFop9ZHt73W/icuLku/P8/G1+arzB5b7S1S3ky5/KdS8AEA9Ww5czZcdf9Jgm2S6\nRymjFGjzAgMBAAECggEBAIryGNgdePyWcSJmHHR9a+CdFWD0aDBa/7CJpAN8VKc1\ngcB8Xgp+7+6X9jTM/EQa+CVEWrmiDgF/gVPnkyNsAzff4rqcEnoFzzglZSS9/lp4\nod7jYa+uTy1LxgflDkeJSfEASStqrT4EZpR3kNInQfQZ1BBNxQXhb6smm+9mL6kK\nQJjAqBgEqtUAmNv0GnH89ZPPgZuIZeeL4cb4BhMEoa5MBnI+HDf07cN1nECQXRJl\nHU/iyhAPfP7RpO8O9KGDEDE36qebu0Cu4yUjWANXiqECFv93sQzONotkl3VPealv\nXM+jzGT7YdgHo/t3QKE8flMBo/XUzGTqi8j5AOXiaBkCgYEAylKVtjQMYgg4qMwd\n9Je+KZ9qL6QVHCsB2NPUt8N99oj70efsG4aGaEAadr8meNhIJ5lpoK+FXqSBIbbD\nS/xeOVI3XoMx/EdKLw/ZNi87G/EHYK9z7Fr3W7q8DFXe2hZ/ojFXC/aaBanjVVBK\n/6RfPzXfnx+vGX/t1FhcLC+yQD8CgYEAwfMtrXfH+3dW77dxXT/CTFJVs/o1K2qb\nepnQ6A33KMHPLBtPZZ6z5rzIO7OMSNItOTXTEoRXHmOKc5FtXGtbCvGSRByb6FgD\nWG3p2Bp2sZLuJBzXmLbSnEbHTNHM6uTgxNgWAh8pYpjPY8xF7BqYz2rGT47OPBmc\ntRzDjnzjak0CgYAqkM1mk/S2+zvQZ4E14GblouBYPZEjZ/jvgUGTl9F8eL1iIAUQ\nlXDZpgLrULPrYLVtf101rTfF/Z4dVbIo3mOEc8OqYre1d9onpJHyUGWDL2Z59O/S\nniDEb7j4b2h/QZSArxi9L5if8GofnNDqj85qIg92Dthr6PpEXoKl2TMLSQKBgFzQ\nBHHYukiqSV4ZyRQ4qMBhPkYMXFlUgObgqMoDtN06MewHfa1BjxHCEYgQWfeXLLEO\nAt3/mrkeJWk8lLr/XOgVxkr17d34EFHG93rE3zwG9hMuAjZAdvT2IfWvCIL32GAa\nkB2fz+ww+D3nySY9bBcGH7R+wE6eaxF4nFSZizKZAoGBAJzuaWCnVK0djfgvUsjm\nGUtyDvgyREcpAsXvES1pB2NLVeEUxm0uRtj6k4DhCv3rJfUwfMr0+sa9NUnXuaSR\nVqLYvAD8bNPKXwn7ymzQ7WioCqmZuUhLnQRppkjhfQGKLH0MnMw9Xh9FwJ9kzGNE\nUnTEhaaHsoaHMlLlRET32gyG".replace("\n",""); // 生成好的data String data = "{\"skuList\":[{\"skuId\":\"1\",\"price\":9999,\"quantity\":1,\"title\":\"标题\",\"imageList\":[\"https://dummyimage.com/234x60\"],\"type\":401,\"tagGroupId\":\"idxxx\"}],\"outOrderNo\":\"1213\",\"totalAmount\":9999,\"limitPayWayList\":[],\"payExpireSeconds\":3000,\"orderEntrySchema\":{\"path\":\"page/index/index\",\"params\":\"{\\\"poi\\\":\\\"6601248937917548558\\\",\\\"aweme_useTemplate\\\":1}\"}}"; String byteAuthorization = getByteAuthorization(privateKeyStr, data, appId, nonceStr, timestamp, keyVersion); System.out.println(byteAuthorization); } public static String getByteAuthorization(String privateKeyStr, String data, String appId, String nonceStr, long timestamp, String keyVersion) { String byteAuthorization = ""; try { // 生成签名 String signature = getSignature(privateKeyStr, "POST", "/requestOrder", timestamp, nonceStr, data); // 构造byteAuthorization StringBuilder sb = new StringBuilder(); sb.append("SHA256-RSA2048 "). append("appid=").append(appId).append(","). append("nonce_str=").append(nonceStr).append(","). append("timestamp=").append(timestamp).append(","). append("key_version=").append(keyVersion).append(","). append("signature=").append(signature); byteAuthorization = sb.toString(); } catch (Exception ex) { ex.printStackTrace(); return ""; } return byteAuthorization; } public static String getSignature(String privateKeyStr, String method, String uri, long timestamp, String nonce, String data) throws Exception { String rawStr = method + "\n" + uri + "\n" + timestamp + "\n" + nonce + "\n" + data + "\n"; System.out.println(rawStr); Signature sign = Signature.getInstance("SHA256withRSA"); sign.initSign(string2PrivateKey(privateKeyStr)); sign.update(rawStr.getBytes(StandardCharsets.UTF_8)); return Base64.getEncoder().encodeToString(sign.sign()); } public static PrivateKey string2PrivateKey(String privateKeyStr) { PrivateKey prvKey = null; try { byte[] privateBytes = Base64.getDecoder().decode(privateKeyStr); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateBytes); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); prvKey = keyFactory.generatePrivate(keySpec); } catch (Exception ex) { ex.printStackTrace(); } return prvKey; } }

    密钥生成

    推荐使用签名调试工具
    适用于JAVA(PKCS8格式)
    非JAVA适用(PKCS1格式)
    openssl genrsa -out private_key.pem 2048 rsa -in private_key.pem -pubout -out public_key.pem pkcs8 -topk8 -inform PEM -in private_key.pem -outform PEM -nocrypt -out rsa_private_key.pem rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem exit // 注:生成出来的私钥文件为rsa_private_key.pem, 公钥文件为rsa_public_key.pem // PKCS8格式,私钥以-----BEGIN PRIVATE KEY-----开头,-----END PRIVATE KEY-----结尾

    应用公钥上传方式

    登录「抖音开放平台」,进入小程序的「开发管理-开发设置」页,在「密钥设置」处点击“更新”。