会员对外文档平台 会员对外文档平台
登录
接口
介绍
  • TOB直充接口

  • TOB激活码直充接口

  • OTT直充接口

  • OTT自动续费接口

  • OTT激活码直充接口

  • 通用接口

  • 内容点播接口

    • 解锁状态批量查询接口
    • 内容定价浮层查询接口
    • 内容购买下单接口
    • 单点内容关联查询接口
  • 卡券类接口

  • 用户信息接口

  • 会员福利接口

  • 合作方客户FV管理

# 内容购买下单接口

# 简介

# 业务介绍

合作方通过本文档的接口实现同步订单操作,购买内容权益。

# 接口定义

# 应用场景

合作方订单完成后调用本接口,通知爱奇艺发放权益。

# 接口域名

环境 域名
生产 openapi.vip.iqiyi.com
测试 test-openapi.vip.iqiyi.com

# URL

/content/subscribe

# 请求方式

参数 说明
Method POST
Content-Type application/x-www-form-urlencoded

# 请求参数

变量名 名称 是否必须 类型 说明
encryptContent 加密后的业务参数 是 String 由业务参数 AES加密得到,具体过程见AES+RSA加密描述
encryptAesPassword 加密后的AES秘钥 是 String RSA加密AES随机秘钥等到生成具体过程见AES+RSA加密描述
partnerNo 合作方编码 是 String 合作方的唯一标识

# data参数

变量名 名称 是否必须 说明
userId 用户唯一标识 3选1 OTT的用户唯一标识,即给该用户开通权益,由32位或者64的字母和数字的组合(userId和mobile,openid至少要填一个,使用的优先级user_id,openId, mobile 依次递减)
mobile 用户手机号 3选1 用户手机号(user_id和mobile,openid至少要填一个,使用的优先级userId,openId, mobile 依次递减)
openid 系统用户id 3选1 合作方系统用户id (userId和mobile,openid至少要填一个,使用的优先级user_id,openId, mobile 依次递减)
partnerOrderCode 订单号 是 合作方的订单号
orderFee 订单总价格 是 订单总价格=sum(totalFee),单位分,这个价格涉及到商务结算、双方分成
partnerProductCode 包月产品或单点内容标识 是 包月产品或单点内容标识,双方约定配置,单点不能与包月订单产品ID相同
cpContentId 内容ID 单点产品必填 爱奇艺侧的内容ID,(对应其他接口的aid),产品类型为单点时有意义
totalFee 产品价格 是 产品价格,值必须大于0,否则认为无效订单(单位分)
payTime 定单支付时间 是 定单支付UTC时间(毫秒)
fc 爱奇艺内部渠道来源信息标识,非爱奇艺售卖渠道无需填写 否
fr_version 爱奇艺内部渠道收银台标识,非爱奇艺售卖渠道无需填写 否
skuId skuId 否 加更礼商品必传

# 业务参数

样例如下:

{
    "userId": "XXXXXXX" , #String类型,OTT的用户唯一标识,即给该用户开通权益,由32位或者64的字母和数字的组合(userId和mobile,openid至少要填一个,使用的优先级user_id,openId, mobile 依次递减)。
    "mobile": "138XXXXXXXX", #String类型,用户手机号(user_id和mobile,openid至少要填一个,使用的优先级userId,openId, mobile 依次递减)
    "openid":"xxxx",  #String  合作方系统用户id (userId和mobile,openid至少要填一个,使用的优先级user_id,openId, mobile 依次递减)
    "partnerOrderCode": "XXXXXX", #String类型,合作方的订单号(必填)。
    "orderFee": 1000, #int类型,订单总价格=sum(totalFee),单位分,这个价格涉及到商务结算、双方分成(必填)
    "orderProducts": [{
          "partnerProductCode": "1001" , #String类型,包月产品或单点内容标识,双方约定配置,单点不能与包月订单产品ID相同(必填)
          "cpContentId": "101"  #String类型,爱奇艺侧的内容ID,(对应其他接口的aid),产品类型为单点时有意义
          "totalFee": 1500,  #int类型,产品价格,值必须大于0,否则认为无效订单(单位分)(必填),
          "pid":"pidxxx" #String   
    }],
    "payTime": 1589359821000  #Long类型,定单支付UTC时间(毫秒)(必填),
    "skuId": "sku_1111111" #String类型,商品类型为加更礼时必传
} 

