NAV
javascript shell

Ayvri V2 REST API

The Ayvri API let’s you create new Ayvri activities and scenes to use in your application.
It is a REST based API with predictable, resource-oriented URLs, and uses HTTP response codes to indicate API errors. We use built-in HTTP features, like HTTP authentication and HTTP verbs, which are understood by off-the-shelf HTTP clients. JSON is returned by all API responses, including errors.

We offer two methods for integrating with the Ayvri API. The Connect style of integration uses the Authorization Code Flow from OAuth2 to allow a user to authorize you to act on their behalf to upload activities and scenes. There are some limitations to what can be done using the Connect integration method. The Commercial integration style gives you access to all api features.

Connect Authentication

Ayvri Connect lets your app act on behalf of Ayvri users. Ayvri attempts to follow the OAuth2 Authorization Code Flow as closely as possible.

Before you start you will need to:

Get an Authorization Code for a User

For Ayvri to issue you an Authorization Code, you must send an Ayvri user to Ayvri’s authorization endpoint.

The Ayvri authorization endpoint is https://ayvri.com/authorize

The authorization endpoint will be expecting the following query parameters:

An example authorization request might look like https://ayvri.com/authorize?client_id=myclient134&redirect_uri=https://my-cool-app.com/oauth2_callback&response_type=code&state=req123

Ayvri will validate the supplied redirect_uri against the supplied client_id and present the user the option to grant your app authorization.

Success

When a user authorizes your app, Ayvri will redirect the user to the redirect_uri supplied with the authorization request. Ayvri will supply the following query parameter with the response:

An example successful response might look like https://my-cool-app.com/oauth2_callback?code=894759329&state=req123.

Failure

If Ayvri deems it safe to do so, the user may return to you with an error response. Ayvri will provide the following query parameters with the error response:

If the redirect_uri could not be validated, no error will be reported to you.

Exchange the Authorization Code for Access and Refresh Tokens

Exchange Authorization Code for Access and Refresh Tokens

