重要通知

在低调扎实免费的运转了四年之后,咕咚OpenAPI将迎来一次全面更新。此次更新在保留现有数据结构的前提下,对业务代码进行了全面的重构,提升了业务性能,增强了业务健壮性,丰富了输出数据。同时,商务部门也将对合作提出新的诉求。

因此,在经过3个月的内测之后,我们决定在2018年6月1日全面关闭本页面文档中的所有接口,将所有业务迁移至新的OpenAPI服务,新的文档将由商务部门重新沟通后提供。请各合作方做好相应准备,避免对业务造成冲击。

相关业务合作沟通,请联系邮箱:support@codoon.com

本文档用于引导第三方开放者在自己的应用中集成咕咚的帐号和该帐号所产生的数据。开发者通过认证鉴权接口从咕咚网获取咕咚用户的认证令牌,绑定认证令牌后。 即可通过此令牌访问咕咚的数据,并且在注册回调接口后还能在用户上传数据后得到实时的通知。

咕咚开放API的鉴权认证是基于OAuth2.0协议,如果对协议不了解可以参考协议官方网站http://oauth.net/2/

接入API需要申请咕咚网接入的AppKey和AppSecret。因为咕咚暂时没有开放申请,所以如果有接入的需求,请将您应用的简介和公司或者个人信息通过邮件发送到 support@codoon.com
接入测试可以使用测试的AppKey和AppSecret:app_key 3d1602888d5111e29f42782bcb058632, app_secret 3d1606d48d5111e29f42782bcb058632


认证授权

第三方应用通过认证授权接口获取咕咚用户的授权令牌,从而得到通过API读写数据的权限。大体过程如下图

第一步:获取Access Code

URL https://openapi.codoon.com/authorize
访问方式 浏览器Redirect
参数
  • client_id:应用程序标识,就是AppKey
  • redirect_uri:获取返回的AccessCode的转跳地址,必须和注册时提交的地址一致
  • response_type:恒等于code
  • scope:申请接口范围(可选参数)现在只开放user和sports,多个权限用逗号隔开
示例如下:

    
    https://openapi.codoon.com/authorize?client_id=xxx&redirect_uri=http%3A%2F%2Fapi.yourdomain.com%2Fget_code&response_type=code&scope=user,sports
    

将参数urlencode后放在url的参数部分,然后转跳到这个地址上。如果用户在咕咚网已经登录,就会显示授权页面,点击确认后会转跳到参数redirect_uri所指定的地址 AccessCode通过参数code返回,示例如下:

    
    http://api.yourdomain.com/get_code?code=xxxxxxxxxxxxxxxxxxxx
    

AccessCode是一个很重要的返回值,你需要将其存储起来供下一次调用使用。

第二步:获取Access Token(授权令牌)

在获取到AccessCode之后,就可以通过这个code获取授权令牌(Access Token)了。获取Access Token需要用之前获取的Access Code作为参数发起一次Http请求, 由于客户端发起容易被截获,建议在服务端发起这个请求。

URL https://openapi.codoon.com/token
访问方式 POST
HTTP HEADER Key:Authorization  Value:"Basic "+base64("AppKey:AppSecret")
参数
  • client_id:应用程序标识,就是AppKey
  • grant_type:恒为authorization_code
  • redirect_uri:获取返回的AccessCode的转跳地址,必须和注册时提交的地址一致
  • code:在上一步获取的Access Code
  • scope:申请接口范围(可选参数)现在只开放user和sports,多个权限用逗号隔开

下面是一个Python的例子

    
    >>>import requests
>>>import base64
>>>client_key = "xxxxx" >>>client_secret = "xxxxx" >>>params = dict(
client_id="xxxxx", grant_type="authorization_code", code="xxxxxxxxxxxxxxxxxxxxxx", redirect_uri="http://api.yourdomain.com/get_code", scope="user,sports",
) >>>headers = {'Authorization': 'Basic %s' % base64.b64encode(client_key + ":" + client_secret)} >>>response = requests.post("https://openapi.codoon.com/token",data=params, headers=headers) >>>print response.text {"access_token": {access_token}, "token_type": "bearer", "expire_in": 3600, "refresh_token": {refresh_token}, "scope": {scope}}

返回json对象的格式:

access_token 授权令牌,用于访问API接口的时候使用
token_type 恒为Bearer
expire_in 距过期还剩多少秒
refresh_token 重新获取AccessToken的刷新授权码
scope 授权允许访问的接口范围

Access Token(授权令牌)过期获取新令牌的过程