orderProducts 数组说明:虽然参数体为数组,但只能传一个产品信息,如果传多个,将只取第一个。

# 返回参数

爱奇艺在收到合作方的下单通知后,返回内容为Json String,其参数如下

字段名 类型 说明
msg String 业务处理文字说明
data Object 消息数据,内容为json格式的字符串,采用UrlBase64 Encode
data. encryptContent String 业务参数经过AES 加密得到,具体解密过程见AES+RSA解密描述
data. encryptAesPassword String AES加密秘钥通过RSA合作方公钥得到,具体解密过程见AES+RSA解密描述
code String 业务状态码A00000 正常业务处理

# 返回示例

data.encryptContent()解密后的数据格式如下:

{
	"iqiyiOrderCode":"xxx", #订单号  爱奇艺
	"startTime":1589159821000, #权益开始时间 (毫秒)
	"endTime": 1589359821000 #权益结束时间  (毫秒)
}

# 返回码定义

返回码code 描述
A00000 成功
Q00302 加解密错误
301 参数错误
306 系统错误
307 单点内容校验失败
308 获取UID失败
327 价格无效
330 查询会员信息失败
333 合作方用户没有可用的优惠资格
335 优惠资格的产品与传入的不匹配
336 产品的价格与传入的不匹配

# 附录

# 生成RSA key命令参考

openssl genrsa -out rsa_private_key.pem 1024

openssl pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt > pkcs8_rsa_private_key.pem

openssl rsa -in pkcs8_rsa_private_key.pem -pubout -out pkcs8_rsa_public_key.pem

# AES + RSA加密描述

总体流程:随机生成32位AES密码串 originAesPassword 对请求内容进行AES加密 得到 encryptContent —> 通过爱奇艺公钥对 AES密码串 aesPassword进行RSA 加密得到:encryptAesPassword

采用AES加密业务参数,具体计算方法如下:
1、 随机生成AES 秘钥originAesPassword(不超过64位)
2、 通过AES加密参数
3、 通过RSA使用爱奇艺公钥加密AES密码串

# JAVA版本示例代码如下:

public class Test {

    public static String originAesPassword = "EHgvANZJO8YzTQG4ZJyuGiiXbwU8n58coJDo9t6kg8FiR0I6C22UQPwWWT7clYBW";
    public static String  content = "{\"userId\": \"111111\",\"partnerOrderCode\":\"111111\",\"orderFee\": 1000,\"orderProducts\":[{\"partnerProductCode\": \"1001\",\"totalFee\": 1500,\"pid\":\"123123\"}],\"payTime\": 1589359821000 }";
    public static String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYfgx6oYHOOyb4b9Os9zgtKfUaSqFCJSFS1CGRk1YYzuaUioK46nI+FiMY6OI1xgNvgaVEuIKYgM9niYaODVbvLIj8hx/By4nj91VcIg5b5lTj3no+yDewiecoBp3rohAgpfGDYwLmzuB8lL74XMr3GJPA8MDxdNncvtcXeYpohwIDAQAB";

    public static void main(String[] args) throws Exception {

            System.out.println(AES.AESEncode(originAesPassword,content));
            System.out.println("----------------");
            System.out.println(AES.encryptByPublicKey(originAesPassword,publicKey));

    }
}

注意:AES加密参数后会换行,提交时需删掉空格

# 加密工具类

import org.apache.commons.codec.binary.Base64;
import sun.misc.BASE64Encoder;

import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.*;
import java.security.spec.X509EncodedKeySpec;

public class AES {

