-
-
Notifications
You must be signed in to change notification settings - Fork 16
Home
To get rid of the dirty DOM-Parsing in the current version of "php-runtastic" i started tinkering around the API calls send from the Runtastic Pro iOS App.
Here are some details for anyone interested.
To receive data from the apps' backend, you have to login first. It can be done by sending a uncompressed JSON string via POST request.
URI: https://appws.runtastic.com/webapps/services/auth/login
Type: POST
Content-Type: JSON
{ "additionalAttributes": [ "accessToken" ], "email": "[email protected]", "password": "thepassword" }
The mandatory Request-Header Attributes are:
(Note: Content-Length and X-Date have to be generated at runtime)
(Note 2: X-Auth-Token depends on X-Date - so it also have to be generated)
Host: appws.runtastic.com
X-App-Key: at.runtastic.runtastic.pro
Content-Length: 56
X-Auth-Token: 5b3e1c74b148d0229f4b2fb299eb952966f93c24
X-Date: 2014.12.12 20:25:20
Connection: keep-alive
X-App-Feature-Set: pro
Accept: /
Content-Type: application/json
Accept-Encoding: deflate
The response is a uncompressed JSON string:
{
"userId": "13374711",
"accessToken": "238af7a6fsdg998sdg7s6asfas77f9sd4as4da433as56f7sdg77s7f65a7s7dsa",
"uidt": "89a9sdaaa9a6f67dg7s9sg987asd8hj9rq8a6s6c"
}
User-ID and Access-Token are needed to proceed with further calls to the backend.
After getting User-ID and Access-Token, its possible to receive all the user info for the logged-in user via a simple GET request.
URI: https://appws.runtastic.com/webapps/services/users/13374711?access_token= 238af7a6fsdg998sdg7s6asfas77f9sd4as4da433as56f7sdg77s7f65a7s7dsa
Type: GET
The header attributes from the login are still valid while doing the GET request. As far as i noticed, changes in the header don't affect the connection as long as its the same session and the cookies are still stored.
The response is a gzip-compressed JSON string.
{
"firstName": "Donald",
"lastName": "Duck",
"height": "1.86",
"weight": "84.0",
"gender": "M",
"birthday": "567043200000",
"countryCode": "DE",
"locale": "en",
"unit": "0",
"avatarUrl": "http://avatars0.runtastic.com/files/5234284/big.avatar_upload_ 13374711.JPG?updatedAt=1402413757000",
"weightUnit": "0",
"temperatureUnit": "0",
"liquidUnit": "0",
"agbAccepted": "true",
"localytics": "Gold-Paid.>12M",
"membershipStatus": "gold.paid",
"createdAt": "1305832375000",
"subscriptions": [
{
"id": "15698267",
"updatedAt": "1417224709000",
"status": "paid",
"planName": "gold",
"validFrom": "1417377307000",
"validTo": "1448913307000",
"paidContractSince": "1385841307000",
"active": "true",
"paymentProvider": "adyen",
"paymentProviderText": "Runtastic.com"
}
],
"email": "[email protected]",
"isEmailConfirmed": "true"
},
"userSettings": {
"myFitnessPalConnected": "true"
},
"dataChanged": "true"
}
To receive session data, you have to perform a POST request containing the number of sessions per page (Attribute: "perPage") and the last sync date (Attribute: "syncedUntil). Since we are using the app backend, we can use the sync mechanisms in place to load all the sessions onto the device for offline use. That means if we want to receive all the sessions available, we set the number of sessions per page to a high number (e.g 2000) and the "syncedUntil" attribute to a timestamp years ago (e.g 946684800 (Unix time for 01.01.2010 00:00:00). To perform the request, the access-token received at login time has to be attached to the URL.
URI: https://appws.runtastic.com/webapps/services/runsessions/v3/sync?access_token= 238af7a6fsdg998sdg7s6asfas77f9sd4as4da433as56f7sdg77s7f65a7s7dsa
Type: POST
Content-Type: JSON
{ "perPage": "2000", "syncedUntil": "946684800" }
The mandatory Request-Header Attributes are:
(Note: Content-Length and X-Date have to be generated at runtime)
Host: appws.runtastic.com
X-App-Key: at.runtastic.runtastic.pro
Content-Length: 56
X-Auth-Token: 5b3e1c74b148d0229f4b2fb299eb952966f93c24
X-Date: 2014.12.12 20:25:20
Connection: keep-alive
X-App-Feature-Set: pro
Accept: /
Content-Type: application/json
Accept-Encoding: deflate
The response is a gzip-compressed JSON string. In the example above, only two sessions are visible.
{
"syncedUntil": "1418418819229",
"perPage": "2000",
"sessions": [
{
"id": "9273971",
"sportTypeId": "15",
"distance": "9500",
"duration": "900000",
"startTime": "1330490983000",
"endTime": "1330491883000",
"calories": "566",
"elevationGain": "0",
"elevationLoss": "0",
"manual": "true",
"sportDeviceId": "3807",
"edited": "false",
"updatedAt": "1330492278000",
"pause": "0",
"speedData": {
"avg": "38.0",
"max": "0.0"
},
"additionalInfoData": {
"weatherId": "2",
"feelingId": "1"
},
"indoor": "false",
"gpsTraceAvailable": "false",
"heartRateAvailable": "false",
"cadenceTraceAvailable": "false",
"stepTraceAvailable": "false",
"altitudeTraceAvailable": "false",
"speedTraceAvailable": "false"
},
{
"id": "148005739",
"sportTypeId": "19",
"distance": "12359",
"duration": "8249984",
"startTime": "1385832681000",
"endTime": "1385840931000",
"calories": "756",
"elevationGain": "28",
"elevationLoss": "28",
"manual": "false",
"sportDeviceId": "56752",
"edited": "false",
"updatedAt": "1385841082000",
"pause": "16",
"gpsData": {
"longitude": "10.5037365",
"latitude": "52.272583"
},
"speedData": {
"avg": "5.393",
"max": "12.024"
},
"additionalInfoData": {
"weatherId": "2",
"feelingId": "1",
"surfaceId": "2",
"temperature": "5.0"
},
"gradientData": {
"zones": [
{
"name": "zone1",
"distance": "200",
"duration": "196358",
"min": "-2.0",
"max": "-90.0"
},
{
"name": "zone2",
"distance": "11700",
"duration": "7756052",
"min": "-2.0",
"max": "2.0"
},
{
"name": "zone3",
"distance": "400",
"duration": "256943",
"min": "2.0",
"max": "90.0"
}
],
"avgUp": "2.906666",
"avgDown": "3.644768",
"maxUp": "3.337932",
"maxDown": "3.734207"
},
"liveTrackingEnabled": "false",
"indoor": "false",
"extData": {
"gradientData": {
"avgUp": "2.906666",
"avgDown": "3.644768",
"maxUp": "3.337932",
"maxDown": "3.734207"
}
},
"gpsTraceAvailable": "true",
"heartRateAvailable": "false",
"cadenceTraceAvailable": "false",
"stepTraceAvailable": "false",
"altitudeTraceAvailable": "false",
"speedTraceAvailable": "false",
"encodedTrace": "sn~Hiob_ABCkAvGl@xObI
GdJBxKoAjKl@tKjApKqBnK}GpKt@DsKfGqJ~E}K|Dk@rMOhTFdQYbSjAhRpBjUhCvTbC|RvAtRpClPu@lD",Mz@tJmIhIgUpHwLrJrC
KP`@eOl@oSoBkQcHkN}G{JF}S_AkSwFqKg@qOuAaQcAqP{DeMmGqImK_CsK_ByJqCyJwIwJp@kKtFcK|FoJ
"records": {
"achievements": {
"fastestKm": "553900",
"fastestMi": "952068",
"fastest3Mi": "3080990",
"fastest5k": "3219988",
"fastest10k": "6475988"
},
"positions": {
"fastestKm": "1385840132000",
"fastestMi": "1385833942000",
"fastest3Mi": "1385832901000",
"fastest5k": "1385833369000",
"fastest10k": "1385833369000"
}
}
}
]
}