在获取授权令牌的时候,API授权接口会返回一个Refresh Token(刷新令牌)的值,这个值需要存起来,当授权令牌过期后,可以通过这个值去获取一个新的授权令牌, 从而不必再重复第一步从获取Access Code开始。执行这个过程的方式和第二步类似,地址相同,只是参数有所区别。

URL https://openapi.codoon.com/token
访问方式 POST
HTTP HEADER Key:Authorization  Value:"Basic "+base64("AppKey:AppSecret")
参数
  • client_id:应用程序标识,就是AppKey
  • grant_type:恒为refresh_token
  • refresh_token:在上一次获取授权令牌的时候获取的refresh_token
  • scope:申请接口范围(可选参数)现在只开放user和sports,多个权限用逗号隔开

下面是一个Python的例子

    
    >>>import requests
>>>import base64

>>>client_key = "xxxxx"
>>>client_secret = "xxxxx"
>>>params = dict(
client_id="xxxxx",
grant_type="恒为refresh_token",
refresh_token="xxxxxxxxxxxxxxxxxxxxxx",
scope="user,sports",
)
>>>headers = {'Authorization': 'Basic %s' % base64.b64encode(client_key + ":" + client_secret)}
>>>response = requests.post("https://openapi.codoon.com/token",data=params, headers=headers)
>>>print response.text {"access_token": {access_token}, "token_type": "bearer", "expire_in": 3600, "refresh_token": {refresh_token}, "scope": {scope}}

返回值格式同第二步

访问API

在获取到用户的授权令牌后,第三方应用就可以使用这个令牌来访问用户的数据了,咕咚开放API暂时只支持Bearer这一种方式, 只需要将Access Token放到Http Header的Authorization键中即可

URL https://openapi.codoon.com/api/method_name
访问方式 POST/GET
认证参数 Http Header: Authorization:Bearer {Access Token}
API参数 接口所需参数均为命名参数,需要将参数组合成一个json对象,放在body里

下面是一个Python的示例

    
    >>>import requests
>>>headers = {"Authorization": "Bearer %s" % accesstoken} >>>post_data = {...} >>>response = requests.request('POST', "https://openapi.codoon.com/api/api_func", data=json.dumps(post_data), headers=headers) >>>print response.content {rs:True,...}

返回值是一个json对象,根据不同的接口,返回值有所区别,将在API部分详细说明

API详细说明

API可以通过Http协议的GET和POST方法访问,如果没有注明用GET,否则建议使用POST方法

1.获取用户信息

Method Name verify_credentials
访问方法 GET
API参数(Body) {}

返回值说明

    
    {
        "id": "String",                                     // ID
        "domain": "String",                                 // 域
        "certificatename": "String",                        // 暂时没有使用的属性
        "get_icon_large": "String",                         // 头像(大)
        "get_icon_middle": "String",                        // 头像(中)
        "get_icon_small": "String",                         // 头像(小)
        "get_icon_tiny": "String",                          // 头像(超小)
        "get_icon_xlarge": "String",                        // 头像(超大)
        "mobile_portraits_l": ["String"...]                 // 手机头像,220x220
        "mobile_portraits_x": ["String"...]                 // 手机头像,640x640
        "nick": "String",                                   // 姓名
        "followings": Int,                                  // 关注数
        "followers": Int,                                   // 粉丝数
        "location": "String",                               // 地址
        "weight": Int,                                      // 体重
        "height": Int,                                      // 身高
        "realname": "String",                               // 真实姓名
        "birthday": {"y": Int, "m": Int, "d": Int},         // 生日
        "address": "String",                                // 地址
        "gender": Int,                                      // 性别 0: 女, 1: 男
        "hobby":"String"                                    // 爱好
        "descroption": "String",                            // 运动宣言
        "routes_count": Int,                                // 上传过的路线条数
        "week_goal_type": "String",                         // 周目标类型
        "week_goal_value": Int                              // 周目标的值
    }
    

2.修改用户属性

Method Name update_profile
访问方法 POST
API参数(Body)
                    
{
    "height": Int,           // 身高
    "weight": Int,           // 体重
    "gender": Int,           // 性别 0: 女, 1: 男
    "nick": "String",        // 姓名
    "hobby": "String",       // 爱好
    "img_data": "String",    // base64编码后的头像文件
    "img_name": "String",    // 头像文件名,主要是需要用到后缀来区别图片格式
    "descroption": "String", // 运动宣言(注意此处有拼写问题,因为一个美丽的错误)
}
                    
                

