1、用户注册的回调地址必须是一个公网可达的地址,用户可以在注册前使用注册的地址在公网进行自测
测试方式如下:
curl --location '{注册的回调地址}' \--header 'Content-Type: application/json' \-d '{}'
小鱼会使用注册的回调地址进行回调,携带的body如上所示,如500ms未及时返回或返回状态码不为2xx、400,将判定为接口不通,注册失败
2、小鱼默认开启防火墙,拦截的是ip和端口,如果客户注册的地址未在小鱼做过登记或者域名对应的ip和端口发生了改变,请与客户经理联系在小鱼进行备案,否则将判定为接口不通,注册失败
REST URL
POST https://sdk.xylink.com/api/rest/external/{version}/callbacks?enterpriseId=XXX&signature=XXX
请求消息体示例(Json)
{
"handlerUrl": "https://test.top/callback/event",
"callbackEvent":"NewUserCall",
"version":"v2",
"businessTag":"business-test"
}
请求参数说明
业务参数 | 位置 | 说明 | 是否必须 | 初始平台 |
enterpriseId | Query | 企业id | 必传 | 3.9最新版 |
signature | Query | API签名,参见签名规则 | 签名鉴权1.0(旧):是 签名鉴权2.0:否 | 3.9最新版 |
version | Path | 接口版本 | v1版本为历史版本,接口请求内容及返回结构会永久保留 v2及以后版本为活跃版本,请求参数及返回参数会随着业务的需要而扩充,但是字段不会减少,结构也不会变化,因此需要用户兼容字段增加的情形 | 3.9最新版 |
callbackEvent | Body | 注册的事件 | 必传 | 3.9最新版 |
handlerUrl | Body | 用于处理这个事件REST URL,方法必须是POST,若更新成功HTTP Status应为200;调用失败小鱼会重试5次 | 必传 | 3.9最新版 |
version | Body | body版本,当且仅当值为v2时回调数据进行结构化包装 | 回调数据想要使用结构化包装返回时必传v2(部分事件类型默认v2可以不传,请参照事件列表中的默认版本),不需要时key可以省略 | 5.2最新版 |
businessTag | Body | 业务标记,用于给会议室分组,会议室分组请参考:回调功能描述 | 非必传,仅对企业事件生效,对会议室事件无效, | 5.2最新版 |
成功时返回httpcode 200,失败时返回小鱼RESTAPI错误码
REST URL
PUT https://sdk.xylink.com/api/rest/external/{version}/callbacks/{eventType}?enterpriseId=XXX&signature=XXX
请求消息体示例(Json)
{
"handlerUrl": "https://test.top/callback/event",
"callbackEvent":"NewUserCall",
"version":"v2",
"businessTag":"business-"
}
请求参数说明
业务参数 | 位置 | 说明 | 是否必须 | 初始平台 |
enterpriseId | Query | 企业id | 必传 | 3.9最新版 |
signature | Query | API签名,参见签名规则 | 签名鉴权1.0(旧):是 签名鉴权2.0:否 | 3.9最新版 |
version | Path | 接口版本 | v1版本为历史版本,接口请求内容及返回结构会永久保留 v2及以后版本为活跃版本,请求参数及返回参数会随着业务的需要而扩充,但是字段不会减少,结构也不会变化,因此需要用户兼容字段增加的情形 | 3.9最新版 |
callbackEvent | Body | 注册的事件 | 必传 | 3.9最新版 |
handlerUrl | Body | 用于处理这个事件REST URL,方法必须是POST,若更新成功HTTP Status应为200;调用失败小鱼会重试5次 | 必传 | 3.9最新版 |
version | Body | body版本,当且仅当值为v2时回调数据进行结构化包装 | 回调数据想要使用结构化包装返回时必传v2(部分事件类型默认v2可以不传,请参照事件列表中的默认版本),不需要时key可以省略 | 5.2最新版 |
businessTag | Body | 业务标记,用于给会议室分组,会议室分组请参考:回调功能描述 | 非必传,仅对企业事件生效,对会议室事件无效, | 5.2最新版 |
成功时返回httpcode 200,失败时返回小鱼RESTAPI错误码
REST URL
GET https://sdk.xylink.com/api/rest/external/{version}/callbacks?enterpriseId=XXX&&businessTag=XXX&signature=XXX
请求参数说明
业务参数 | 位置 | 说明 | 是否必须 | 初始平台 |
enterpriseId | Query | 企业id | 必传 | 3.9最新版 |
signature | Query | API签名,参见签名规则 | 签名鉴权1.0(旧):是 签名鉴权2.0:否 | 3.9最新版 |
businessTag | Query | 业务标记,用于给会议室分组,会议室分组请参考:回调功能描述 | 非必传,默认查询无分组的回调注册信息 | 5.2最新版 |
version | Path | 接口版本 | v1版本为历史版本,接口请求内容及返回结构会永久保留 v2及以后版本为活跃版本,请求参数及返回参数会随着业务的需要而扩充,但是字段不会减少,结构也不会变化,因此需要用户兼容字段增加的情形 | 3.9最新版 |
成功时返回结果数据,失败时返回小鱼RESTAPI错误码
[
{
"callbackEvent":"NewUserCall",
"handlerUrl":"https://test.top/callback/event"
}
]
REST URL
DELETE https://sdk.xylink.com/api/rest/external/{version}/callbacks/{eventType}?enterpriseId=XXX&businessTag=XXX&signature=XXX
请求参数说明
业务参数 | 位置 | 说明 | 是否必须 | 初始平台 |
enterpriseId | Query | 企业id | 必传 | 3.9最新版 |
signature | Query | API签名,参见签名规则 | 签名鉴权1.0(旧):是 签名鉴权2.0:否 | 3.9最新版 |
businessTag | Query | 业务标记,用于给会议室分组,会议室分组请参考:回调功能描述 | 非必传,默认查询无分组的回调注册信息 | 5.2最新版 |
version | Path | 接口版本 | v1版本为历史版本,接口请求内容及返回结构会永久保留 v2及以后版本为活跃版本,请求参数及返回参数会随着业务的需要而扩充,但是字段不会减少,结构也不会变化,因此需要用户兼容字段增加的情形 | 3.9最新版 |
eventType | Path | 事件类型 | 3.9最新版 |
成功时返回httpcode 200,失败时返回小鱼RESTAPI错误码
REST URL
POST https://sdk.xylink.com/api/rest/external/{version}/callbacks/meetingRoom/event?enterpriseId=XXX&signature=XXX
请求消息体示例(Json)
{
"callbackEvent":"ConferenceRosterInfo",
"handlerUrl":"http://www.baidu.com",
"version":"v2",
"confNumber":"9026984337"
}
请求参数说明
业务参数 | 位置 | 说明 | 是否必须 | 初始平台 |
enterpriseId | Query | 企业id | 必传 | 5.2最新版 |
signature | Query | API签名,参见签名规则 | 签名鉴权1.0(旧):是 签名鉴权2.0:否 | 5.2最新版 |
version | Path | 接口版本 | v1版本为历史版本,接口请求内容及返回结构会永久保留 v2及以后版本为活跃版本,请求参数及返回参数会随着业务的需要而扩充,但是字段不会减少,结构也不会变化,因此需要用户兼容字段增加的情形 | 5.2最新版 |
callbackEvent | Body | 注册的事件 | 必传 | 5.2最新版 |
handlerUrl | Body | 用于处理这个事件REST URL,方法必须是POST,若更新成功HTTP Status应为200;调用失败小鱼会重试5次 | 必传 | 5.2最新版 |
version | Body | body版本,当且仅当值为v2时回调数据进行结构化包装 | 回调数据想要使用结构化包装返回时必传v2(部分事件类型默认v2可以不传,请参照事件列表中的默认版本),不需要时key可以省略 | 5.2最新版 |
confNumber | Body | 云会议室号码 | 必传 | 5.2最新版 |
成功时返回httpcode 200,失败时返回小鱼RESTAPI错误码
REST URL
POST https://sdk.xylink.com/api/rest/external/{version}/callbacks/meetingRoom/event/update?enterpriseId=XXX&signature=XXX
请求消息体示例(Json)
{
"callbackEvent":"ConferenceRosterInfo",
"handlerUrl":"http://www.baidu.com",
"version":"v2",
"confNumber":"9026984337"
}
请求参数说明
业务参数 | 位置 | 说明 | 是否必须 | 初始平台 |
enterpriseId | Query | 企业id | 必传 | 5.2最新版 |
signature | Query | API签名,参见签名规则 | 签名鉴权1.0(旧):是 签名鉴权2.0:否 | 5.2最新版 |
version | Path | 接口版本 | v1版本为历史版本,接口请求内容及返回结构会永久保留 v2及以后版本为活跃版本,请求参数及返回参数会随着业务的需要而扩充,但是字段不会减少,结构也不会变化,因此需要用户兼容字段增加的情形 | 5.2最新版 |
callbackEvent | Body | 注册的事件 | 必传 | 5.2最新版 |
handlerUrl | Body | 用于处理这个事件REST URL,方法必须是POST,若更新成功HTTP Status应为200;调用失败小鱼会重试5次 | 必传 | 5.2最新版 |
version | Body | body版本,当且仅当值为v2时回调数据进行结构化包装 | 回调数据想要使用结构化包装返回时必传v2(部分事件类型默认v2可以不传,请参照事件列表中的默认版本),不需要时key可以省略 | 5.2最新版 |
confNumber | Body | 云会议室号码 | 必传 | 5.2最新版 |
成功时返回httpcode 200,失败时返回小鱼RESTAPI错误码
REST URL
GET https://sdk.xylink.com/api/rest/external/{version}/callbacks/meetingRoom/event?enterpriseId=XXX&signature=XXX&callbackEvent={事件类型}
请求参数说明
业务参数 | 位置 | 说明 | 是否必须 | 初始平台 |
enterpriseId | Query | 企业id | 必传 | 5.2最新版 |
signature | Query | API签名,参见签名规则 | 签名鉴权1.0(旧):是 签名鉴权2.0:否 | 5.2最新版 |
callbackEvent | Query | 注册的事件 | 必传 | 5.2最新版 |
version | Path | 接口版本 | v1版本为历史版本,接口请求内容及返回结构会永久保留 v2及以后版本为活跃版本,请求参数及返回参数会随着业务的需要而扩充,但是字段不会减少,结构也不会变化,因此需要用户兼容字段增加的情形 | 5.2最新版 |
成功时返回结果数据,失败时返回小鱼RESTAPI错误码
[
{
"callbackEvent":"ConferenceRosterInfo",
"handlerUrl":"https://test.top/callback/event",
"version": null
}
]
REST URL
POST https://sdk.xylink.com/api/rest/external/{version}/callbacks/meetingRoom/event/delete?enterpriseId=XXX&signature=XXX
请求消息体示例(Json)
{
"callbackEvent": "ConferenceRosterInfo",
"confNumber": "9026984337"
}
请求参数说明
业务参数 | 位置 | 说明 | 是否必须 | 初始平台 |
enterpriseId | Query | 企业id | 必传 | 5.2最新版 |
signature | Query | API签名,参见签名规则 | 签名鉴权1.0(旧):是 签名鉴权2.0:否 | 5.2最新版 |
version | Path | 接口版本 | v1版本为历史版本,接口请求内容及返回结构会永久保留 v2及以后版本为活跃版本,请求参数及返回参数会随着业务的需要而扩充,但是字段不会减少,结构也不会变化,因此需要用户兼容字段增加的情形 | 5.2最新版 |
callbackEvent | Body | 注册的事件 | 必传 | 5.2最新版 |
confNumber | Body | 云会议室号码 | 必传 | 5.2最新版 |
成功时返回httpcode 200,失败时返回小鱼RESTAPI错误码
注:Roster和Hand管理接口将逐步废弃,请参考(废弃接口)
为方便进行企业级、会议室级事件注册,在此提供批量的事件管理,包含企业级及会议室级事件管理接口
REST URL
POST https://sdk.xylink.com/api/rest/external/{version}/callbacks/batch/add?enterpriseId=XXX&signature=XXX
请求消息体示例(Json)
[
{
"callbackEvent": "VodEditStatus",
"handlerUrl": "http://www.xylink.com",
"version": "v1",
"businessTag": "test"
},
{
"callbackEvent": "ConferenceRosterInfo",
"handlerUrl": "http://www.xylink.com",
"version": "v2",
"confNumber": "9026984337"
}
]
注:任意一个回调地址探测失败都将注册失败,单次最多20个
请求参数说明
业务参数 | 位置 | 说明 | 是否必须 | 初始平台 |
enterpriseId | Query | 企业id | 必传 | 5.2最新版 |
signature | Query | API签名,参见签名规则 | 签名鉴权1.0(旧):是 签名鉴权2.0:否 | 5.2最新版 |
version | Path | 接口版本 | v1版本为历史版本,接口请求内容及返回结构会永久保留 v2及以后版本为活跃版本,请求参数及返回参数会随着业务的需要而扩充,但是字段不会减少,结构也不会变化,因此需要用户兼容字段增加的情形 | 5.2最新版 |
callbackEvent | Body | 注册的事件 | 必传 | 5.2最新版 |
handlerUrl | Body | 用于处理这个事件REST URL,方法必须是POST,若更新成功HTTP Status应为200;调用失败小鱼会重试5次 | 必传 | 5.2最新版 |
version | Body | body版本,当且仅当值为v2时回调数据进行结构化包装 | 回调数据想要使用结构化包装返回时必传v2(部分事件类型默认v2可以不传,请参照事件列表中的默认版本),不需要时key可以省略 | 5.2最新版 |
confNumber | Body | 云会议室号码 | 必传 | 5.2最新版 |
成功时返回httpcode 200,失败时返回小鱼RESTAPI错误码
REST URL
POST https://sdk.xylink.com/api/rest/external/{version}/callbacks/callbacks/page?enterpriseId=XXX&businessTag=XXX&signature=XXX
请求消息体示例(Json)
{
"pageindex": 0,
"pagesize": 10,
"conditionModel": {
"eventLevel": ["enterprise","conference"],
"callbackEvent":["MeetingStatus"]
}
}
参数说明:
业务参数 | 位置 | 说明 | 初始平台 | |
enterpriseId
| Query | 企业id | 必传 | 5.2最新版 |
signature | Query | API签名,参见签名规则 | 签名鉴权1.0(旧):是 签名鉴权2.0:否 | 5.2最新版 |
businessTag | Query | 业务标记,用于给会议室分组,会议室分组请参考:回调功能描述 | 非必传,默认查询所有 | 5.2最新版 |
version | Path | 接口版本 | v1版本为历史版本,接口请求内容及返回结构会永久保留 v2及以后版本为活跃版本,请求参数及返回参数会随着业务的需要而扩充,但是字段不会减少,结构也不会变化,因此需要用户兼容字段增加的情形 | 5.2最新版 |
pageindex | Body | 页码,从0开始 | 5.2最新版 | |
pagesize | Body | 每页数据量,大于0 | 5.2最新版 | |
conditionModel | Body | 条件,此对象可以不传 | 5.2最新版 | |
eventLevel | Body | conditionModel子内容;事件等级,分为企业级(enterprise)和会议室级(conference),可以不传,默认是all | 5.2最新版 | |
callbackEvent | Body | conditionModel子内容;事件类型,可以是会议室事件也可以是企业级事件,会与eventLevel进行匹配查询 | 5.2最新版 |
成功时返回httpcode 200,失败时返回小鱼RESTAPI错误码
{
"pageindex": 0,
"pagesize": 10,
"total": 1,
"data": [
{
"confNumber": null,
"callbackEvent": "MeetingStatus",
"handlerUrl": "http://www.baidu.com",
"version": "v1",
"businessTag": "test"
}
]
}
返回值说明:
参数 | 说明 |
pageindex | 页码 |
pagesize | 每页数量 |
total | 符合conditionModel条件的数据总量,如果conditionModel不传代表所有数据量 |
data | 数据包 |
confNumber | 会议室号 |
callbackEvent | 事件类型 |
handlerUrl | 回调地址 |
version | body版本号 |
businessTag | 业务tag |
如回调的数据为:
{
"conferenceNumber":"91223345",
"count":"32"
}
非结构化包装
{
"conferenceNumber":"91223345",
"count":"32"
}
结构化包装:将数据包装到data
{
"eventType":"NewUserCall",
"data":{
"conferenceNumber":"91223345",
"count":"32"
},
"code":200,
"msgId":"94703009-19b5-410e-8f70-87fcfbf2d239",
"timestamp":1682575409216
}
import cn.hutool.core.util.HexUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.security.Security;
/**
*@Classname SM4Util
*@Date 2021/9/18 5:47 下午
*@Created by anan
*@Description description here
*需要引入包:
*implementation 'org.bouncycastle:bcprov-jdk15on:1.57'
*/
public class EncryptUtil {
private static final Logger logger = LoggerFactory.getLogger(EncryptUtil.class);
static {
Security.addProvider(new BouncyCastleProvider());
}
/**
*国密SM3加盐hash
*@param key
*@param value
*@return
*/
public static String sm3SaltedHashValue(String key, String value) {
logger.info("key: {}, value:{}", key, value);
//加盐
byte[] passwdbyte = arraycat(key.getBytes(),value.getBytes());
//SM3计算
SM3Digest mdDigest=new SM3Digest();
mdDigest.update(passwdbyte,0,passwdbyte.length);
byte[] result=new byte[mdDigest.getDigestSize()];
mdDigest.doFinal(result, 0);
return HexUtil.encodeHexStr(result);
}
/**
* 拼接buf1和buf2数组
*/
public static byte[] arraycat(byte[] buf1,byte[] buf2) {
byte[] bufret=null;
int len1=0;
int len2=0;
if(buf1!=null) {
len1=buf1.length;
}
if(buf2!=null) {
len2=buf2.length;
}
if(len1+len2>0) {
bufret=new byte[len1+len2];
}
if(len1>0) {
System.arraycopy(buf1,0,bufret,0,len1);
}
if(len2>0) {
System.arraycopy(buf2,0,bufret,len1,len2);
}
return bufret;
}
/**
* 计算签名
*
* @param token
* @param content 内容
* @return
*/
public static String calcSign(String token, String content) {
//签名计算
try {
content = content.length() > 100 ? content.substring(0, 100) : content;
String encrypt = EncryptUtil.sm3SaltedHashValue(token, content);
return encrypt.substring(0, 30);
} catch (Exception e) {
logger.error("failed to calcSign, canbe igonre", e);
}
return "";
}
public static void main(String[] args) throws JsonProcessingException {
String token = "1c104121ff95b265e26f3f64a36330d8a5214c96a75a448ed0da1ab4b0fd4354";
String content = "{\"eventType\":\"NewUserCall\",\"data\":{\"callerNumber\":\"+86-19800000235\",\"calleeNumber\":\"9090317356\",\"callerType\":\"user\",\"calleeType\":\"meetingRoom\",\"callerId\":\"26471418\",\"calleeId\":\"9090317356\",\"callerName\":\"TestXiAn00235\",\"calleeName\":\"hongyue 共享会议室\",\"callerExternalUserId\":null,\"calleeExternalUserId\":null,\"callerDeviceType\":5,\"calleeDeviceType\":0,\"callStatus\":\"end\",\"time\":1639382663053,\"userCountOfSameConf\":46,\"meetingId\":\"103-bj1-testqaSig1ms-1161979400250\",\"caller\":true},\"code\":200,\"msgId\":\"9eff78e8-1d6b-4390-935c-34f98fc95cc8\",\"timestamp\":1639382663119}";
ObjectMapper mapper = new ObjectMapper();
Object socketMessage = mapper.readValue(content, Object.class);
System.out.println(socketMessage.toString());
String content1 = mapper.writeValueAsString(socketMessage);
System.out.println(content1);
String sign = calcSign(token, content1);
System.out.println(sign);
}
}