var request = require('request');
var base64_credentials = new Buffer(CLIENT_ID + ":" + PASSWORD).toString('base64')
request.post({
url: 'https://api.ayvri.com/2.0/token',
headers: { Authorization: 'Basic ' + base64_credentials },
body: encodeUri('grant_type=authorization_code&code={$code}'),
function(err, res, body) {
grant = JSON.parse(body);
console.log(grant);
}
);
curl -X POST https://api.ayvri.com/2.0/token \
-u $CLIENT_ID:$PASSWORD \
-d 'grant_type=authorization_code&code={$code}'
Example Response
{
access_token: '80a0jacec98f0ace0acacca.098f89cjca09ec0aca0j.0accejcs',
refresh_token: '08aecjaca0aec0jacejiecjac.09ec8acjce0a0ecjaaciajc.0acjc0',
token_type: 'bearer',
expires_in: 604800,
}

An authorization_code must be exchanged for access and refresh tokens by issuing an authenticated request to the token endpoint. Ayvri’s token endpoint is https://api.ayvri.com/2.0/token. Ayvri will authenticate the request using HTTP Basic access authentication and expects a URI encoded body with the grant_type and code parameters set.

Once an access token has been recovered it may be used as a normal bearer token with other endpoints on the API. The access token gives you authorization to upload activities and scenes on behalf of the user that authorized you to do so. Scenes uploaded will be added to their profile and may be removed by them without your knowledge. The tokens issued through the Connect integration style have the following limitations:

Commercial Authentication

Getting an API access token

var request = require('request');
var base64_credentials = new Buffer(CLIENT_ID + ':' + PASSWORD).toString('base64');
request.post(
{
url: 'https://api.ayvri.com/2.0/auth',
headers: { Authorization: 'Basic ' + base64_credentials },
form: { grant_type: 'client_credentials' },
},
function(err, res, body) {
grant = JSON.parse(body);
console.log(grant);
},
);
curl -X POST https://api.ayvri.com/2.0/auth \
-u $CLIENT_ID:$PASSWORD \
-d 'grant_type=client_credentials'
Example Response
{
access_token: '80a0jacec98f0ace0acacca.098f89cjca09ec0aca0j.0accejcs'
refresh_token: '08aecjaca0aec0jacejiecjac.09ec8acjce0a0ecjaaciajc.0acjc0'
token_type: 'bearer',
expires_in: 604800,
}

Getting a new access token using a refresh token

var request = require('request');
var base64_credentials = new Buffer(CLIENT_ID + ':' + PASSWORD).toString('base64');
request.post(
{
url: 'https://api.ayvri.com/2.0/auth',
headers: { Authorization: 'Basic ' + base64_credentials },
form: { grant_type: 'refresh_token', refresh_token: grant.refresh_token },
},
function(err, res, body) {
grant = JSON.parse(body);
console.log(grant);
},
);
curl -X POST https://api.ayvri.com/2.0/auth \
-u $CLIENT_ID:$PASSWORD \
-d "grant_type=refresh_token&refresh_token=$REFRESH_TOKEN"

Ayvri v2 api uses JWT authentication. In order to get a valid auth token, you will need to pass your api account details to the authentication endpoint. This will return a grant which includes an access_token and a refresh_token. Tokens expire after 1 week. When your token expires,you can retrieve a new access_token by passing the refresh_token from your original grant to the

The auth endpoint will return a json object which contains the access_token and refresh_token.

Getting Started : 101

With an access token, create a simple activity & scene

var request = require('request');
request.post(
{
url: 'https://api.ayvri.com/2.0/activity',
headers: { Authorization: YOUR_ACCESS_TOKEN },
body: JSON.stringify({ activityType: ADD_ACTIVITY_TYPE }),
},
function(err, res, body) {
var resBody = JSON.parse(body);
var uploadUrl = resBody.uploadUrl;
var activityId = resBody.activityId;
request.post(
{
url: uploadUrl,
body: YOUR_GPX_OR_IGC_DATA,
},
function(err, res, body) {
request.post(
{
url: 'https://api.ayvri.com/2.0/scene',
headers: { Authorization: YOUR_ACCESS_TOKEN },
body: JSON.stringify({ activities: [activityId] }),
},
function(err, res, body) {
console.log(JSON.parse(body));
var embedUrl = JSON.parse(body).embedUrl;
},
);
},
);
},
);

Once you have an authentication token, you can get started uploading activities and creating scenes.
Creating a scene is a 3 step process

The example here shows how to create a simple scene using the javascript request library, and is used as a simple example to get you started.
Once you can create an activity and a scene, see below for more details and capabilities to customize your scene.

Create Activity

Creating a new activity

var request = require('request');

var activityDetails = {
activityId: 'UTMB_2017',
title: 'UTMB 2017',
activityType: 'Run',
avatar: {
name: 'Brook Martin',
},
color: 'rgb(40,15,110)',
};

request.post(
{
url: 'https://api.ayvri.com/2.0/activity',
headers: { Authorization: grant.access_token },
body: JSON.stringify(activityDetails),
},
function(err, res, body) {
var uploadUrl = JSON.parse(body).uploadUrl;
console.log(body);
},
);
curl -X POST https://api.ayvri.com/2.0/activity \
-H "Authorization: accesss_token" \
-H "Accept: application\json"
-d "{\"activityType\": \"Run\"}"
Example Response

Creating an activity will save the activity details to your api account and return an upload URL to use to push a GPS or IGC file up to the server to be processed.

Activity has the following attributes

Upload Activity

Upload a gps or igc file

var require('fs');
fs.readFile(file, function(err, data) {
request.put({
url: uploadUrl,
body: data
},(err, res, body) => {
//should return a 200 response
});
})
curl -X PUT -T file uploadUrl \

Use the upload url in the response of the created activity to push the activity gps to ayvri. The upload url is valid for 3 minutes.

When the url is uploaded, ayvri will process the tracks to prepare them to be displayed in the viewer. This processing takes only a few seconds.

When a file has been uploaded, ayvri will process the track to get it ready to be displayed in a Scene.

Create Scene

Create a Scene containing activities

var request = require('request');
var sceneDetails = {
title: 'choose a unique title',
activities: [{activityId: activityId_1}, {activityId: activityId_2}...]
}
request.post({
url: 'https://api.ayvri.com/2.0/scene',
headers: { Authorization: access_token },
body: JSON.stringify(sceneDetails)
},
function(err, res, body) {
var embedUrl = JSON.parse(body).embedUrl
});
curl -X POST https://api.ayvri.com/2.0/scene \
-H "Authorization: access_token"
-d '{"activities":[{activityId: activityId_1}, {activityId: activityId_2}...]}'

When the activities have been uploaded and processed, create a Scene to display the activity or activities.

A Scene has the following root attributes, see below for child object details

Activities

A Scene’s activities array is a subset of the activity details

Custom Loading Screen

var request = require('request');
var sceneDetails = {
title: 'choose a unique title',
activities: [...],
loading: {
background: "https://url.to/background-image",
startImg: "https://url.to/image-to-replace-play-button"
}
}
request.post({
url: 'https://api.ayvri.com/2.0/scene',
headers: { Authorization: access_token },
body: JSON.stringify(sceneDetails)
},
function(err, res, body) {
var embedUrl = JSON.parse(body).embedUrl
});
curl -X POST https://api.ayvri.com/2.0/scene \
-H "Authorization: access_token"
-d '{"activities":[...], "loading":{"background":"https://url.to/background-image"}}'

You can set a custom loading screen on your Scene. ayvri does not provide a background image for your loading screen (yet). The loading screen will not be used if the Scene is set to autoplay.

Sharing Image

Set an image to be used by social networks when your Scene is shared.

Default Speed & Distance

For fine control over player speed and the follow distance of an activity, use the Segments, however you can set a simple default which will override the built in defaults

Autoplay

The Scene can be set to autoplay when loaded, so the loading page which not be seen.

Stats

var request = require('request');
var sceneDetails = {
title: 'choose a unique title',
activities: [...],
stats: ["speed","altitude","gradient","localTime"],
defaultStatsVisible: 3
}
request.post({
url: 'https://api.ayvri.com/2.0/scene',
headers: { Authorization: access_token },
body: JSON.stringify(sceneDetails)
},
function(err, res, body) {
var embedUrl = JSON.parse(body).embedUrl
});
curl -X POST https://api.ayvri.com/2.0/scene \
-H "Authorization: access_token"
-d '{"activities":[...], "stats": ["speed","altitude","gradient","localTime"], "defaultStatsVisible": 3 }'

The Scene can display stats specific to the target activity such as speed, altitude, local time and more.
valid stats are
"speed","airSpeed","boatSpeed","distance","altitude","gradient","climbrate","glideRatio","elevation","altitude","altitudeFromStart","localTime","gmtTime"

By default only the first stat in the array is displayed and other stats can be viewed by the user by click a tab which opens the other stats to view.

The number of stats visible by default can be set with defaultStatsVisible

Media

Photos and other types of media can be added into the scene by defining them in the Scene’s media array.

Media items have the following common properties:

Photo

var request = require('request');
var sceneDetails = {
title: 'choose a unique title',
activities: [{ activityId: activityId_1 }],
media: [
{
mediaType: 'photo',
source: 'https://url.to/image-file',
target: {
activityId: 'activityId_1',
time: '2017-06-02T12:11:00Z',
},
},
],
};
request.post(
{
url: 'https://api.ayvri.com/2.0/scene',
headers: { Authorization: access_token },
body: JSON.stringify(sceneDetails),
},
function(err, res, body) {
var embedUrl = JSON.parse(body).embedUrl;
},
);
curl -X POST https://api.ayvri.com/2.0/scene \
-H "Authorization: access_token"
-d '{"activities":[{ "activityId": "activityId_1" }], "media": [{"mediaType": "photo", "source": "https://url.to/image-file", "target": { "activityId": "activityId_1", "time": "2017-06-02T12:11:00Z"} }] }'

A photo that will be displayed at a point along a specific activity. When the scene reaches the specified time, the camera will focus on the photo for several seconds. The target activity must be in this scene, and the target time must be between the start and end time of the target activity.

Photo

In addition to the common media properties listed above, Photo also has the following properties:

Segments

var request = require('request');
var sceneDetails = {
title: 'choose a unique title',
activities: [...],
segments: [
{
time: "2017-11-03T12:11:00Z",
target: "activity",
targetId: "uniqueTargetId",
speed: 300,
targetDistance: 2000
},
{
time: "2017-11-03T12:18:00Z",
target: "activity",
targetId: "uniqueTargetId",
speed: 100,
targetDistance: 1200
}
]
}
request.post({
url: 'https://api.ayvri.com/2.0/scene',
headers: { Authorization: access_token },
body: JSON.stringify(sceneDetails)
},
function(err, res, body) {
var embedUrl = JSON.parse(body).embedUrl
});
curl -X POST https://api.ayvri.com/2.0/scene \
-H "Authorization: access_token"
-d '{"activities":[...], "segments": [{"time":"2017-11-03T12:11:00Z", "target": "activity":, "targetId":"uniqueTargetId", "speed": 300, "targetDistance": 2000}, {"time":"2017-11-03T12:18:00Z", "target": "activity":, "targetId":"uniqueTargetId", "speed": 100, "targetDistance": 1200}] }'

Segments define the activity of the camera in the scene including which activity is followed, how closely the camera follows the activity, and how quickly time passes.

There are multiple uses for segments, for instance if there is a less interesting portion of a track, a larger followDistance and higher speed automatically gives the user a quick view of this area. Over a more interesting portion of the track, a closer followDistance and slower speed will bring a larger focus on that segment.

Additionally, for scenes with multiple tracks or activities, like a triathlon, adventure race or other multi-track scenes, a segment lets the scene creator define when to switch from viewing one activity to move to view another. For instance, viewing the swim portion of a triathlon, and then at a specified time, switching to follow the bike portion.

If setting segments, it is required that the first segment be defined at the beginning of the scene. If no segments are defined, the player will use follow the first activity at the pre-defined default speed and target distance.

Exit Screen

var request = require('request');
var sceneDetails = {
title: 'choose a unique title',
activities: [...],
exitScreen: [
{
"image": "https://url.to/image",
"link": "https://url.to/your-page"
}
]
}
request.post({
url: 'https://api.ayvri.com/2.0/scene',
headers: { Authorization: access_token },
body: JSON.stringify(sceneDetails)
},
function(err, res, body) {
var embedUrl = JSON.parse(body).embedUrl
});
curl -X POST https://api.ayvri.com/2.0/scene \
-H "Authorization: access_token"
-d '{"activities":[...], "exitScreen":[{"image": "https"://url.to/image", "link":"https://url.to/your-page"}] }'

When the scene is finished playing, you can add an optional 3 links with images to the exit screen. These images and links will be displayed above the sharing icons. The images will be evenly spaced across the screen and are fit into a 1:1 aspect ratio taking up 20% of the screeen width.

Distance Markers

var request = require('request');
var sceneDetails = {
title: 'choose a unique title',
activities: [{ activityId: 'someActivity' }],
distanceMarkers: {
frequency: 5,
color: '#4286f4',
height: 200,
},
};
request.post(
{
url: 'https://api.ayvri.com/2.0/scene',
headers: { Authorization: access_token },
body: JSON.stringify(sceneDetails),
},
function(err, res, body) {
var embedUrl = JSON.parse(body).embedUrl;
},
);
curl -X POST https://api.ayvri.com/2.0/scene \
-H "Authorization: access_token"
-d '{"activities":[{"activityId": "someActivityId"}], "distanceMarkers": {"frequency": 5, "color": "#4286f4"}}'

A scene can have distance markers evenly distributed across the length of a scene.

If the frequency is 5 and the users is viewing in metric, the markers will display at each 5 kilometer. If the user is viewing in imperial, the markers will be displayed at each 5 miles.

Client API

With the Ayvri Client API, your scene can be updated in real-time via Javascript. This API is currently in beta. Contact us to enable the Client API on your API account and for access to the documentation.