快应用消息开放 API 接口文档(服务端)
更新时间:
公共
推送超量说明
长期服务消息:
- 针对用户授权的一个模板消息,模板消息推送数量由开发在v订阅管理后台选用长期服务消息模板时配置,在用户授权后,可连续向用户推送消息的数量为选用模板时填写的”发送数量“。
- 同一个用户在 24 小时内不允许推送相同的消息。
- 单次可授权最多 3 条模板。
一次性服务消息:
- 针对用户授权的一个模板消息,模版消息的推送数量为 1 次,即一次授权一次推送。
- 单次可授权最多 3 条模板。
内容消息(原订阅消息):
- 针对用户授权的一个模板消息,模板消息的推送数量没有上限,且 CP 可配置推送消息的人群,在用户订阅下即可推送,单个用户 24 小时内不同模板消息发送总数量一天最多 5 条。
- 同一个用户在 24 小时内不允许推送相同的消息。
- 单次可授权最多 3 条模板。
vivo 服务器地址
tips:由于测试环境整个链路打通对CP来说比较繁琐,所以建议CP接入时直接对接线上环境
V订阅测试环境域名:jovi-msgcenter-test.vivo.com.cn
V订阅线上环境域名:jovi-msgcenter.vivo.com.cn
公共传入参数
HTTP Header 中( 推送鉴权接口除外 )。
| 属性名字 | 类型 | 是否必填 Y/N | 描述 |
|---|---|---|---|
| access-token | String | Y | 当鉴权成功时会返回该字段,推送消息时需要提供 access-token,有效期默认为 30 天,过期后无法使用,请调用授权接口重新获取; |
全局公共返回码详解
对接完成上线前请一定在群里面跟我们开发(或通过v订阅管理平台->设置->账号信息 )确认几个线上参数:client_id、client_secret。
| result | desc |
|---|---|
| 0 | 请求成功 |
| 7 | accessToken 校验错误 |
| 10000 | 业务错误,具体请参考返回的 msg 信息 |
| 10001 | 消息已经过期 |
| 10010 | 资源已达上限,稍后重试 |
| 10020 | 用户的该模板消息发送次数超过限制 |
| 10030 | 推送速度过快,请稍后再试 |
| 10040 | 未处理异常,请联系开发人员 |
| 10050 | 推送内容审核流量过大,稍后重试 |
| 10051 | 推送内容审核异常 |
| 10052 | 推送内容含有敏感信息 |
| 10060 | 重复订阅 |
| 10070 | 模板信息校验错误,请核对 |
| 10080 | 用户未订阅 |
| 10090 | 模板关键词匹配错误,具体请参考返回的 msg 信息 |
| 10100 | 发生熔断 |
| 10110 | 发生限流 |
| 10130 | vivo 账号登录态校验失败 |
| 10140 | 模板不存在 |
| 20000 | 参数错误,具体请参考返回的 msg 信息 |
| 20020 | 订阅关系不存在 |
接口定义
鉴权
获取 accesstoken 接口
接口说明
要想调用V订阅相关接口,任何接入方都要有个鉴权操作。其他接口 header 中必须携带该接口返回的参数 accessToken 。
注意:需要对 url 参数进行转义处理
限制:一天限制调用不超过 1000 次。
注意:GET请求需要对url参数进行转义处理,POST不需要 传入的参数 client_secret 需要 client_secret = URLEncoder.encode(client_secret,"utf-8") 一次
接口定义
|
接口url |
/openapi/oauth/token | |||
|
协议
|
HTTPS | |||
|
请求方法
|
GET 或者 POST | |||
|
调用方向
|
开发者服务器 -> vivo 开放平台 | |||
|
接口备注
|
POST 情况下 Content-Type 为:application/x-www-form-urlencoded | |||
|
请求头
|
字段名
|
字段类型
|
是否必须
|
字段描述
|
| 无 | ||||
|
输入参数
|
字段名
|
字段类型 |
是否必须
|
字段描述
|
|
grant_type
|
String
|
Y
|
固定值:client_credentials
|
|
|
client_id
|
String
|
Y
|
vivo 开放平台上创建一个服务系统自动分配的 serviceId
|
|
|
client_secret
|
String
|
Y
|
自动分配的 serviceId 对应的 serviceSecret
|
|
|
响应头
|
字段名
|
字段类型
|
是否必须
|
字段描述
|
| 无 | ||||
|
输出参数
(Json) |
字段名
|
字段类型 |
是否必须
|
字段描述
|
|
access_token
|
String
|
Y
|
获取的 Access Token,预留足 250 个字符
|
|
|
expires_in
|
int
|
Y
|
Access Token 的有效期,以秒为单位
|
|
| 请求示例 |
Request::
|
|||
模板消息推送
关键字长度限制;
| 参数类型 | 参数示例 | 类型 |
|---|---|---|
| 事物 | 姓名、地址等 30 字以内(60 个字节) | thing |
| 数字 | 32 位数字以内 | number |
| 字母 | 32 个字母以内 | character |
| 符号 | 5 位符号以内 | symbol |
| 字符串 | 订单号、内容备注等(100 位以内) | string |
| 时间 | 2020 年 12 月 11 日 16:35(40 位以内) | time |
| 金额 | CNY99.9/99.9 元(10 位数以内) | name |
| 电话 | +86-0766-66888866(17 位以内) | phone |
| 车牌 | 粤 Z8Z888 挂(8 位以内) | licenseplate |
| 状态 | 5 个汉字以内 | status |
一次性服务消息推送接口
接口说明
服务消息仅用于向用户发送重要的服务通知,只能用于符合其要求的服务场景中,如信用卡刷卡通知,商品购买成功通知等。不支持广告等营销类消息以及其它所有可能对用户造成骚扰的消息。
接口定义
|
接口url |
/openapi/templete/service/send | |||
|
协议名称
|
HTTPS | |||
|
请求方法
|
POST | |||
|
消息方向
|
开发者服务器 -> vovi 开放平台 | |||
|
接口备注
|
Content-Type 为:application/json;charset=UTF-8 | |||
|
请求头
|
字段名
|
字段类型
|
是否必须
|
字段描述
|
| access-token |
String
|
Y | 通过鉴权接口获取到的 AccessToken | |
|
输入参数
|
字段名
|
字段类型 |
是否必须
|
字段描述
|
|
scene
|
String
|
Y
|
场景标识,在订阅消息的时候 CP 传递的内容(64位以内)
|
|
|
userId
|
String
|
Y
|
CP 维护的用户的标识,和订阅时传递的 userId 对应(64位以内)
|
|
|
clientId
|
String
|
Y
|
快应用 Id
|
|
|
templateId
|
String
|
Y
|
模板 id,开发者在开放平台的服务消息中选用的模板 id
|
|
|
skipType
|
integer
|
Y
|
点击跳转类型 1:跳转快应用页面
|
|
|
skipUrl
|
String
|
Y
|
跳转的 url,例如跳转快应用:hap://app/com.example.quickapp/page?key=value
|
|
|
noticeDigest
|
String
|
N
|
自定义通知内容(最多 60 字)
|
|
|
data
|
Object
|
Y
|
模板填充的数据,根据消息模板的关键词进行填充
|
|
|
color
|
String
|
Y
|
文字颜色,默认黑色
|
|
|
响应头
|
字段名
|
字段类型
|
是否必须
|
字段描述
|
|
输出参数
(Json) |
字段名
|
字段类型 |
是否必须
|
字段描述
|
|
code
|
int
|
Y
|
业务状态码,注意和 http 协议的 Response 状态码区分开来。具体取值含义参考附录
|
|
| 请求示例 |
Request:
Response: |
|||
内容消息推送接口
接口说明
内容消息(原订阅消息)用于向用户发送已经订阅的频道通知;
接口定义
|
接口名称 |
/openapi/templete/subscribe/send | |||
|
协议名称
|
HTTPS | |||
|
请求方法
|
POST | |||
|
消息方向
|
开发者服务器 -> vovi 开放平台 | |||
|
接口备注
|
Content-Type 为:application/json;charset=UTF-8 | |||
|
请求头
|
字段名
|
字段类型
|
是否必须
|
字段描述
|
| access-token |
String
|
Y | 通过鉴权接口获取到的 AccessToken | |
|
输入参数
|
字段名
|
字段类型 |
是否必须
|
字段描述
|
|
scene
|
String
|
Y
|
场景标识,在订阅消息的时候 CP 传递的内容(64位以内)
|
|
|
clientId
|
String
|
Y
|
快应用 Id
|
|
|
userId
|
array
|
Y
|
userId 数组,CP 维护的用户的标识,和订阅时传递的 userId 对应,一次最多 500 个
|
|
|
templateId
|
String
|
Y
|
模板 id,开发者在开放平台的服务消息中选用的模板 id
|
|
|
skipType
|
integer
|
Y
|
点击跳转类型 1:跳转快应用页面
|
|
|
skipUrl
|
String
|
Y
|
跳转的 url,例如跳转快应用:hap://app/com.example.quickapp/page?key=value
|
|
|
noticeDigest
|
String
|
N
|
自定义通知内容(最多 60 字)
|
|
|
data
|
Object
|
Y
|
模板填充的数据,根据消息模板的关键词进行填充
|
|
|
picUrl
|
String
|
N
|
当消息样式为样式二或样式三时必传,图片尺寸规格通过v订阅管理后台查看
|
|
|
响应头
|
字段名
|
字段类型
|
是否必须
|
字段描述
|
|
输出参数
(Json) |
字段名
|
字段类型 |
是否必须
|
字段描述
|
|
code
|
int
|
Y
|
业务状态码,注意和 http 协议的 Response 状态码区分开来。具体取值含义参考附录
|
|
| 请求示例 |
Request:
Response: |
|||
长期服务消息推送接口
接口说明
长期服务消息用于发送需要持续推送服务状态的订单通知,如机票值机、延误、起飞等。不支持广告等营销类消息以及其它所有可能对用户造成骚扰的消息。
接口定义
|
接口url |
/openapi/templete/longService/send | |||
|
协议名称
|
HTTPS | |||
|
请求方法
|
POST | |||
|
消息方向
|
开发者服务器 -> vovi 开放平台 | |||
|
接口备注
|
Content-Type 为:application/json;charset=UTF-8 | |||
|
请求头
|
字段名
|
字段类型
|
是否必须
|
字段描述
|
| access-token |
String
|
Y | 通过鉴权接口获取到的 AccessToken | |
|
输入参数
|
字段名
|
字段类型 |
是否必须
|
字段描述
|
|
scene
|
String
|
Y
|
场景标识,在订阅消息的时候 CP 传递的内容(64位以内)
|
|
|
userId
|
String
|
Y
|
CP 维护的用户的标识,和订阅时传递的 userId 对应(64位以内)
|
|
|
clientId
|
String
|
Y
|
快应用 Id
|
|
|
templateId
|
String
|
Y
|
模板 id,开发者在开放平台的服务消息中选用的模板 id
|
|
|
skipType
|
integer
|
Y
|
点击跳转类型 1:跳转快应用页面
|
|
|
skipUrl
|
String
|
Y
|
跳转的 url,例如跳转快应用:hap://app/com.example.quickapp/page?key=value
|
|
|
noticeDigest
|
String
|
N
|
自定义通知内容(最多 60 字)
|
|
|
data
|
Object
|
Y
|
模板填充的数据,根据消息模板的关键词进行填充
|
|
|
color
|
String
|
Y
|
文字颜色,默认黑色
|
|
|
响应头
|
字段名
|
字段类型
|
是否必须
|
字段描述
|
|
输出参数
(Json) |
字段名
|
字段类型 |
是否必须
|
字段描述
|
|
code
|
int
|
Y
|
业务状态码,注意和 http 协议的 Response 状态码区分开来。具体取值含义参考附录
|
|
| 请求示例 |
Request:
Response: |
|||
事件回传配置
订阅解订阅事件回传
接口说明
用户触发订阅或者解订阅,服务器处理业务完成之后,能够将处理结果回传给开发者;
开发者需要在服务消息管理后台回传配置里配置
服务器地址:vivo 回传数据的服务器地址,HTTPS 访问
密钥:secretKey 数据签名算法需要的密钥;vivo 服务器会根据这个密钥对数据进行签名,开发者服务器根据密钥对签名进行校验;
ps:建议长度为 256 位的 AES 密钥
注意:这里会一次回传多条数据,但是只会使用第一条数据进行签名校验,也就是 CP 服务器收到回传之后也只需要使用第一条数据进行验签即可。
加密算法
相关代码
dto 为 list 报文第一个元素 ,调用 getCpSign 方法即可
public static String getCpSign(Map<String, Object> dto, Long timestamp, String secret) {
StringBuilder sb = new StringBuilder();
sb.append(converDto(dto)).append("&").append(secret);
String str1 = sb.toString();
String str2 = getSHA256Str(str1);
String toSignStr = getStringToSign(timestamp.toString(), str2);
return sha256_HMAC(toSignStr, secret);
}
private static String converDto(Map<String, Object> dto){
StringBuilder sb = new StringBuilder(dto.get("event").toString());
Collection array = (Collection)dto.get("templateIds");
for(Object tmpId:array){
sb.append(tmpId);
}
return sb.append(dto.get("userId"))
.append(dto.get("scene")).toString();
}
/***
* 利用Apache的工具类实现SHA-256加密 并转小写
* @param str 加密后的报文
* @return
*/
private static String getSHA256Str(String str) {
MessageDigest messageDigest;
String encdeStr = "";
try {
messageDigest = MessageDigest.getInstance("SHA-256");
byte[] hash = messageDigest.digest(str.getBytes("UTF-8"));
encdeStr = Hex.encodeHexString(hash);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return encdeStr.toLowerCase();
}
private static String getStringToSign(String timestamp, String sHA256Str) {
return new StringBuilder(timestamp).append(sHA256Str).toString();
}
/**
* sha256_HMAC加密
* @param message 消息
* @param secret 秘钥
* @return 加密后字符串
*/
private static String sha256_HMAC(String message, String secret) {
String hash = "";
try {
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
sha256_HMAC.init(secret_key);
byte[] bytes = sha256_HMAC.doFinal(message.getBytes());
hash = byteArrayToHexString(bytes);
} catch (Exception e) {
e.printStackTrace();
}
return hash;
}
/**
* 将加密后的字节数组转换成字符串
* @param b 字节数组
* @return 字符串
*/
private static String byteArrayToHexString(byte[] b) {
StringBuilder hs = new StringBuilder();
String stmp;
for (int n = 0; b != null && n < b.length; n++) {
stmp = Integer.toHexString(b[n] & 0XFF);
if (stmp.length() == 1) {
hs.append('0');
}
hs.append(stmp);
}
return hs.toString().toLowerCase();
}
测试数据
dto:
{"event": "sub","scene": "123","userId":"fsdf","templateIds": ["fsdfdfggdfgfgffgd"]}
timestamp: 1615449854093
secret: XrwuQQsIdn0CJ/QYW176BMtshpEaRrLvJB0R/mtmLNc=
生成的sign:
f7056be6b1c7d5792da5719bc7312a1d1e98d9efa61728c4f4eca0478d2d2a49
接口定义
|
协议名称
|
HTTPS | |||
|
请求方法
|
POST | |||
|
消息方向
|
vovi 开放平台 -> 开发者服务器 | |||
|
接口备注
|
Content-Type 为:application/json;charset=UTF-8 | |||
|
请求头
|
字段名
|
字段类型
|
是否必须
|
字段描述
|
| timestamp |
long
|
Y | 时间戳 | |
| sign |
String
|
Y | 签名字符串 | |
|
输入参数
|
字段名
|
字段类型 |
是否必须
|
字段描述
|
|
Array
|
||||
|
event
|
String
|
Y
|
事件标识 sub:订阅事件 unSub:解订阅事件
|
|
|
scene
|
String
|
Y
|
场景标识,在订阅消息的时候 CP 传递的内容
|
|
|
userId
|
String
|
Y
|
CP 维护的用户的标识,和订阅时传递的 userId 对应
|
|
|
templateIds
|
Array
|
Y
|
模板 id,开发者在开放平台的服务消息中选用的模板 id
|
|
|
响应头
|
字段名
|
字段类型
|
是否必须
|
字段描述
|
|
输出参数
(Json) |
字段名
|
字段类型 |
是否必须
|
字段描述
|
|
code
|
int
|
Y
|
业务状态码,注意和 http 协议的 Response 状态码区分开来。具体取值含义参考附录
|
|
| 请求示例 |
Request:
Response: |
|||
注意
对接完成上线前请一定在群里面跟我们开发(或通过v订阅管理平台->设置->账号信息 )确认几个线上参数:client_id、client_secret。
Q&A
Q:订阅失败?
A:请确认下订阅参数同一个应用同一个模板 ID 下"userId"+"scene"参数唯一。
Q:发送消息时返回{"code":10040,"msg":"系统异常"}?
A:
- 如果是内容消息(原订阅消息)请检查发送参数"userId"是否为数组格式,因为订阅消息可以一次发送给多个用户,所以设计格式为数组;
- 关键字参数为 key-value 格式:"data": { "thing1": { "value": "我", "color": "#123435" }, "thing2": { "value": "王快马", "color": "#123435" } }。
Q:发送消息返回{"code":10090,"msg":"关键词匹配错误"}?
A:请仔细对照在"v订阅管理后台"配置的模板关键词的属性,例如:
交易状态 { { status1 } }
电话号码 { { number1 } }
充值金额 { { amount1 } }
充值类型 { { thing1 } }
Q:发送消息返回{"code":10020,"msg":"超过调用频率限制"}?
A:一次性服务消息只能发送一条消息,订阅消息一天之内同一个模板同一个用户只能发送 3 条消息。
Q:订阅成功或者取消订阅之后没有收到事件回调?
A:请检查在"v订阅管理后台"配置的回调地址是否正确,除首次添加立即生效外,后续修改都会在 6 小时之内才能生效。
Q:消息发送成功,消息中心也有消息,但是手机没有弹窗通知?
A:请检查手机的快应用通知开关是否开启悬浮弹窗选项,快应用引擎版本需要大于等于 1091,智慧引擎版本需要大于等于 4.6.6.0,并确认 vivo 账户的登录状态是否已经失效,如失效需要重新登录。