Motiontag API
This is a brief tutorial on how to set up your backend/scripts to work with the APIs MOTIONTAG has to offer.
1. Prerequisites
In order to create an account in any of our products you need to contact the MOTIONTAG staff. They will provide you with a dedicated domain, which also serves as the base URL for the APIs. When signed in you can see your custom tenant key below.
my-tenant-key.motion-tag.de
) and
an account to sign in. Contact
MOTIONTAG Support
to request a custom domain setup and an account. If you
already have both, visit your custom domain and sign in to see
a customized version of this documentation.
Furthermore, you'll be able to sign in into our dashboard to access information about your setup and your users. When logged in with the right privileges you'll be able to download or upload certain data manually as well.
Part of your base URL contains your tenant key, which you need to
create correct iss
claims. When signed in you can see
your custom tenant key below.
my-tenant-key.motion-tag.de
) and
an account to sign in. Contact
MOTIONTAG Support
to request a custom domain setup and an account. If you
already have both, visit your custom domain and sign in to see
a customized version of this documentation.
2. Authentication
Every request must be authenticated with a JWT.
The JWT must be signed with the shared secret which is available below when signed in
and encoded with HS256
.
my-tenant-key.motion-tag.de
) and
an account to sign in. Contact
MOTIONTAG Support
to request a custom domain setup and an account. If you
already have both, visit your custom domain and sign in to see
a customized version of this documentation.
Depending on the endpoint, the JWT must include specific claims such
as sub
and exp
, which are documented in
each endpoint's parameter list. Depending on the intended use, a JWT
can either be scoped to a single end user, or to all users. Here an
example of the claims for a single user.
{ "iss": "tenant-key", "sub": "aaaaaaaa-1111-2222-3333-bbbbbbbbbbbb", "exp": 1709020393 }
Unless noted otherwise, the JSON Web Token must be sent as HTTP
authorization header with Bearer
, like this:
{ "Authorization": "Bearer abc123.def456.gehz7890" }
Code example
Here's a small Ruby and Python code example on how to create the JWT
for a single user. Which includes the iss
as tenant key,
the sub
as User ID (UUID) and exp
as an
expiration timestamp (seconds since epoch) as well as assuming the
shared secret is available in the environment variable
SHARED_SECRET
.
In Ruby using the jwt
gem
require 'jwt' claims = { iss: 'tenant-key', sub: 'aaaaaaaa-1111-2222-3333-bbbbbbbbbbbb', exp: Time.now.to_i + 60, } JWT.encode(claims, ENV['SHARED_SECRET'], 'HS256') # => abc123.def456.gehz7890
In Python using PyJWT
package
import os import time import jwt claims = { "iss": "tenant-key", "sub": "aaaaaaaa-1111-2222-3333-bbbbbbbbbbbb", "exp": int(time.time()) + 60 } jwt.encode(claims, os.getenv("SHARED_SECRET"), algorithm="HS256") # => abc123.def456.gehz7890
3. User management
3.1 Create user
In order to create a user on our backend the SDK (on the phone) must be configured with a user token at runtime. This enables the SDK to send us events we need to create tracks and stays.
Tokens can be generated on your backend, or manually with the form below (only accessible when signed in). They are signed JWTs. Users are identified by distinct UUIDs – the creation and management of the user UUIDs is up to you. MOTIONTAG creates a user entry in its database when data from the SDK for a new user UUID arrives for the first time. This user UUID is used to identify data transferred back to you.
To generate the JWTs on your backend, encode and sign a payload like the example below with the shared secret, which can be found above in Authentication section.
Claims for SDK token
Claim | Type | Description | Required |
---|---|---|---|
iss |
String |
Your tenant key | |
sub |
String |
User UUID | |
exp |
Integer |
Expiration time in seconds since epoch |
When using the HS256
algorithm
the following example claim payload
{ "iss": "tenant-key", "sub": "aaaaaaaa-1111-2222-3333-bbbbbbbbbbbb", "exp": 1709020393 }
can be encoded as a valid user token (JWT). A code example on how to do this can be found here. This token can be used to initialize the MOTIONTAG SDK within your iOS or Android app. Now you have to find a way to deliver this token to your own apps. We need this JWT to create an authorization header ourselves in order to send events (e.g. location data) from inside our SDK to our backend.
Generate valid tokens
In this section you can generate one or multiple valid JWTs to test with your app. Additionally you can compare those generated JWTs with the ones you created and check if you did everything correctly.
my-tenant-key.motion-tag.de
) and
an account to sign in. Contact
MOTIONTAG Support
to request a custom domain setup and an account. If you
already have both, visit your custom domain and sign in to see
a customized version of this documentation.
3.2 Delete user
The following endpoint enqueues a job, which deletes related user data in the background, the complete process can take several hours. The delete user endpoint does not require any request parameters, instead it needs a user specific JWT with the following claims.
Endpoint
DELETE/json_api/user
Response body
{ "data": { "type": "Delete user", "id": "84342a1f-2963-4d78-a8ae-4651b81cb891" } }
On success, you receive a JSON
response with a
type
and id
property, id
contains the user id. The response HTTP status is 202
accepted.
Claims for authorization header
See the authentication section on how to create an authorization header from the following claims.
Claim | Type | Description | Required |
---|---|---|---|
iss |
String |
Your tenant key | |
sub |
String |
User UUID | |
exp |
Integer |
Expiration time in seconds since epoch |
4. Data management
There are two ways you can retrieve tracks and stays into your backend from MOTIONTAG. Both ways allow you to get multiple items of multiple users with only one authorization token (JWT).
The Synchronization API is like an endless stream of tracks and stays which are chronologically ordered and grouped into pages of reasonable size. New entries are appended continuously. This endpoint is deterministic, which means you can jump back and forth between pages any time and will always retrieve the same data.
The Dump Interface can be accessed programmatically, but allows you only to download data. This is basically the same endpoint you can access when downloading dumps from the dashboard. In order to download dumps they need to be created manually first. Luckily dumps can be scheduled by MOTIONTAG before execution, what allows e.g. for weekly dump creations for the next six months.
4.1 Synchronization API
This is an endpoint for full synchronization of the complete storyline of all users. Meant to be implemented by customers that run their own backend service and want to maintain a full copy of all their user's storyline on their backend service.
An initial request without the special page
parameter
will return the first available page, and include a link to the next
page. When the end is reached, an empty page without a next link is
returned. In this case the consumer should pause for a short time and
then retry to load the same page again.
In case you are wondering, possible values for modes and purpose depend on the server configuration and can be looked up in the admin dashboard here.
The geometry attribute is optional. It depends on your tenant configuration whether your are able to receive it from the Synchronization API.
- Retrieve tracks and stays for multiple users and days at once
- You only need one JWT to authenticate
- It is deterministic, so every time you send the same request you get the same response
- This also means you can go back and forth in time
- You handle data edits directly on your side, between your app and your backend
- You can't retrieve any edits on tracks and stays
- There is only tracks and stays data available via this API
Endpoint
GET/sync/storyline
Claims for authorization header
See the authentication section on how to create an authorization header from the following claims.
Claim | Type | Description | Required |
---|---|---|---|
sub |
String |
Fixed value for this endpoint: sync |
|
exp |
Integer |
Expiration time in seconds since epoch, recommended to set to near future |
Query parameters
Name | Type | Description |
---|---|---|
page[after] |
String | Paging position, used by the server to determine next page |
Initial request example
Do not include page parameter on the initial request.
GET/sync/storyline
{ "data": [ { "type" : "Track", "id" : "8861e1e2-abd0-41cc-9b3d-f8c2d2613cf4", "attributes" : { "user_id" : "d28907c7-0846-461f-950e-9d40f2ca418c", "created_at" : "2018-01-01T16:00:00Z", "started_at" : "2018-01-01T14:00:00Z", "started_at_timezone" : "Europe/Zurich", "finished_at" : "2018-01-01T15:00:00Z", "finished_at_timezone" : "Europe/Zurich", "geometry" : { "type" : "LineString", "coordinates" : [ [ 1, 1.5 ], [ 1.5, 2 ] ] }, "track_mode" : "bicycle", "track_length_in_meters" : 5000 } }, { "type" : "Stay", "id" : "c862b09b-2786-4be3-b0d6-90997783a343", "attributes" : { "user_id" : "437b0a94-d495-4e4e-96fb-fe1783b5c95e", "created_at" : "2018-01-01T16:00:00Z", "started_at" : "2018-01-01T14:00:00Z", "started_at_timezone" : "Europe/Zurich", "finished_at" : "2018-01-01T15:00:00Z", "finished_at_timezone" : "Europe/Zurich", "geometry" : { "type" : "Point", "coordinates" : [ 1, 1.5 ] }, "stay_purpose" : "study" } } ], "links": { "next" : "https://api.motion-tag.de/sync/storyline?page[after]=abc123" } }
The consumer is expected to store the received entries and
immediately afterwards request the next page given in
links.next
. The value of page[after]
has
no meaning beyond being used by the server to determine the next page.
Subsequent request example
In this example, no data is returned. In the case of no data, the consumer should pause for a short time and then request the same URL again.
GET/sync/storyline?page[after]=abc123
{
"data": []
}
4.2 Dump interface
Data dumps available on the admin dashboard interface under "Dumps" can be downloaded from this endpoint by using their filename. The filename is chosen automatically on creation and consists of the dump type, its user and date criteria, and the format. Note that the API currently only provides the ability to download dumps, not to create or delete them.
- Retrieve tracks and stays for multiple users and days at once
- There is also other data, e.g. user statistics or trips and journeys available
- It is even possible to get a custom dump design
- You only need one JWT to authenticate
- You can retrieve edits on tracks and stays
- It is not deterministic, so results might change over time regarding tracks and stays
- Dumps can't be created programmatically and need to be scheduled ahead of time
Endpoint
GET/dumps/{filename}
Claims for authorization header
See the authentication section on how to create an authorization header from the following claims.
Claim | Type | Description | Required |
---|---|---|---|
sub |
String |
Fixed value for this endpoint: dumps |
|
exp |
Integer |
Expiration time in seconds since epoch, recommended to set to near future |
Path parameters
Name | Type | Description |
---|---|---|
filename |
String |
Filename of the dump |
Query parameters
As an alternative authentication method you can use the JWT as URL query parameter instead of the HTTP request header.
Name | Type | Description | Required |
---|---|---|---|
jwt |
String |
The generated JWT |
Example request
GET/dumps/ExampleDump.SomeProject.2020-01-01--2020-01-31.csv.gz
Example with alternative authorization
GET/dumps/ExampleDump.SomeProject.2020-01-01--2020-01-31.csv.gz?jwt=abc123.def456.gehz7890
4.3 Stream API
This is an endpoint for full synchronization of the complete storyline of all users, including user edits. Meant to be implemented by customers that run their own backend service and want to maintain a full copy of all their users' storyline on their backend service.
An initial request without the special time
parameter
will return the results of the first time slice, and include a link to the next
time slice. A time slice contains all objects that were created or updated within that time slice.
Individual time slices can contain no results, but will still provide a link to the next time slice.
The consumer should ensure that the requests are paused for a while when the next link reaches the current time and no results are returned.
In case you are wondering, possible values for modes and purposes depend on the server configuration and can be looked up in the admin dashboard here.
- Retrieve tracks and stays for multiple users and days at once
- The consumer is always up to date with the latest user data and edits
- You only need one JWT to authenticate
- The consumer needs to ensure that data known already on the consumer side is updated appropriately based on the object id
Endpoint
GET/stream/storyline
Claims for authorization header
See the authentication section on how to create an authorization header from the following claims.
Claim | Type | Description | Required |
---|---|---|---|
sub |
String |
Fixed value for this endpoint: stream |
|
exp |
Integer |
Expiration time in seconds since epoch, recommended to set to near future |
Query parameters
Name | Type | Description |
---|---|---|
time[after] |
Timestamp without time zone | In ISO8601 format. Fractions of seconds are ignored. Starting position from which on user data and edits are fetched |
Initial request example
Do not include the time parameter on the initial request.
GET/stream/storyline
{ "data": [ { "id": "8b6d1f66-276f-45ff-9c25-622298043887", "user_id": "1263c31f-e0de-4154-b938-0740506c4076", "updated_at": "2024-08-22T12:01:00Z", "started_at": "2024-08-22T11:00:00Z", "started_at_timezone": "Europe/Vienna", "finished_at": "2024-08-22T11:10:00Z", "finished_at_timezone": "Europe/Berlin", "misdetected_completely": false, "geometry": { "type": "LineString", "coordinates": [ [1.0, 1.5], [1.5, 2.0] ] }, "created_at": "2024-08-22T11:20:00Z", "type": "Track", "length": 5000, "mode": "train", "detected_mode": "regional_train", "merged_into_id": null, "merge_count": 0, "public_transport_information": { "detected_departure_station_id": "16", "detected_departure_station_name": "Wien HBF", "detected_departure_station_location": { "type": "Point", "coordinates": [7.0, 8.0] }, "detected_arrival_station_id": "17", "detected_arrival_station_name": "Berlin HBF", "detected_arrival_station_location": { "type": "Point", "coordinates": [7.0, 9.0] }, "detected_line_number": "REX123", "detected_operator": "OEBB", "detected_route_id": "123", "detected_resource": "gtfs" } }, { "id": "5fa64219-cb4b-478e-80a8-0122cc4e9890", "user_id": "56192c4a-682e-4701-ba2a-2ba30c72e696", "updated_at": "2024-08-22T12:01:10Z", "started_at": "2024-08-22T11:11:00Z", "started_at_timezone": "Europe/Berlin", "finished_at": "2024-08-22T11:21:00Z", "finished_at_timezone": "Europe/Berlin", "misdetected_completely": false, "geometry": { "type": "Point", "coordinates": [1.0, 1.5] }, "created_at": "2024-08-22T11:30:00Z", "type": "Stay", "purpose": "study", "detected_purpose": "leisure", "point_of_interest_information": { "detected_poi_name": "Library" } } ], "links": { "next": "http://www.example.com/stream/storyline?time%5Bafter%5D=2024-08-01+12%3A15%3A17+UTC" } }
Attributes
Merges can happen by the user between subsequent tracks. The later track B is always merged into the earlier track A. Such an operation increases the merge_count of track A by 1, and track B references track A in its merged_into_id attribute. Track A does not back-reference track B. Track A will have the combined geometry and timestamps of both tracks A and B. This means that items that have set a merged_into_id contain duplicated spatio-temporal information. Such and misdetected_completely items are not part anymore of the current state of the storyline, so it is likely that in an analysis, such items should be filtered out and only the attributes not prefixed with detected_ should be used. detected_* attributes never change. This means that if a e.g. a track was detected as public transport, but was corrected to car, it will still have the public transport attributes that were originally detected.
- merge_count: How many tracks have been merged into the track.
- merged_into_id: The id of the track that this track has been merged with.
- misdetected_completely: Whether the user deleted an item because it was wrongly detected.
Paid attributes
Depending on which paid features are enabled on your tenant, some of the attributes may or may not be present in the response. Note that even if a feature is enabled, an item might not contain the attribute if no attribute was found. These are:
- Geometries
- Public transport information
- Point of interest information
The consumer is expected to store the received entries and
immediately afterwards request the next page given in
links.next
. The value of time[after]
has
refers to the start of the next time slice for which data can be fetched.
Subsequent request example
In this example, the consumer reached the end of the stream and no data is returned. Assuming the current time is 2024-08-22T12:00:00Z, and the consumer sends a request at that time, the response will be empty and contain a link pointing to a timestamp that is close to the request time. In this case, the request should be paused for a short time and then the same URL should be requested again. Note that the returned timestamp in the link is URL-encoded and needs to be decoded before being used.
GET/stream/storyline?time[after]=2024-08-22T12:00:00Z
{ "data": [], "links":{ "next":"http://www.example.com/stream/storyline?time%5Bafter%5D=2024-08-01+12%3A00%3A01+UTC" } }
5. Interactive API
If you plan to integrate our SDK and directly connect your app with our
backend you are in the correct place here. The Interactive API
allows the user to directly fetch (GET
) and edit (PATCH
)
tracks and stays. This means your backend is only needed to create the JWTs
for your users in order to directly identify the user on our backend side.
You still need to maintain the user UUID and the JWT, but every interaction
is completely decoupled from your backend. In order to download tracks or
stays with their respective edits to your backend you would need to use the
Dump Interface.
- Your users can directly edit tracks and stays
- Your app talks directly to our backend and handles track and stay data accordingly
- Your backend doesn't need to save any tracks and stays
- Your backend only has to deal with user management, but avoids all the internet traffic and data persistence around tracks and stays
- You need for each user a separate JWT to authenticate and fetch data, which you anyways have to create in order to create a user for the SDK
- There is only tracks and stays data available via this API
5.1 Storyline GET
This endpoint allows to retrieve a part of the storyline of a single user. It is meant for interactive use, such as displaying a list of tracks and stays on a map in a mobile app.
Endpoint
GET/storyline/{date}
Claims for authorization header
See the authentication section on how to create an authorization header from the following claims.
Claim | Type | Description | Required |
---|---|---|---|
sub |
String |
UUID of a user | |
aud |
String |
Fixed value for this endpoint: read |
|
exp |
Integer |
Expiration time in seconds since epoch |
Path parameters
Name | Type | Description | Required |
---|---|---|---|
date |
Date |
Single date, e.g. "2020-01-01" |
Query parameters
Name | Type | Description | Required |
---|---|---|---|
fields[Track] |
String |
Comma separated list of fields to include in Track | |
fields[Stay] |
String |
Comma separated list of fields to include in Stay |
The fields
parameters allow you
to limit the list of fields being returned to a
sparse fieldset.
In particular the geometry
field of Track can become quite large
and it makes sense to exclude it when not needed.
Tracks and stays are filtered to have started on the given date, in the local timezone they occurred in.
Response body
A list of storyline items. The list is ordered chronologically.
-
type
Can beTrack
orStay
.Track
has mode attributes,Stay
has purpose attributes. -
started_at
Is in the local timezone it occured in and includes the UTC offset. -
finished_at
Is in the local timezone it occured in and includes the UTC offset. -
length
Is only present for Storyline items of typeTrack
and is in meters. -
mode_key
Is the untranslated key of the mode, only present if the type isTrack
. This attribute can potentially be edited by the user. -
mode_name
Is the translated name of the mode, only present if the type isTrack
. See below for more information about the languages. -
purpose_key
Is the untranslated key of the purpose, only present if the type isStay
. This attribute can potentially be edited by the user. -
purpose_name
Is the translated name of the purpose, only present if the type isStay
. See below for more information about the languages. -
detected_mode_key
Is the untranslated key of the detected mode, only present if the type isTrack
. -
detected_mode_name
Is the translated name of the detected mode, only present if the type isTrack
. See below for more information about the languages. -
detected_purpose_key
Is the untranslated key of the detected purpose, only present if the type isStay
. -
detected_purpose_name
Is the translated name of the detected purpose, only present if the type isStay
. See below for more information about the languages. -
trip_id
In case trip generation is enabled for your tenant, this attribute will present the uuid of trip object. Can be empty. -
trip_purpose_key
In case trip generation is enabled for your tenant, this attribute will present the purpose of the trailing stay of the trip and is the untranslated key of the purpose. Can be empty. -
misdetected_completely
Is a flag if a storyline item was misdetected completely and should be therefore not being displayed once set totrue
. The default isfalse
. -
geometry
geometry
of aTrack
is a GeoJSON feature oftype
LineString
orMultiLineString
.geometry
of aStay
is a GeoJSON feature oftype
Point
.
The possible values for modes and purpose depend on the server configuration and can be looked up in the admin dashboard here.
The language of translated fields (currently mode_name
and
purpose_name
) is determined by the given
Accept-Language
header, or the server's default. The available languages
depend on the settings of the server.
Example request
GET/storyline/2020-01-01
{ "data": [ { "id": "4db59ee6-92ae-4e96-b5ec-eb192ee175cc", "type": "Track", "attributes": { "started_at": "2020-11-01T11:00:00+01:00", "finished_at": "2020-11-01T13:00:00-05:00", "length": 5000, "mode_key": "light_rail", "mode_name": "Rapid transit railway", "detected_mode_key": "train", "detected_mode_name": "Train", "misdetected_completely": false, "geometry": { "type": "LineString", "coordinates": [[2.0, 3.0], [3.0, 4.0]] } } }, { "id": "26966953-6a54-4f0f-886c-e2e0074b3005", "type": "Stay", "attributes": { "started_at": "2020-11-01T13:00:00-05:00", "finished_at": "2020-11-02T01:00:00-05:00", "purpose_key": "home", "purpose_name": "At home", "detected_purpose_key": "home", "detected_purpose_name": "At home", "misdetected_completely": true, "geometry": { "type": "Point", "coordinates": [3.0, 4.0] } } } ] }
This example response contains two storyline items, one Track and one Stay.
Example request with limited fields
GET/storyline/2020-01-01?fields[Track]=started_at,finished_at,mode_name&fields[Stay]=started_at,finished_at,purpose_name
{ "data": [ { "id": "4db59ee6-92ae-4e96-b5ec-eb192ee175cc", "type": "Track", "attributes": { "started_at": "2020-11-01T11:00:00+01:00", "finished_at": "2020-11-01T13:00:00-05:00", "mode_name": "Rapid transit railway" } }, { "id": "26966953-6a54-4f0f-886c-e2e0074b3005", "type": "Stay", "attributes": { "started_at": "2020-11-01T13:00:00-05:00", "finished_at": "2020-11-02T01:00:00-05:00", "purpose_name": "At home" } } ] }
5.2 Storyline PATCH
This endpoint allows to update a certain attribute of the storyline
of a single user. For a storyline item of type Track
you can edit
the attribute mode
. For a storyline item of type Stay
you can edit
the attribute purpose
. For both types Track
and Stay
you can edit
the attribute misdetected_completely
, which indicates that this item
should no longer be displayed. Note that you can only edit a single attribute per request.
Currently the only supported operation in the meta object of the JSON body is edit
.
Endpoint
PATCH/storyline/{id}
Claims for authorization header
See the authentication section on how to create an authorization header from the following claims.
Claim | Type | Description | Required |
---|---|---|---|
sub |
String |
UUID of a user | |
aud |
String |
Fixed value for this endpoint: read |
|
exp |
Integer |
Expiration time in seconds since epoch |
Path parameters
Name | Type | Description | Required |
---|---|---|---|
id |
UUID |
ID of a storyline item, e.g. 26966953-6a54-4f0f-886c-e2e0074b3005 |
Editable attributes in body
Name | Type | Description |
---|---|---|
mode |
String |
Mode key of a storyline item of type Track, e.g. "car" |
purpose |
String |
Purpose key of a storyline item of type Stay, e.g. "work" |
misdetected_completely |
Boolean |
Whether the storyline item should be displayed, e.g. true |
Example request
PATCH/storyline/26966953-6a54-4f0f-886c-e2e0074b3005
{ "data": { "id": "26966953-6a54-4f0f-886c-e2e0074b3005", "type": "Stay", "attributes": { "purpose": "sport" } }, "meta": { "operation": "edit" } }
Returns 204 No content if the operation was successful.
5.3 Calendar
This endpoint allows you to retrieve one element for each day with a count of storyline items since the activation of the user for the requested year.
GET/calendar/{year}
Claims for authorization header
See the authentication section on how to create an authorization header from the following claims.
Claim | Type | Description | Required |
---|---|---|---|
sub |
String |
UUID of a user | |
aud |
String |
Fixed value for this endpoint: read |
|
exp |
Integer |
Expiration time in seconds since epoch |
Path parameters
Name | Type | Description | Required |
---|---|---|---|
year |
Integer |
Single year, e.g. "2020" |
Response body
A chronologically sorted list of dates the user was active in, with storyline counts.
Example request
GET/calendar/2020
{ "data": { "id": "7015915d-cb3c-417e-a855-6091bf3f9d14/2020", "type": "Calendar", "attributes": { "days": [ { "date": "2020-12-29", "storyline_count": 0 }, { "date": "2020-12-30", "storyline_count": 2 }, { "date": "2020-12-31", "storyline_count": 1 } ] } } }
This example response contains always just one entry. It shows all days of the year with a count of storyline items per day since the activation of the user (in this example case the user was activated on '2020-12-29').
5.4 Modes
This endpoint allows you to retrieve all enabled modes of your tenant.
Endpoint
GET/modes
Claims for authorization header
See the authentication section on how to create an authorization header from the following claims.
Claim | Type | Description | Required |
---|---|---|---|
sub |
String |
UUID of a user | |
aud |
String |
Fixed value for this endpoint: read |
|
exp |
Integer |
Expiration time in seconds since epoch |
Response body
An alphabetically sorted list of modes. The id property contains the
provided user ID of the JWT token sub
claim.
Example request
GET/modes
{ "data": { "id": "7015915d-cb3c-417e-a855-6091bf3f9d14/2020", "type": "Modes", "attributes": [ { "id": "Mode::Airplane", "key": "airplane", "name": "Airplane", "color": "#e9b100", "darker_color": "#ba8e00", "icon": "/icons/modes/airplane.png", "icon_white_3x": "/icons/modes/airplane_white_3x.png", "icon_svg": "/icons/modes/airplane.svg", "carbon_emission_per_kilometer": 196, "public_transport": false }, {..}, ] } }
On success, you receive a JSON
response with a
type
and id
property, id
contains the user id. The response HTTP status is 200
OK.
5.5 Purposes
This endpoint allows you to retrieve all enabled purposes of your tenant.
Endpoint
GET/purposes
Claims for authorization header
See the authentication section on how to create an authorization header from the following claims.
Claim | Type | Description | Required |
---|---|---|---|
sub |
String |
UUID of a user | |
aud |
String |
Fixed value for this endpoint: read |
|
exp |
Integer |
Expiration time in seconds since epoch |
Response body
An alphabetically sorted list of purpose. The id property contains the
provided user ID of the JWT token sub
claim.
Example request
GET/purposes
{ "data": { "id": "7015915d-cb3c-417e-a855-6091bf3f9d14/2020", "type": "Purposes", "attributes": [ { "id": "home", "key": "home", "name": "At home", "color": "#4f4f4f", "darker_color": "#3f3f3f", "icon_white_3x": "/icons/purposes/home_white_3x.png", "icon_svg": "/icons/purposes/home.svg", "icon_marker_png": "/icons/purposes/home_marker.png" }, {..}, ] } }
On success, you receive a JSON
response with a type
and id
property, id
contains the user id. The response
HTTP status is 200
OK.
5.6 Statistics
The response contains statistics for count
, length
and duration
within a given date range for the current user. Additionally name
translations,
the days
count and the carbon_emission_per_kilometer
are included.
Endpoint
GET/statistics/{date_range}
Claims for authorization header
See the authentication section on how to create an authorization header from the following claims.
Claim | Type | Description | Required |
---|---|---|---|
sub |
String |
UUID of a user | |
aud |
String |
Fixed value for this endpoint: read |
|
exp |
Integer |
Expiration time in seconds since epoch |
Path parameters
Name | Type | Description | Required |
---|---|---|---|
date_range |
Date Range |
e.g. "2020-01-01--2020-01-31" |
Response body
A list of different statistics for the given date range.
-
count
number of tracks, grouped by mode key -
length
travelled distance in meters, grouped by mode key -
duration
duration as number of minutes, grouped by mode key -
days
total number of days with tracks -
name
translation of the mode key to the user's language -
carbon_emission_per_kilometer
carbon emission value in grams per kilometer and mode key
Example request
GET/statistics/2024-01-01--2024-01-31
{ "data": [ { "id": "2024-01-01--2024-01-31/user", "type": "statistics", "attributes": { "count": { "bicycle": 22, "car": 3, "...<count for each mode>..." }, "length": { "bicycle": 53.25, "car": 32.44, "..." }, "duration": { "bicycle": 421, "car": 222, "..." }, "name": { "bicycle": "Fahrrad", "car": "Auto", "..." }, "carbon_emission_per_kilometer": { "bicycle": 0, "car": 139, "..." }, "days": 12 } } ] }
- Both dates of the range are required
- To get statistics for a single day, request a date range that starts and ends on the same day
-
The part after the slash in the id, e.g. in
2016-01-01--2016-01-31/user
, contains the scope for auser
.