丁香医生开放平台开发者文档
1. 概述
1. 阅读对象
本文档供接入合作方技术开发人员阅读,主要包含系统交互流程、详细接口文档等内容。
2. 接口使用场景
此文档上的所有接口仅供服务端之间调用,不能直接使用客户端直接调用丁香医生的开放接口(客户端调用存在接口密钥泄漏的风险)。
3. 接入方式
接入方式 | API方式 | H5方式 |
---|---|---|
说明 | 丁香医生仅提供开放接口,合作方需要自实现问诊服务全流程(用户端展现、问诊费用支付、用户端消息通知等)。 | 丁香医生提供开放接口和HTML5网页,用户端展现由丁香医生提供的网页承载,问诊费用直接入丁香医生账户,合作方需完成用户端消息通知。 |
特点 | 可跨多端接入,定制性高、便于合作方业务整合。 | 对接便捷,但定制性低。 |
不支持场景 | 无 | 不支持在禁用支付宝支付的应用内使用(如:微信、手机QQ)。 |
2. 系统交互流程
1. 用户授权流程
3. 接口规范说明
1. 接口交互方式
以 HTTPS(GET/POST)+JSON 方式进行数据交互,请求地址:https://ask.dxy.com/open/i/platform/${接口编号}
。
所有接口都只能在服务端之间调用,合作方不能通过客户端直接调用。
2. 参数类型及长度定义
名称 | 说明 |
---|---|
Int | 正整型,范围[0~2^63) |
String(x) | 字符串型,字符串长度不超过x,例如String(500)表示长度不超过500的字符串 |
3. 请求参数说明
当接口说明需要用户级鉴权时,需要设置请求头 ask-platform-sid:${userToken} ,获取userToken的方式见接口100010。
请求头User-Agent
不建议使用工具包或者编程语言默认的值,如包含"Apache,HttpClient,Java,python"等关键字的User-Agent
会被限流,可使用User-Agent: DXYS-Partner
。
- GET请求:所有参数需要以URLEncode(UTF-8)格式发送(先签名再URL编码),例如:key1=value1&key2=value2&key3=%E4%B8%AD%E6%96%87%E5%8F%82%E6%95%B0
- POST参数:request headers中的Content-Type设置为application/x-www-form-urlencoded;charset=utf-8 ,有文件上传时为 multipart/form-data 。
4. 签名方式
所有请求都需要包含的公共参数如下:
参数名 | 类型 | 示例值 | 说明 |
---|---|---|---|
nonce | String(32) | GPID5J2m5cZ4pZEYxgA2l7qIzgHSoLmF | 定长32个字符的随机数字字母字符串 [0-9a-zA-Z]{32} |
timestamp | Int | 1509419983789 | Unix毫秒单位的时间戳,需取发起请求的时间,与服务端时间差超过10分钟会判定为不合法请求 |
appId | String(32) | dxy6p64jhh75oi4cpq6 | 丁香医生分配给合作方的appId,是调用方的身份标识 |
sign | String(100) | 26aefe8433c2aef074e041847282570abc7cb862 | 除sign外其他参数的签名 |
sign 的生成方式:除 sign 参数外,包括业务参数在内的所有参数都要参与签名,按字段名称 ASCII 码从小到大排序后,字段名和字段值都采用原始值使用 URL 键值对格式 key1=value1&key2=value2&key3=value3... 拼成字符串 string,然后对拼接后的字符串使用SHA-1算法生成签名 sign 。 注意: appSignKey 只参与签名,不作为请求参数。
Java版签名的例子 SignUtil.java:
public static void main(String[] args) throws IOException {
String appId = "<appId>";
String appSignKey = "<appSignKey>";
String timestamp = String.valueOf(System.currentTimeMillis());
String nonce = StringUtil.random(32);
Map<String, Object> params = new HashMap<>();
params.put("appId", appId);
params.put("timestamp", timestamp);
params.put("nonce", nonce);
params.put("param1", "value1");//业务参数1
params.put("param2", "value2");//业务参数2
params.put("sign", getSign(params, appSignKey));
//.发送请求
String url = "https://ask.dxy.com/open/i/platform/130001";
String responseBodyAsString = HttpClientUtil.post(url, params);
System.out.println(responseBodyAsString);
}
/**
* 获取签名
*
* @param params
* @param appSignKey
* @return
*/
public static String getSign(Map<String, Object> params, String appSignKey){
TreeMap<String, Object> treeMap = new TreeMap<>();
params.forEach(treeMap::put);
treeMap.remove("sign");
treeMap.put("appSignKey", appSignKey);
StringBuilder signSb = new StringBuilder();
treeMap.forEach((key, value) -> signSb.append(key).append("=").append(value).append("&"));
if (signSb.length() > 0) {
signSb.deleteCharAt(signSb.length() - 1);
}
return getSHA1(signSb.toString().getBytes());
}
/**
* 用SHA1算法生成安全签名
*
* @param content 签名信息
* @return 安全签名
*/
public static String getSHA1(byte[] content) throws NoSuchAlgorithmException {
// SHA1签名生成
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update(content);
byte[] digest = md.digest();
StringBuffer hexstr = new StringBuffer();
String shaHex = "";
for (int i = 0; i < digest.length; i++) {
shaHex = Integer.toHexString(digest[i] & 0xFF);
if (shaHex.length() < 2) {
hexstr.append(0);
}
hexstr.append(shaHex);
}
return hexstr.toString();
}
5. 返回结果示例
GET返回示例:
{
"data": {
"items": [
{
"order_id": 67000032,
"question_id": 9800001,
"status": 0,
"merchant_fee": 1500,
"create_timestamp": 1509372966000,
"confirm_timestamp": 1509373966000
}
]
}
}
POST返回示例:
{
"data": {
"items": [
{
"updated": 1509419983789,
"id": "6200001"
}
]
}
}
错误信息返回示例:
{
"error": {
"code": 10003,
"message": "请求参数不正确"
}
}
成功的请求返回结果会包含data
节点,失败的请求返回结果会包含error
节点。
接口返回为错误结构体时,code
为错误码,message
为错误信息。详细错误码定义见附录6.2。
分页数据结构示例:
{
"data": {
"items_per_page": 8, //每页包含元素个数
"start_index": 9, //当前页起始元素编号
"page_index": 2, //当前页码,从1开始
"total_pages": 3, //总页码
"total_items": 20, //总元素个数
"current_item_count": 8, //当前页元素个数
"items": []
}
}
其中:items_per_page
表示每页包含元素个数,start_index
表示当前页起始元素编号,page_index
表示当前页码,total_pages
表示总页码,current_item_count
表示当前页元素个数。
注意应该通过判断page_index与total_pages
的大小关系来确定是否有下一页。
4. 接口列表
1. 用户授权
100010-获取用户身份凭证
接口编号 | 100010 |
---|---|
请求方 | 合作方 |
服务方 | 丁香医生 |
请求方式 | POST |
用户级鉴权 | 否 |
接口说明 | 为合作方用户获取用户 token。非幂等,对同一个用户多次获取token后,最新的 token 会覆盖原 token (原 token 失效) |
请求参数
参数名 | 类型 | 必填 | 示例值 | 说明 |
---|---|---|---|---|
uid | String(30) | 是 | u100821 | 合作方的用户唯一标识 |
nickname | String(30) | 是 | 飞翔的电灯泡 | 用户在合作方的昵称 |
返回结果
参数名 | 类型 | 必填 | 示例值 | 说明 |
---|---|---|---|---|
token | String(64) | 是 | ASK-3yK3skDcrx66us24 | 用户身份凭证,重新获取前一直有效 |
100011-获取免登录链接
接口编号 | 100011 |
---|---|
请求方 | 合作方 |
服务方 | 丁香医生 |
请求方式 | POST |
用户级鉴权 | 否 |
接口说明 | web开放方式接入丁香医生开放平台时,获取用户进入丁香医生系统的免登录链接。 |
请求参数
参数名 | 类型 | 必填 | 示例值 | 说明 |
---|---|---|---|---|
uid | String(30) | 是 | u100821 | 合作方的用户唯一标识 |
redirect | String(200) | 否 | aHR0cHM6Ly9hc2suZHh5LmNvbS9pbmRleCMvZmluZA== | 登入后重定向链接的base64(UTF-8)编码(有重定向需求的传入) |
返回结果
参数名 | 类型 | 必填 | 示例值 | 说明 |
---|---|---|---|---|
login_url | String(300) | 是 | https://ask.dxy.com/login/openweb/1767104/yROI2iesF9EQiM3Mi2O?redirect=aHR0cDovL2Fza3Rlc3QuZHh5Lm5ldC9pbmRleCMvbWluZS8 | web 开放方式用户的免登录链接(15分钟内仅可使用1次) |
2. 科室和医生信息
110001-快速提问搜索医生
接口编号 | 110001 |
---|---|
请求方 | 合作方 |
服务方 | 丁香医生 |
请求方式 | GET |
用户级鉴权 | 否 |
接口说明 | 根据文本内容匹配医生 |
请求参数
参数名 | 类型 | 必填 | 示例值 | 说明 |
---|---|---|---|---|
q | String(500) | 是 | "感冒" | 搜索文本 |
min_price | Int | 否 | 1000 | 价格筛选的下限,单位分 |
max_price | Int | 否 | 8000 | 价格筛选的上限,单位分 |
job_title | Int | 否 | 4 | 医生职称:2医师,3主治医师,4副主任医师,5主任医师 |
department | Int | 否 | 2 | 科室ID,见接口110002 |
page_index | Int | 否 | 1 | 页码,默认1 |
items_per_page | Int | 否 | 10 | 分页大小,默认10 |
返回结果
参数名 | 类型 | 必填 | 示例值 | 说明 |
---|---|---|---|---|
user_id | Int | 是 | 666 | 医生ID |
avatar | String(255) | 是 | https://askpub.dxycdn.com/2017/09/07/06/pcbedzr9.jpg | 头像 |
nickname | String(30) | 是 | 王小明 | 医生姓名 |
hospital_name | String(60) | 是 | 北京协和医院 | 医院名称 |
hospital_info | Array[HospitalInfo] | 是 | 详见下方"HospitalInfo数据结构" | 详见下方"HospitalInfo数据结构" |
job_title_name | String(30) | 是 | 主治医师 | 职称 |
section_name | String(30) | 是 | 儿科 | 科室名称 |
ask_fee | Int | 是 | 1000 | 问诊费用,单位:人民币分 |
vip | Boolean | 是 | true | 是否加V认证 |
star | String(5) | 否 | 4.99 | 患者给医生的评分(保留两位小数格式化后的字符串) |
tags | Array[String] | 否 | ["感冒","发烧"] | 擅长疾病,列表长度不超过50,单元素字符串长度不超过30。 |
display_tags | Array[String] | 否 | ["从业10年","三甲医院"] | 展示标签,列表长度不超过50,单元素字符串长度不超过50。 |
HospitalInfo数据结构
参数名 | 类型 | 示例值 | 说明 |
---|---|---|---|
name | String(100) | 浙江大学医学院附属儿童医院滨江院区 | 医院名称 |
grade_name | String(30) | 三级甲等 | 医院级别 如 "三级甲等","未知" |
trade | String(30) | 公立 | 医院性质 如 "公立","未知" |
110002-科室列表
接口编号 | 110002 |
---|---|
请求方 | 合作方 |
服务方 | 丁香医生 |
请求方式 | GET |
用户级鉴权 | 否 |
接口说明 | 获取丁香医生对应问题类型可用的科室列表 |
请求参数
参数名 | 类型 | 必填 | 示例值 | 说明 |
---|---|---|---|---|
question_type | int | 否 | 0 | 当传0时,返回图文问诊可用的科室列表,传6时,返回电话急诊可用的科室列表,传7时,返回快速图文可用的科室列表 |
返回结果
参数名 | 类型 | 必填 | 示例值 | 说明 |
---|---|---|---|---|
id | Int | 是 | 12 | 科室ID |
name | String(30) | 是 | 疼痛科&麻醉科 | 科室名称 |
member_count | Int | 是 | 213 | 科室中可用的医生数 |
description | String(128) | 是 | 手术麻醉、坐骨神经痛、三叉神经痛、癌痛 | 科室简介 |
110003-科室下的医生列表
接口编号 | 110003 |
---|---|
请求方 | 合作方 |
服务方 | 丁香医生 |
请求方式 | GET |
用户级鉴权 | 否 |
接口说明 | 科室下的医生列表(可分页) |
请求参数
参数名 | 类型 | 必填 | 示例值 | 说明 |
---|---|---|---|---|
department | Int | 是 | 12 | 科室ID,见接口110002 |
rank_type | Int | 否 | 1 | 排序规则:0综合排序,1月回答次数降序,2星级评分降序,4价格升序,5价格降序,6响应时间升序 |
min_price | Int | 否 | 0 | 价格筛选,最小价格,单位:人民币分 |
max_price | Int | 否 | 5000 | 价格筛选,最大价格,单位:人民币分 |
job_title | Int | 否 | 4 | 医生职称:2医师,3主治医师,4副主任医师,5主任医师 |
area_id | int | 否 | 110000 | 各个地区的行政划分码, 完整版需要向丁香医生平台方获取 |
page_index | Int | 否 | 1 | 页码,从1开始 |
items_per_page | Int | 否 | 10 | 页长,默认10,最大200 |
返回结果
参数名 | 类型 | 必填 | 示例值 | 说明 |
---|---|---|---|---|
user_id | Int | 是 | 4592076 | 医生id |
avatar | String(255) | 是 | https://askpub.dxycdn.com/avatar.jpg | 医生头像URL |
nickname | String(30) | 是 | 戴梦成 | 医生姓名 |
hospital_name | String(60) | 是 | 青岛XXXX医院 | 医院名称 |
hospital_info | Array[HospitalInfo] | 是 | 详见下方"HospitalInfo数据结构" | 详见下方"HospitalInfo数据结构" |
location_str | String(30) | 否 | 山东 青岛市 | 医生所在地区 |
section_name | String(30) | 是 | 皮肤科 | 科室名称 |
job_title_name | String(30) | 是 | 主治医师 | 医生职称 |
ask_fee | Int | 是 | 1000 | 问诊费用,单位:人民币分 |
reply_count | Int | 是 | 200 | 月回答数(最近30天回答数) |
vip | Boolean | 是 | true | 是否加V认证 |
star | String(5) | 否 | 4.99 | 患者给医生的评分(保留两位小数格式化后的字符串) |
tags | Array[String] | 否 | ["痤疮","脱发","过敏"] | 擅长疾病列表,列表长度不超过50,单元素字符串长度不超过30。 |
display_tags | Array[String] | 否 | ["从业10年","三甲医院"] | 医生标签列表,列表长度不超过50,单元素字符串长度不超过50。 |
start_work_year | Int | 否 | 1997 | 开始工作年份(非必传字段) |
introduction | String(512) | 否 | 皮肤病学博士。擅长湿疹皮炎、荨麻疹、过敏、痤疮(痘痘)、银屑病牛皮癣、癣、灰趾甲、白斑、脱发提问放清晰图片 | 医生个人简介 |
status | Int | 是 | 0 | 医生状态:0正常,1封禁,2停诊 |
HospitalInfo数据结构
参数名 | 类型 | 示例值 | 说明 |
---|---|---|---|
name | String(100) | 浙江大学医学院附属儿童医院滨江院区 | 医院名称 |
grade_name | String(30) | 三级甲等 | 医院级别 如 "三级甲等","未知" |
trade | String(30) | 公立 | 医院性质 如 "公立","未知" |
110004-医生详细信息
接口编号 | 110004 |
---|---|
请求方 | 合作方 |
服务方 | 丁香医生 |
请求方式 | GET |
用户级鉴权 | 否 |
接口说明 | 获取医生详细信息 |
请求参数
参数名 | 类型 | 必填 | 示例值 | 说明 |
---|---|---|---|---|
user_id | Int | 是 | 4592076 | 医生id |
返回结果
参数名 | 类型 | 必填 | 示例值 | 说明 |
---|---|---|---|---|
user_id | Int | 是 | 4592076 | 医生id |
avatar | String(255) | 是 | https://askpub.dxycdn.com/avatar.jpg | 医生头像URL |
nickname | String(30) | 是 | 戴梦成 | 医生姓名 |
hospital_name | String(60) | 是 | 中国医学科学院皮肤病医院 | 医院名称 |
hospital_info | Array[HospitalInfo] | 是 | 详见下方"HospitalInfo数据结构" | 详见下方"HospitalInfo数据结构" |
location_str | String(30) | 否 | 山东 青岛市 | 医生所在地区 |
section_name | String(30) | 是 | 皮肤科 | 科室名称 |
job_title_name | String(30) | 是 | 主治医师 | 医生职称 |
ask_fee | Int | 是 | 1000 | 问诊费用,单位:人民币分 |
vip | Boolean | 是 | true | 是否加V认证 |
star | String(5) | 否 | 4.99 | 患者给医生的评分(保留两位小数格式化后的字符串) |
avg_reply_time | Int | 否 | 120 | 医生的平均响应时间,单位秒 |
tags | Array[String] | 否 | ["痤疮","脱发","过敏"] | 擅长疾病列表,列表长度不超过50,单元素字符串长度不超过30。 |
display_tags | Array[String] | 否 | ["从业10年","三甲医院"] | 医生标签列表,列表长度不超过50,单元素字符串长度不超过50。 |
start_work_year | Int | 否 | 1997 | 开始工作年份 |
introduction | String(512) | 否 | 北京协和医学院皮肤病学博士。擅长湿疹皮炎、荨麻疹、过敏、痤疮(痘痘)、银屑病牛皮癣、癣、灰趾甲、白斑、脱发提问放清晰图片 | 医生个人简介 |
status | Int | 是 | 0 | 医生状态:0正常,1封禁,2停诊 |
practice_experience | String | 否 | 1.复旦医学院毕业\n2.全国首例颅脑手术\n3.完成心脏搭桥手术240例 | 执业经历 |
academic_experience | String | 否 | 1.中华医学会科研项目1项\n2.主持国家自然基金4项\n3.参与编写《支气管镜诊疗专家共识》 | 学术经历 |
professional_profile | String | 否 | 1.中华医学会皮肤病理学组委员\n2.北京医师协会新生儿儿科医师分会理事\n3.中国医师协会皮肤分会专业委员会委员 | 专业资历 |
HospitalInfo数据结构
参数名 | 类型 | 示例值 | 说明 |
---|---|---|---|
name | String(100) | 浙江大学医学院附属儿童医院滨江院区 | 医院名称 |
grade_name | String(30) | 三级甲等 | 医院级别 如 "三级甲等","未知" |
trade | String(30) | 公立 | 医院性质 如 "公立","未知" |
110005-通过提问内容推荐科室
接口编号 | 110005 |
---|---|
请求方 | 合作方 |
服务方 | 丁香医生 |
请求方式 | GET |
用户级鉴权 | 否 |
接口说明 | 通过提问内容推荐科室 |
请求参数
参数名 | 类型 | 必填 | 示例值 | 说明 |
---|---|---|---|---|
content | String(600) | 是 | 得了灰指甲怎么办 | 描述问诊的语句或者关键词 |
返回结果
参数名 | 类型 | 必填 | 示例值 | 说明 |
---|---|---|---|---|
id | Int | 否 | 12 | 科室ID |
name | String(30) | 否 | 疼痛科&麻醉科 | 科室名称 |
3. 问诊相关
120001-创建问题
接口编号 | 120001 |
---|---|
请求方 | 合作方 |
服务方 | 丁香医生 |
请求方式 | POST |
用户级鉴权 | 是 |
接口说明 | 创建问题(需要15分钟内调用接口130001确认订单后问诊正式生效) |
请求参数
参数名 | 类型 | 必填 | 示例值 | 说明 |
---|---|---|---|---|
content | String(600) | 是 | 感冒了怎么办 | 问题内容 |
doctor_user_id | Int | 条件 | 12196047 | 医生ID(type=0普通图文问诊时必填) |
ask_fee | Int | 是 | 3100 | 问诊费用,单位人民币分,用于价格校验。 |
ip | String(30) | 否 | 100.100.100.100 | 用户的ip |
attachments | MultipartFile[] | 否 | 此字段不参与签名,multipart/form-data方式上传图片文件,支持批量上传,最多9个文件,单文件不超过10M,文件总大小不超过20M | |
attachments_urls | String(2000) | 否 | https://cdndomain.com/img1.jpg | 支持批量,最多9个文件,单文件不超过10M,文件总大小不超过20M。多个URL可以先UrlEncode后再半角逗号连接,例如:"https%3A%2F%2Fcdndomain.com%2Fimg1.jpg,https%3A%2F%2Fcdndomain.com%2Fimg2.jpg" |
type | Int | 否 | 0 | 问诊类型:0普通图文问诊,6电话急诊,7快速图文问诊。 |
cellphone | String(30) | 否 | 18888888888 | 患者手机号,当问题为电话急诊时需要传入 |
department | Int | 否 | 9 | 科室ID,见接口110002。电话急诊、快速图文时建议传入。 |
返回结果
参数名 | 类型 | 必填 | 示例值 | 说明 |
---|---|---|---|---|
order_id | Int | 是 | 1 | 订单ID |
question_id | Int | 是 | 1 | 问题ID |
120002-获取问题详情
接口编号 | 120002 |
---|---|
请求方 | 合作方 |
服务方 | 丁香医生 |
请求方式 | GET |
用户级鉴权 | 是 |
接口说明 | 获取问题详情(用户创建问诊时的内容算作第1个对话dialog) |
请求参数
参数名 | 类型 | 必填 | 示例值 | 说明 |
---|---|---|---|---|
question_id | Int | 是 | 1 | 问题ID |
返回结果
参数名 | 类型 | 必填 | 示例值 | 说明 |
---|---|---|---|---|
id | Int | 是 | 1 | 问题ID |
doctor | 同接口110003返回数据结构 | 否 | 接诊的医生信息,非定向的问诊(快速图文、电话急诊)没有医生接诊时无当前节点。 | |
content | String(600) | 是 | “感冒怎么办” | 问题内容 |
status | Int | 是 | 问题状态 | 0:待回答,1:已回答,2:用户取消,3:医生拒绝回答,4:超时退回,5:已结束,6:待支付,7:已取消支付 |
finish_status | Int | 是 | 问题完成状态 | 0:未完成,1:系统自动完成,2:提问者关闭,3:用户投诉后结束,4:审核不通过结束,5:管理后台关闭 |
live_call_state | Int | 否 | 电话急诊状态,只有当问题类型为电话急诊时才会返回。 | 1:待接听,2:医生接诊,3:通话完成,4:已结束(正常),5:已结束(无人接听),6:已结束(医生通话异常),7:已结束(问诊总结异常),10:已结束(通话遇到问题),11:正在接听(医生已拨打),12:已结束(医生通话异常,未拨打过患者手机)13:已结束(丁香医生后台发起的退款) |
create_timestamp | long | 是 | 1509361251000 | 创建Unix时间戳(单位:毫秒) |
finish_timestamp | long | 是 | 1509361251000 | 问题结束时间。13 位毫秒级时间戳 |
attachment_url_list | Array[String] | 否 | ["https://askpub.dxycdn.com/2017/09/07/06/pcbedzr9.jpg", "https://askpub.dxycdn.com/2017/09/07/06/pcbedzr9.jpg"] | 图片URL(临时链接,5分钟实效性) |
refused_message | String(512) | 是 | 症状不明 | 医生拒绝理由 |
appended | Boolean | 是 | true | 当前是否为被追问状态 |
ask_count | Int | 是 | 1c | 询问次数(含提问) |
last_reply_timestamp | Int | 是 | 1509361251000 | 医生最后一次回复Unix时间戳(单位:毫秒) |
order_id | Int | 是 | 3377217 | 订单id |
dialogs | Array[Dialog] | 否 | 对话内容(第一条即为提问),Dialog定义如下 |
Dialog数据结构
参数名 | 类型 | 示例值 | 说明 |
---|---|---|---|
id | Int | 1 | 对话ID |
question_id | Int | 1 | 问题ID |
user_id | Int | 1 | 用户ID |
user_nickname | String(30) | 阿wing | 用户昵称 |
user_avatar | String(255) | https://askpub.dxycdn.com/2017/09/07/06/pcbedzr9.jpg | 用户头像 |
type | Int | 0 | 对话类型:0提问,1回答 |
content | String(600) | "多喝热水" | 对话内容 |
attachment_url_list | Array[String] | ["https://askpub.dxycdn.com/2017/09/07/06/pcbedzr9.jpg", "https://askpub.dxycdn.com/2017/09/07/06/pcbedzr9.jpg"] | 图片url(5分钟内有效),最多9个链接,每个链接最长255个字符。 |
voice_list | Array[VoiceDetail] | 录音文件列表,VoiceDetail定义如下 | |
create_timestamp | Int | 1509361251000 | 创建Unix时间戳(单位:毫秒) |
VoiceDetail数据结构
参数名 | 类型 | 示例值 | 说明 |
---|---|---|---|
id | Int | 1 | 对话ID |
url | String(255) | https://video1p.dxycdn.com/2019/0912/743/33678485709834 | 录音文件URL(5分钟内有效) |
duration | Int | 600000 | 录音时长,单位为毫秒 |
file_format | String(10) | M4A | 文件后缀名(M4A,WAV) |
120003-用户追问
接口编号 | 120003 |
---|---|
请求方 | 合作方 |
服务方 | 丁香医生 |
请求方式 | POST |
用户级鉴权 | 是 |
接口说明 | 用户追问(问诊没有被医生回复或者医生回复的24小时内可追问,最多追问2次) |
请求参数
参数名 | 类型 | 必填 | 示例值 | 说明 |
---|---|---|---|---|
content | String(600) | 是 | 接下来怎么办 | 追问内容 |
question_id | Int | 是 | 1 | 对应问题ID |
attachments | MultipartFile[] | 否 | multipart/form-data方式上传图片文件,支持批量上传,最多9个文件,单文件不超过10M,文件总大小不超过20M[无法识别的内容] | |
attachments_urls | String(2000) | 否 | https://cdndomain.com/img1.jpg | 支持批量,最多9个文件,单文件不超过10M,文件总大小不超过20M。多个URL可以先UrlEncode后再半角逗号连接,例如:"https%3A%2F%2Fcdndomain.com%2Fimg1.jpg,https%3A%2F%2Fcdndomain.com%2Fimg2.jpg" |
dialog_index | Int | 否 | 2 | 用户对话的顺序编号,追问从2开始依次递增。可用来避免因接口重复请求导致用户对话重复的问题,重复请求可保证幂等,建议传入。 |
返回结果
参数名 | 类型 | 必填 | 示例值 | 说明 |
---|---|---|---|---|
id | Int | 是 | 1 | 追问对话ID |
updated | Int | 是 | 1509419983789 | 处理完成的Unix时间戳(单位:毫秒) |
120004-问题列表
接口编号 | 120004 |
---|---|
请求方 | 合作方 |
服务方 | 丁香医生 |
请求方式 | GET |
用户级鉴权 | 是 |
接口说明 | 获取某用户所问的问题列表 |
请求参数
参数名 | 类型 | 必填 | 示例值 | 说明 |
---|---|---|---|---|
page_index | Int | 否 | 1 | 页码默认1 |
items_per_page | Int | 否 | 10 | 页大小 默认10 |
返回结构
同接口120002返回数据结构
4. 投诉处理
140001-发起投诉
接口编号 | 140001 |
---|---|
请求方 | 合作方 |
服务方 | 丁香医生 |
请求方式 | POST |
用户级鉴权 | 是 |
接口说明 | 投诉分为两种类型(详细投诉状态流转见 附录6.3): 0 发起投诉 这里的投诉应该是由合作方初审过的确实需要交由丁香医生处理的用户投诉,当合作方对问诊发起投诉后,丁香医生会有专人负责审核,审核结果会通过状态通知接口反馈给合作方。当审核状态为“通过”时表示丁香医生已经认可这起投诉,结束了用户的问诊并且将问诊费用已经退回到合作方的账户中,但和用户相关的处理如退款、消息通知需要合作方自行处理。 1 发起申诉(申请取消提问) 根据问题的状态来确认是否能够直接进行取消本次提问的操作,会在1min内告知是否“通过”申诉 |
请求参数
参数名 | 类型 | 必填 | 示例值 | 说明 |
---|---|---|---|---|
content | String(1024) | 是 | 问题没有被解决,医生态度也不好,回应非常慢 | 投诉内容,长度需要控制在10到500字。 |
question_id | Int | 是 | 1 | 对应问题ID |
cellphone | String(11) | 否 | 13713366666 | 联系方式 |
type | Int | 是 | 1 | 投诉类型: 0 发起投诉 1 发起申诉(取消提问) |
返回结构
参数名 | 类型 | 必填 | 示例值 | 说明 |
---|---|---|---|---|
id | Int | 是 | 1 | 投诉ID |
updated | Int | 是 | 1509419983789 | 处理完成的Unix时间戳(单位:毫秒) |
140002-获取投诉
接口编号 | 140002 |
---|---|
请求方 | 合作方 |
服务方 | 丁香医生 |
请求方式 | GET |
用户级鉴权 | 是 |
接口说明 | 获取某个问题下的投诉 |
请求参数
参数名 | 类型 | 必填 | 示例值 | 说明 |
---|---|---|---|---|
question_id | Int | 是 | 1 | 对应问题ID |
返回结构
参数名 | 类型 | 必填 | 示例值 | 说明 |
---|---|---|---|---|
id | Int | 是 | 1 | 投诉ID |
question_id | Int | 是 | 1 | 对应问题ID |
status | Int | 是 | 0 | 0:未审核,1:审核通过,2:审核不通过 |
content | String(1024) | 是 | 没有效果 | 投诉内容 |
cellphone | String(11) | 否 | "13713366666" | 联系方式 |
create_timestamp | Int | 是 | 1509361251000 | 创建Unix时间戳(单位:毫秒) |
reason | String(1024) | 否 | 同意 | 审核原因 |
5. 订单相关
130002-订单查询
接口编号 | 130002 |
---|---|
请求方 | 合作方 |
服务方 | 丁香医生 |
请求方式 | GET |
用户级鉴权 | 是 |
接口说明 | 根据订单id查询一条订单记录 |
请求参数
参数名 | 类型 | 必填 | 示例值 | 说明 |
---|---|---|---|---|
order_id | Int | 是 | 62000121 | 丁香医生统一订单id |
返回结果
参数名 | 类型 | 必填 | 示例值 | 说明 |
---|---|---|---|---|
order_id | Int | 是 | 62000121 | 丁香医生统一订单id |
question_id | Int | 是 | 98000232 | 问题id |
status | Int | 是 | 1 | 订单状态:0待确认,4已确认,5退款中,6已退款,10已关闭 |
ask_order_fee | Int | 是 | 1500 | 丁香医生订单金额(单位:分,币种CNY) |
merchant_fee | Int | 是 | 1500 | 合作方订单金额(单位:分,币种CNY) |
create_timestamp | Int | 是 | 1509361251000 | 订单创建Unix时间戳(单位:毫秒) |
confirm_timestamp | Int | 否 | 1509361351000 | 订单确认Unix时间戳(单位:毫秒) |
130001-订单确认
接口编号 | 130001 |
---|---|
请求方式 | POST |
请求方 | 合作方 |
服务方 | 丁香医生 |
用户级鉴权 | 是 |
接口说明 | 确认一笔订单,关联的问诊正式生效 |
请求参数
参数名 | 类型 | 必填 | 示例值 | 说明 |
---|---|---|---|---|
order_id | Int | 是 | 62000121 | 丁香医生统一订单id |
返回结果
参数名 | 类型 | 必填 | 示例值 | 说明 |
---|---|---|---|---|
id | Int | 是 | 62000121 | 请求时的丁香医生统一订单id |
updated | Int | 是 | 1509419983789 | 处理完成的Unix时间戳(单位:毫秒) |
130003-关闭订单
接口编号 | 130003 |
---|---|
请求方 | 合作方 |
服务方 | 丁香医生 |
请求方式 | POST |
用户级鉴权 | 是 |
接口说明 | 关闭一笔未确认的订单。若订单已调用130001(订单确认)接口,则不能再关闭。 |
请求参数
参数名 | 类型 | 必填 | 示例值 | 说明 |
---|---|---|---|---|
order_id | Int | 是 | 62000121 | 丁香医生统一订单id |
返回结果
参数名 | 类型 | 必填 | 示例值 | 说明 |
---|---|---|---|---|
id | Int | 是 | 62000121 | 请求时的丁香医生统一订单id |
updated | Int | 是 | 1509419983789 | 处理完成的Unix时间戳(单位:毫秒) |
5. 消息推送
除了通过调用API的方式与开放平台产生交互,还可以通过消息推送及时接收到新的状态信息。避免轮询API,大大提高API调用效率。 合作方接入时向丁香医生开发平台提供接口地址即可接收推送。
注意: 出于接口安全性的考虑,callback地址必须支持https,且必须是标准的443端口(即url格式为https://domain.com/xxx
,不能带端口号)
为了保证系统安全,合作方作为服务端接收丁香医生发起的通知请求时,需要对请求参数进行验证签名。状态通知接口的业务参数不参与签名,仅对appId、appSignKey、nonce、timestamp参数按照上面「接口规范说明」-「签名方式」对数据进行签名得到签名字符串sign2。通过比较sign和sign2的相等与否来实现验签。
附上一段接收通知Java版示例供参考:
public class AskCallBackSample {
private static final String APP_ID = "<appId>";
private static final String APP_SIGN_KEY = "<appSignKey>";
public String askCallback(HttpServletRequestMock httpServletRequest) throws Exception {
Map<String, Object> params = new HashMap();
params.put("nonce", httpServletRequest.getParameterValues("nonce")[0]);
params.put("timestamp", httpServletRequest.getParameterValues("timestamp")[0]);
String appIdParam = httpServletRequest.getParameterValues("appId")[0];
params.put("appId", appIdParam);
if (!APP_ID.equals(appIdParam)) {
return "appId error";
}
String signLocal = SignUtil.getSign(params, APP_SIGN_KEY);
if (signLocal == null || !signLocal.equals(httpServletRequest.getParameterValues("sign")[0])) {
return "sign error";
}
//todo 业务处理...
return "SUCCESS";
}
}
/**
* mock的Request类,实际情况应该使用{@link javax.servlet.http.HttpServletRequest}
*/
class HttpServletRequestMock {
public String[] getParameterValues(String nonce) {
return new String[]{""};
}
}
具体的接口定义如下:
状态通知接口
请求方 | 丁香医生 |
---|---|
服务方 | 合作方 |
请求方式 | POST (Content-Type:application/x-www-form-urlencoded;charset=utf-8) |
用户级鉴权 | 否 |
接口说明 | 问诊状态发生变化时,丁香医生向合作方推送问诊状态变化通知。 合作方收到验签通过的通知后,合作方后应该同步返回成功处理的的结果(如下描述或者"SUCCESS "字符串)。当收不到成功处理的结果,丁香医生会采用重试机制再次推送,最多重试5次,间隔时间分别为5分钟、10分钟、20分钟、30分钟、1小时。为避免发生异常,合作方需保证接收接口的幂等性(可以通过msg_id实现)。 |
请求参数
参数名 | 类型 | 必填 | 示例值 | 说明 |
---|---|---|---|---|
msg_id | Int | 是 | 600232 | 消息id,标识1条消息 |
notice_type | Int | 是 | 1 | 1 问诊退回(一般为医生拒绝) 2 问诊退回(超时未被回复) 3 医生回复了问诊 4 问诊结束 5 投诉审核通过 6 投诉审核不通过 7 问诊被用户主动取消 8 医生补充回答(对追问的回答) 9 医生接诊(快速图文,电话问诊) 10 通话完成(电话问诊) 11 问诊已生效(订单已确认) 12 丁香医生后台发起的退款 |
question_id | Int | 是 | 980000232 | 问题id |
uid | String(30) | 是 | u100821 | 合作方的用户唯一标示 |
返回结果
参数名 | 类型 | 必填 | 示例值 | 说明 |
---|---|---|---|---|
id | Int | 是 | 98000232 | 请求时的问题id |
updated | Int | 是 | 1509419983789 | 处理完成的 Unix 时间戳(单位:毫秒) |
6. 附录
1. 线下对账要素
商户订单ID | 丁香医生订单ID | 状态:1.待结算,2.已退款 | 创建时间 | 支付时间 | 退款时间 |
---|---|---|---|---|---|
String(30) | String(10) | Int | yyyy-MM-dd HH:mm:ss | yyyy-MM-dd HH:mm:ss | yyyy-MM-dd HH:mm:ss |
附模版文件:商户订单模版.xls
2. 错误码定义
错误码 | 含义 |
---|---|
10002 | 请求参数为空 |
10003 | 请求参数不正确 |
10004 | 请求过于频繁,请稍后重试 |
10005 | 系统内部错误 |
10006 | 上传的文件大小超过限制 |
10007 | 上传的文件个数超过限制 |
100002 | 当前用户未登录 |
100707 | 暂无可接诊医生 |
200001 | 医生不存在 |
200003 | 医生被封禁 |
200004 | 医生已停诊 |
200301 | 当前用户不是问题的所有者 |
240001 | 应用不存在 |
240002 | 签名错误 |
240003 | 账户余额不足 |
240004 | 应用账号已停用 |
240006 | 请求路径错误 |
240007 | 用户不存在 |
240201 | 已有退款记录 |
240301 | 投诉记录不存在 |
240302 | 问题已被投诉 |
300001 | 问题不存在 |
300004 | 当前问题不能被追问 |
300005 | 超出最大追问限制 |
300006 | 问题已关闭 |
300014 | 无法查看该问题 |
300108 | 问题创建失败 |
300113 | 问题当前的状态不能被投诉 |
300132 | 对话顺序错误 |
600001 | 订单不存在 |
600003 | 订单状态错误 |
600009 | 订单创建失败 |
600013 | 当前用户不是该订单的所有者 |
600015 | 丢失订单信息 |
600502 | 订单关闭失败 |
600506 | 订单已关闭 |
640001 | 电话问诊状态不正确 |
640004 | 电话问诊信息不存在 |
640005 | 手机号为空 |
640006 | 电话问诊信息缺失 |
640013 | 非电话急诊问诊 |
640014 | 手机号不正确 |
690002 | 医生已接诊 |
690003 | 快速图文问诊状态异常 |
3. 投诉状态流转
7. 常见对接问题(Q&A)
Q:问题详情中的音频、视频等资源文件的有效期是多长时间?
A:有效期为5min,合作方需要自行对资源文件进行本地化操作
Q:如何进行测试?
A:目前丁香医生开放平台可以对接三种问诊类型
- 普通图文问诊
- 向测试医生 小新(doctor_user_id:12196047) 提问即可,可以使用
110004-医生详细信息
接口获取医生信息
- 向测试医生 小新(doctor_user_id:12196047) 提问即可,可以使用
- 快速图文问诊&电话问诊
- 需要双方商务商定好开通该服务,并提供一个已经调用过
100010-获取用户身份凭证
接口的uid添加到测试白名单
- 需要双方商务商定好开通该服务,并提供一个已经调用过
110003-科室下的医生列表
接口中找不到测试医生?
Q:在A:测试环境是沙盒模式,为防止正式用户问到测试医生产生不必要的麻烦,在这个接口中对测试医生进行了屏蔽。其他接口可以正常使用测试医生
Q:如何进行联调?
A:为了节省双方的精力,丁香医生平台针对部分问诊流程测试进行了自动化操作
普通图文问诊&快速图文问诊医生接诊后,适用以下规则 (PS. 1和2仅适用于普通图文问诊) ,
其中 x<=3,y<=9
回复【超时】问题被超时退回
回复【拒绝】医生拒绝当前问题
没有关键字(语音,图片,文字)
医生回复:系统的测试文字
回复【文字】
医生回复:患者的文字
回复【语音x】
医生回复:语音x条,会分x次消息 发送
回复【图片y】
医生回复:y张图片+默认的测试文字
回复【图片y】+【文字】
医生回复:患者的文字+y张图片
回复【语音x】+【文字】
医生回复:第一条:1条语音+患者发送的文字内容;x-1后面的语音都是单独发送
回复【语音x】+【图片y】
医生回复:第一条:1条语音+y张图片;x-1后面的语音都是单独发送
回复【语音x】+【图片y】+【文字】
医生回复:第一条:1条语音+y张图片+患者的文字;x-1后面的语音都是单独发送
电话问诊
- 添加完测试白名单之后,联系丁香医生的测试
Q:如何测试医生的语音回复?
A:针对每个平台,医生的语音回复功能默认是不开启的。若需要测试和使用,请联系丁香医生的技术或者测试开通后进行测试
Q:联调过程中发现问题如何反馈?
A:丁香医生开放平台已经对接了多家合作方,一般情况下不会是平台方的错误,请反馈问题前先根据以下步骤进行自测
- 仔细查看文档对比自己的代码是否存在遗漏的地方
- 检查传递参数的编码格式以及请求方式
- 检查签名的生成是否有误
- 消息推送接口的返回值是否符合丁香医生平台方的规则
如果以上方法检查后依然无法排查出问题, 请携带以下俩种信息的一种进行反馈,以方便快速定位问题
请求接口的详细参数,格式如下
请求方法:POST/GET
请求头:User-Agent: xxxx、ask-platform-sid: xxxxx
请求参数(Json格式):{"user_id": 12196047}
请求接口返回值(Json格式):{"error":{"code":10003,"message":"请求参数不正确"}}
Q:测试医生小新,为什么经常停诊?停诊对用户有什么影响?
A:医生由于手术、忘记关诊等原因发生超时退回后,如果有新的提问,可能还会超时,用户体验不好。所以当月累计多个超时退回的问题后,将会自动停诊,测试医生由于大家经常测试超时退回,所以一有新的超时退回问题,就会停诊。停诊之后,已经提问的问题医生可以继续回复,只是接不到新的问题。小新医生只要测试了「超时未回复」的问题,就会停诊,测过这类问题以后就可以找我们开诊。
Q:如何申请预发环境或者线上环境的APPID?
A:请向丁香医生商务这边申请,需要提供回调url,可以先给预发的回调,上线后再替换成线上的回调。
Q:如何线上环境测试?
A:分为以下两种情况:
线上appId可以问线上和测试医生,测试appId只能问测试医生,线上appid测试的话,会走对账流程,会产生结算费用。如果线上对正式的医生进行提问,不要使用「测试」等语句,对医生造成不必要的困扰。请使用真实用户的问诊场景语句进行提问,且医生正常回复后,不予退款。
测试appId就是线上的数据,小新医生就是线上环境的医生,只是对权限进行了隔离,不能问正式医生。线上appId也可以提问测试医生小新,只不过不能在医生列表里找到小新医生,和测试环境流程一样向小新医生提问,需要手动指定,也可以自动回复,向小新医生提问,也会走结算流程。
Q:医生响应时间出现0秒?
A:因为医生数据都是取的最近30天的数据,部分医生最近30天没有接诊问题,所以数据都是0,用户侧可以显示「暂无」。
Q:快速图文如何自动回复?
小新医生属于儿科,请向儿科进行提问:
【接诊并回复】 小新接诊后立即回复。用户再问 就会走原来自动回复的逻辑
【接诊不回复】 小新接诊后不回复。 用户再问 就会走原来自动回复的逻辑