返回值说明

    
    {
        "status": "OK",             // 处理结果,恒为ok
        "data": {
            "portrait_l": "String", // 220的头像URL
            "portrait_x": "String", // 640的头像URL
        },
        "description": "String"     //
        'error_code': code,//1: u'昵称重复', 2: u'更新成功', 3: u'设置一个合理的步长吧', 4: u'文件类型不支持', 5: u"昵称只能是2~12位中文、字母、数字、下划线或减号!", 6: u'昵称不能含有敏感词!', 7:u'签名不能含有敏感词!',
               8: u'信息审核中,不可编辑'
        'vipicon_l': '', 
        'vipicon_m': '', 
        'vipicon_s': '', 
        'viplabel_desc': ''
    }
    

3.获取运动目标

Method Name get_tracker_goal
访问方法 POST
API参数(Body) {}

返回值说明

    
{
    "status": "OK",        // 执行状态
    "descroption": "",     // 状态描述,status不为OK的时候是错误信息描述
    "data": {
        "type":"steps",    // 运动目标类型,可选值范围steps, meters, calories
        "value": Int       // 每日运动目标的值
    },
}
    

4.设置运动目标

Method Name change_tracker_goal
访问方法 POST
API参数(Body)
  
{
    "goal_type": "String" //运动目标类型,可选值范围steps, meters, calories
    "goal_value": Int     //实际数值
}
  

返回值说明

    
{
    "status": "OK",        // 执行状态
    "descroption": "",     // 状态描述,status不为OK的时候是错误信息描述
}
    

5.获取身体数据(体重历史)

Method Name get_body_log
访问方法 POST
API参数(Body) {}

返回值说明

    
{
    "status": "OK",
    "data": [
         [                 // 节约传输数据,使用数组存储,需要按位置获取数据。如果无此数据则为null
             "2012-3-07",  // 对应身体数据的日期
             "number",     // 体重,公斤
             "number",     // 身高,厘米
             "number",     // 体脂率,百分比,最大100
             "number",     // 目标体重
         ]
    ]
}
    

6.更新身体管理数据(修改体重和体重目标)

Method Name post_body_data
访问方法 POST
API参数(Body)
    
{
    "data": [                        // 可一次性上传多条
        {
            "weight": "number",      // 体重,公斤
            "height": "number",      // 身高,厘米
            "weight_goal": "number", // 目标体重
            "fatrate": "number",     // 体脂率,百分比,最大100
            "date": "2012-3-07",     // 对应身体数据的日期
            "update_time": "2012-10-31 17:00:30",
                                     // 设置此数据的时刻,新的数据会把旧的覆盖掉
        }
    ],
}
    

返回值说明

    
{
    "status": "OK",
}
    

7.获取追踪器按天汇总数据

Method Name get_tracker_summary
访问方法 POST
API参数(Body)
    
{
    "date_end": "2012-3-07",  // 获取时间段的最后一天
    "days_back": Int,    // 需要获取的天数,最大30天
}
    

返回值说明

    
{
    "status": "OK",
    "data": [  // 多条
        {
            "status": "null",  // 运动状态 null不动 low轻微 proper适量 over过于
            "calories": 0,     // 消耗卡路里
            "meters": 0,       // 运动距离
            "activity": 0,     // 运动量 (卡路里/体重)
            "steps": 0,        // 步数
            "minutes": 0       // 运动时常
        }
    ],
    "description": ""
}
    

8.获取追踪器单日数据(20分钟一段)

Method Name get_tracker_data
访问方法 POST
API参数(Body)
    
{
    "the_day": "String", 例 2012-03-02
}
    

返回值说明

    
{
    "status": true,               //返回状态
    "data": {
        "meters": [1,2,3, ...],   //每二十分钟的运动距离
        "sports_duration": 120,   //运动持续时间
        "steps": [1,2,3, ...],    //每二十分钟运动的步数
        "calories": [1,2,3, ...], //每二十分钟消耗的卡路里数
        "sports_complete": Int    //运动完成度
    }
}
    

8a.获取追踪器单日数据(10分钟一段)

Method Name api_tracker_oneday
访问方法 POST
API参数(Body)
    
{
    "the_day": "String", 例 2012-03-02
}
    

返回值说明

    
{
    "status": true,               //返回状态
    "data": {
        "meters": [1,2,3, ...],   //每十分钟的运动距离
        "sports_duration": 120,   //运动持续时间
        "steps": [1,2,3, ...],    //每十分钟运动的步数
        "calories": [1,2,3, ...], //每十分钟消耗的卡路里数
        "sports_complete": Int    //运动完成度
    }
}
    

