CRM 对接方案
# 功能概述
配置 CRM 对接功能后,在用户进线时,客服系统会调用企业接口查询用户信息并存储至CRM,查询到的客户信息,将作为客户分组、路由策略的条件。 该功能价值如下:
- 完善客户信息:对于三方渠道,不支持接口传参,可通过 CRM 对接功能,在客户进线时,调用企业业务系统 API 查询客户信息,如 WhatsApp 渠道,可根据客户手机号码查询调用企业 API 查询更多客户信息
- 提升安全性:桌面网站和移动网站支持链接传入用户信息,但该方案安全性较低,升级 CRM 对接功能后,通过服务端查询用户信息,安全性更高
# 对接流程说明
该功能需要企业开发人员提供查询客户信息的接口,供客服系统调用以查询客户信息,详细流程如下:
- 企业根据客服系统接口规范,提供查询客户信息 API
- 在线客服-对接设置-对接客户信息,添加对接方案,配置生效的渠道、加密秘钥和查询客户信息 API
- 用户进线时,读取渠道配置的 CRM 对接方案,根据 CRM 对接方案中配置的接口,通过手机号、Email 和 partnerid 查询客户信息,并将查询结果同步至客服系统 CRM
# CRM 对接接口规范
# ● 接口说明
智齿在调用企业接口时,会对请求内容做AES加密,企业在响应时,也需要对返回数据加密。
接口类型:回调型接口
接口作用:通过「查询用户信息接口地址」+ 「partnerid/手机号/邮箱」查询用户信息,将查询到的用户信息,录入 CRM。
请求方式:POST
请求接口合法验证:
1、请求企业接口时 header 中会传时间戳(取服务器时间 timestamp)、sign(签名) 2、sign 生成规则 MD5(companyId + timestamp + secretKey + parameter),parameter(AES 加密后的请求参数) 3、企业根据 header 中传的参数验证请求是否合法
时间戳转换参考工具:
http://tool.chinaz.com/Tools/unixtime.aspx
parameter 加密示例:
例如,查询条件 email = "55612609866@163.com"; partnerid = "partnerId"; tel = "55612609866"; secretKey="secretKey" 。
parameter = AESUtils.dcodes("{"email":"55612609866@163.com","partnerid":"partnerId","tel":"55612609866"}",secretKey) 为 1D6061B2D3E630351669C2A7FA96681E7D2F340484225A0EEF7D0065FF8D1FA4F42FDBCF8841CFA8F92C44026739C74D0A95AABEA0553274A0E393B891DAACD8EEF0A18B45A61F1807FF8EADD9D76132。
sign 签名生成示例:
例如,companyId = "1"; timestamp="1569397773"; secretKey="secretKey";parameter="1D6061B2D3E630351669C2A7FA96681E7D2F340484225A0EEF7D0065FF8D1FA4F42FDBCF8841CFA8F92C44026739C74D0A95AABEA0553274A0E393B891DAACD8EEF0A18B45A61F1807FF8EADD9D76132"。
sign = Md5("11569397773secretKey1D6061B2D3E630351669C2A7FA96681E7D2F340484225A0EEF7D0065FF8D1FA4F42FDBCF8841CFA8F92C44026739C74D0A95AABEA0553274A0E393B891DAACD8EEF0A18B45A61F1807FF8EADD9D76132") 为 868b2fe841ca486e7344b0c15aac1e76。
参数说明:
参数 | 类型 | 必填 | 描述 |
---|---|---|---|
parameter | String | AES加密后的请求参数 |
请求示例:
「用户信息接口地址」需要客户配置,例如 https://xxxxxxx.xxxxxx.com/sobot/geUserInfo
POST https://xxxxxxx.xxxxxx.com/sobot/geUserInfo HTTP/1.1
Content-Type: application/json
timestamp: 1569397773
sign: 868b2fe841ca486e7344b0c15aac1e76
{
"parameter": "1D6061B2D3E630351669C2A7FA96681E7D2F340484225A0EEF7D0065FF8D1FA4F42FDBCF8841CFA8F92C44026739C74D0A95AABEA0553274A0E393B891DAACD8EEF0A18B45A61F1807FF8EADD9D76132" // AES加密后的请求参数
}
2
3
4
5
6
7
8
9
返回参数加密:
1、企业收到请求后,先校验 sign,再对 parameter 进行解密。 2、企业使用与智齿客服系统约定好的 secretKey(如secretKey)对收到的 parameter 字段进行解密,得到原始请求数据。
parameter 解密示例:
例如,接收到的 parameter = "1D6061B2D3E630351669C2A7FA96681E7D2F340484225A0EEF7D0065FF8D1FA4F42FDBCF8841CFA8F92C44026739C74D0A95AABEA0553274A0E393B891DAACD8EEF0A18B45A61F1807FF8EADD9D76132"。
解密示例: AESUtils.ecodes("1D6061B2D3E630351669C2A7FA96681E7D2F340484225A0EEF7D0065FF8D1FA4F42FDBCF8841CFA8F92C44026739C74D0A95AABEA0553274A0E393B891DAACD8EEF0A18B45A61F1807FF8EADD9D76132",secretKey)
解密结果:
{"email":"55612609866@163.com","partnerid":"partnerId","tel":"55612609866"}
data 加密示例:
例如,查询出的客户信息为 {"uname":"su0012","realname":"su0012","email":"55612609866@163.com","tel":"55612609866","remark":"Regular customer, interested in premium services.","customer_fields":"{\"4a069df0fd4d49298041240bf15e47c8\":\"123\"}","is_vip":"1","vip_level":"","user_label":"0fd208364e3a4c67954027680002a89e"}
data = AESUtils.dcodes("{"uname":"su0012","realname":"su0012","email":"55612609866@163.com","tel":"55612609866","remark":"Regular customer, interested in premium services.","customer_fields":"{\"4a069df0fd4d49298041240bf15e47c8\":\"123\"}","is_vip":"1","vip_level":"","user_label":"0fd208364e3a4c67954027680002a89e"}",secretKey)
加密结果: 8DD8EF1E018180C11E287594A1751B095B44EC2029160C96D58305BD536A9DCBB09591D1D708B22E39A041FE06C149C0A7E10381B67770BF97872B9C125847050A9EAE9990323AFFDCD06DC5EC5736FF007545D07099B761DD66BF6268E91EB5BF67907EE9509D24BA3F95E6F7BAE77D575E762612E58D866B00DFA3587B113F73593866A4026EB88A78996FF71A894705024F4DD743D794129CFBA7A14BE410F1C7D87A80F9CFAFF877A53115E1D35C4D8C14A19EA66C52ABD7240B3CA28B301808802FF21B2F072E006F0408C807BF94CFA2109515746DF9697B6597228A7E0B3E7C6907D3EFBBF79F14040FD2450EE9122B813AD0B47BA2DFC0DA406956FB90361A8073E19832AF1C49E6F9CA37F863376417D472CE6AC02D2CAA34BCA3B4DDCF3DEF3C61922AC6DEE6F107F42F44
返回示例:
{
"data":"8DD8EF1E018180C11E287594A1751B095B44EC2029160C96D58305BD536A9DCBB09591D1D708B22E39A041FE06C149C0A7E10381B67770BF97872B9C125847050A9EAE9990323AFFDCD06DC5EC5736FF007545D07099B761DD66BF6268E91EB5BF67907EE9509D24BA3F95E6F7BAE77D575E762612E58D866B00DFA3587B113F73593866A4026EB88A78996FF71A894705024F4DD743D794129CFBA7A14BE410F1C7D87A80F9CFAFF877A53115E1D35C4D8C14A19EA66C52ABD7240B3CA28B301808802FF21B2F072E006F0408C807BF94CFA2109515746DF9697B6597228A7E0B3E7C6907D3EFBBF79F14040FD2450EE9122B813AD0B47BA2DFC0DA406956FB90361A8073E19832AF1C49E6F9CA37F863376417D472CE6AC02D2CAA34BCA3B4DDCF3DEF3C61922AC6DEE6F107F42F44"
}
2
3
没有查询到客户信息时返回示例:
{
"data":""
}
2
3
# ● 用户身份和资料字段
参数 | 类型 | 必填 | 描述 |
---|---|---|---|
uname | String | 否 | 昵称 |
realname | String | 否 | 真实姓名 |
String | 否 | 邮箱账号 | |
tel | String | 否 | 手机或电话 |
remark | String | 否 | 备注 |
customer_fields | String | 否 | 自定义字段(后台控制) |
is_vip | Number | 否 | 是否为VIP客户 0: 普通客户,1: VIP客户 默认普通客户 |
vip_level | String | 否 | VIP等级对应的id(id值通过上方'查询客户固定字段信息'接口获得),若传入为普通客户字段则即使传入了VIP等级字段也无效 |
user_label | String | 否 | 客户标签对应的id(id值通过上方'查询客户固定字段信息'接口获得) |
# ● AES对称加解密工具类
/**
* AES对称加密和解密
*/
public class AESUtils {
private static final Logger log = LoggerFactory.getLogger(AESUtils.class);
/**
* <p>Discription:[加密]</p>
* @param content 明文 用JSON.toJSONString(Map<String, String> map)转换的json字符串
* @param key 加解密规则 访客系统提供key
* @return String 密文
*/
public static String ecodes(String content, String key) {
if (content == null || content.length() < 1) {
return null;
}
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom random=SecureRandom.getInstance("SHA1PRNG");
random.setSeed(key.getBytes());
kgen.init(128, random);
SecretKey secretKey = kgen.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, "AES");
Cipher cipher = Cipher.getInstance("AES");
byte[] byteContent = content.getBytes("utf-8");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
byte[] byteRresult = cipher.doFinal(byteContent);
StringBuffer sb = new StringBuffer();
for (int i = 0; i < byteRresult.length; i++) {
String hex = Integer.toHexString(byteRresult[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
sb.append(hex.toUpperCase());
}
return sb.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return null;
}
/**
* <p>Discription:[解密]</p>
* @param content 密文
* @param key 加解密规则
* @return String 明文
*/
public static String dcodes(String content, String key) {
if (content == null || content.length() < 1) {
return null;
}
if (content.trim().length() < 19) {
return content;
}
byte[] byteRresult = new byte[content.length() / 2];
for (int i = 0; i < content.length() / 2; i++) {
int high = Integer.parseInt(content.substring(i * 2, i * 2 + 1), 16);
int low = Integer.parseInt(content.substring(i * 2 + 1, i * 2 + 2), 16);
byteRresult[i] = (byte) (high * 16 + low);
}
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom random=SecureRandom.getInstance("SHA1PRNG");
random.setSeed(key.getBytes());
kgen.init(128, random);
SecretKey secretKey = kgen.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
byte[] result = cipher.doFinal(byteRresult);
return new String(result);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return null;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99