    public static String AESEncode(String aesPassword,String content) throws NoSuchPaddingException, BadPaddingException, NoSuchAlgorithmException, IllegalBlockSizeException, UnsupportedEncodingException, InvalidKeyException {
        try {
            SecretKey original_key = null;
            try {
                KeyGenerator _generator = KeyGenerator.getInstance( "AES" );
                SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG" );
                secureRandom.setSeed(aesPassword.getBytes());
                _generator.init(128,secureRandom);
                original_key =  _generator.generateKey();
            }  catch (Exception e) {
                throw new RuntimeException( " 初始化密钥出现异常 " );
            }

            byte [] raw=original_key.getEncoded();
            SecretKey key=new SecretKeySpec(raw, "AES");
            Cipher cipher=Cipher.getInstance("AES");
            cipher.init(Cipher.ENCRYPT_MODE, key);
            byte [] byte_encode=content.getBytes("utf-8");
            byte [] byte_AES=cipher.doFinal(byte_encode);
            String AES_encode=new String(new BASE64Encoder().encode(byte_AES));
            return AES_encode;
        } catch (Exception e){
            e.printStackTrace();
            throw e;
        }

    }

    public static String encryptByPublicKey(String data, String key) throws Exception {
        byte[]byte_publicKey = Base64Util.decode(key);
        byte[]byte_originAesPassword = data.getBytes();
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(byte_publicKey);
        PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        byte[]bytes = cipher.doFinal(byte_originAesPassword);
        return Base64.encodeBase64String(bytes);
    }
}

# AES + RSA解密描述

1、将加密的AES密钥使用合作方私钥解密
2、将加密的业务参数用AES密钥解密得到content

# Java版本代码示例:

public class Test{
        public static void main(String[] args) throws Exception {
            String encryptAesPassword = "";  //加密的AES密钥
            String AESKey = AES.decryptByPrivateKey(encryptAesPassword,privateKey);
            String encryptContent = "";  //加密的业务参数
            String content = AES.AESDecode(AESKey, encryptContent);
            System.out.println(content);
        }
}

# 解密工具类

import org.apache.commons.codec.binary.Base64;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.crypto.Data;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

public class AES {

        public static String privateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALbjYMJwIW+PcvzM+k4vSr09IEKbaXWam33bnqDO+Qsj4POHevGe/jvOuUI/bQn/jXD6WHMivk/N+9Q4firmU1IDRl6fZIA1rfn4S0j+U8Z4bIxFURaBfcrRkA8I3cEQnuCMoD3cJXYZ/uuWogFXzIkTipHj7KrbULIOiR2Zp7ePAgMBAAECgYBJFgi+6yyRdpQPLqMAx6logpr3wz+bvdNRsohr3wprR0VITOX21QDoSa6DKPGcQ0H02jaqnEHNhpWSs5jH8A9vU4XwprOLmo21GYqcnBGjMhZqrJ/IetATqoVBl41zfnsAzZwKQw4hZBsdnhQXMUwoCB4rdUyNMGV4itjhZgBm0QJBAOd7f5j7OAkwU/bfkEtacM1/emgZ5a0Ys0J5RcRPrbhkkwiePKr0O+TQ3tDTRT0NY26DWm/U5+OwKEGt/VyNBl0CQQDKQkcKl8l+Ds518DTj3V3Xj6y0glj6eMYNLIYqi0UPPqtY1ZvvU41FYaTCCZDx/hBQQoOkk0ouefVCqqQST/7bAkAlhXguVPJFUwcZKi3aeQN12+b8fs4i27Ea4ktzwbKYA/1tVTDiSQp4UX78fHJprgTjAfmjzO/1kTVFSC2cVeOlAkB78OFXvGvcs3YRD4FZoO1AiupqMvYThq7Wo9ITgARxsxWM+ljz719ChPNRdEs9/1I/3IKO9zMeB94jXC3uitbBAkEAiT0dweF9U/7OyE74DV5tHbVHWbqEMfIzZ+NzfVlXA91wcS6uAhovjOwCk1/ngToudUbLCazTkSOlWl1mhKBA+A==";