9.获取追踪器睡眠信息(20分钟一段)

Method Name get_sleep_data
访问方法 POST
API参数(Body)
    
{
    "the_day": "String", 例 2012-03-02
}
    

返回值说明

    
{
    "status":"OK",              //返回状态
    "data":{
        "deep_minutes":60,      //深睡时间
        "sleep_complete":0.75,  //睡眠完成度
        "total_minutes": 80,    //总睡眠时间
        "light_minutes": 20,    //浅睡时间
        "detail": [-1, -1, ...] //每二十分钟睡眠详细情况
    },
    "description":""
}
    

9a.获取追踪器睡眠信息(200秒一段)

Method Name get_sleep_data_oneday
访问方法 POST
API参数(Body)
    
{
    "the_day": "String", 例 2012-03-02
}
    

返回值说明

    
{
    "status":"OK",              //返回状态
    "data":{
        "deep_minutes":60,      //深睡时间
        "sleep_complete":0.75,  //睡眠完成度
        "total_minutes": 80,    //总睡眠时间
        "light_minutes": 20,    //浅睡时间
        "detail": [-1, -1, ...] //每200秒睡眠详细情况     -1表示没有数据 , 深睡 3.3*3 以下 , 浅睡 3.3-16.6, 唤醒 16.6 以上 
    },
    "description":""
}
    


10.获取追踪器总完成度

获取追踪器睡眠信息
Method Name get_sport_complete_rate
访问方法 POST
API参数(Body)
    
{
    "the_day": "String", 例 2012-03-02
}
    

返回值说明

    
{
    "status":"OK",           //返回结果
    "data":{
        "sports_complete":0, //运动目标完成率
        "sleep_complete":50  //睡眠目标完成率
    },
    "description":""
}
    

11.获取上传线路数据

Method Name get_route_by_id
访问方法 POST
API参数(Body)
    
{
    "route_id": "String",// 这个值通过通知接口获取
}
    

返回值说明

    
{
    "status": "OK",               // OK表示请求成功
    "data": {
        "total_time": Int,        // 运动持续时间,单位分钟
        "upload_time": String,    // 上传的时间,比如 "2013-09-21 18:02:58"
        "total_calories": Float,  // 消耗卡路里
        "start_time": String,     // 运动开始时间,比如 "2013-09-23 17:40:14"
        "sports_type": String,    // 运动方式 比如 走路、跑步、骑行
        "route_image": String,    // 线路图片地址
        "activity_result": Int,   // 是否达成目标 0 未完成, 1 完成
        "end_time": String,       // 完成运动时间,比如"2013-09-24 17:41:07"
        "total_length": Float,    // 运动距离
        "activity_type": String,  // 运动类型 比如:普通模式、目标模式、挑战模式、计划模式
        "goal_type": String,      // 运动目标类型 比如:距离、时间、卡路里
        "goal_value": Float       // 运动目标值
    },
    "description": ""
}
    

返回错误码

区分错误和正确的请求通过Http的状态码就ok了,如果API请求返回200,一般意义上认为是请求成功了的,但是有的业务是异步的,所以最好通过status字段再判断一次。

错误名称 错误码 HTTP状态 描述
invalid_request 1001 400 在HTTP的Header里没有找到认证信息
invalid_token 1002 401 当Token失效的时候返回这个错误
insufficient_scope 1003 403 当请求的scope不在允许的范围内时返回此错误
invalid_request 2001 N/A 参数缺失,参数错误,访问方法错误的时候返回此错误
unauthorized_client 2003 N/A client_ID不是有效的client_ID
access_denied 2004 N/A 授权发生异常时返回此错误
unsupported_responseType 2005 N/A 发起请求的Method不支持的时候返回此错误

通知接口

开发者在注册APP的时候,需要提供一个回调地址,当用户上传数据的时候,API会即时调用这个地址,将消息通知给开发者的系统。请在5秒内处理完成回调通知的逻辑,开发者系统如果发生超时或者系统错误的时候,API不会重发此通知

返回方式说明

协议 HTTP
方法 POST
参数
user_id
上传数据的用户ID
catalog
上传数据类型activities是智能配件类设备上传数据,gps_sports是gps运动类app上传数据
resource_id
关联资源的ID,根据catalog不同有所区别,activities类型是设备编号,gps_sports是route_id
start_time
运动开始时间(仅限追踪器类运动,非追踪器类为空)
end_time
运动结束时间(仅限追踪器类运动,非追踪器类为空)
返回 不判断内容,只判断返回的状态码,200即认为成功,其余状态均认为失败