        public static String AESDecode(String aesPassword,String content) throws NoSuchPaddingException, NoSuchAlgorithmException, BadPaddingException, IllegalBlockSizeException, InvalidKeyException, IOException {
            try {
                SecretKey original_key = null;
                try {
                    KeyGenerator _generator = KeyGenerator.getInstance( "AES" );
                    SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG" );
                    secureRandom.setSeed(aesPassword.getBytes());
                    _generator.init(128,secureRandom);
                    original_key =  _generator.generateKey();
                }  catch (Exception e) {
                    throw new RuntimeException( " 初始化密钥出现异常 " );
                }
                byte [] raw=original_key.getEncoded();
                SecretKey key=new SecretKeySpec(raw, "AES");
                Cipher cipher=Cipher.getInstance("AES");
                cipher.init(Cipher.DECRYPT_MODE, key);
                byte [] byte_content= new BASE64Decoder().decodeBuffer(content);
                byte [] byte_decode=cipher.doFinal(byte_content);
                String AES_decode=new String(byte_decode,"utf-8");
                return AES_decode;
            } catch (Exception e) {
                e.printStackTrace();
                throw e;
            }
        }
    
        public static String decryptByPrivateKey(String data, String key) throws Exception {
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(key));
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            byte[] bytes = cipher.doFinal(Base64.decodeBase64(data));
            String originStr = new String(bytes);
            return originStr;
        }
}

# 在线测试

参数 值 备注
partnerNo toB_common_test

所需密钥:

参数 值
爱奇艺公钥 MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYfgx6oYHOOyb4b9Os9zgtKfUaSqFCJSFS1CGRk1YYzuaUioK46nI+FiMY6OI1xgNvgaVEuIKYgM9niYaODVbvLIj8hx/By4nj91VcIg5b5lTj3no+yDewiecoBp3rohAgpfGDYwLmzuB8lL74XMr3GJPA8MDxdNncvtcXeYpohwIDAQAB
合作方私钥 MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALbjYMJwIW+PcvzM+k4vSr09IEKbaXWam33bnqDO+Qsj4POHevGe/jvOuUI/bQn/jXD6WHMivk/N+9Q4firmU1IDRl6fZIA1rfn4S0j+U8Z4bIxFURaBfcrRkA8I3cEQnuCMoD3cJXYZ/uuWogFXzIkTipHj7KrbULIOiR2Zp7ePAgMBAAECgYBJFgi+6yyRdpQPLqMAx6logpr3wz+bvdNRsohr3wprR0VITOX21QDoSa6DKPGcQ0H02jaqnEHNhpWSs5jH8A9vU4XwprOLmo21GYqcnBGjMhZqrJ/IetATqoVBl41zfnsAzZwKQw4hZBsdnhQXMUwoCB4rdUyNMGV4itjhZgBm0QJBAOd7f5j7OAkwU/bfkEtacM1/emgZ5a0Ys0J5RcRPrbhkkwiePKr0O+TQ3tDTRT0NY26DWm/U5+OwKEGt/VyNBl0CQQDKQkcKl8l+Ds518DTj3V3Xj6y0glj6eMYNLIYqi0UPPqtY1ZvvU41FYaTCCZDx/hBQQoOkk0ouefVCqqQST/7bAkAlhXguVPJFUwcZKi3aeQN12+b8fs4i27Ea4ktzwbKYA/1tVTDiSQp4UX78fHJprgTjAfmjzO/1kTVFSC2cVeOlAkB78OFXvGvcs3YRD4FZoO1AiupqMvYThq7Wo9ITgARxsxWM+ljz719ChPNRdEs9/1I/3IKO9zMeB94jXC3uitbBAkEAiT0dweF9U/7OyE74DV5tHbVHWbqEMfIzZ+NzfVlXA91wcS6uAhovjOwCk1/ngToudUbLCazTkSOlWl1mhKBA+A==
点击此处进行接口调试
在线调试

← 内容定价浮层查询接口 单点内容关联查询接口 →