sharedmobility.github.io

Introduction:

VOI is a Swedish ride sharing company focused on electric scooters. They have scooters placed in several cities and countries around the world, including Sweden, Spain, Italy, France and more.

Base url of the API is https://api.voiapp.io/v1

Authentication:

The API requires an Access Token. This token is valid for only a short time (10 minutes I think, I haven’t tried to measure). You get the Access Token by opening a session. You need an Authentication Token to open a session. When opening a session, you get:

To get the first Authentication Token, see steps 1,2,3 below.

See here example of python implementation of the session authentication (once the step 1-2-3 are done): https://github.com/hawisizu/scooter_scrapper/blob/master/providers/voi.py

1 - Get OTP

POST request to https://api.voiapp.io/v1/auth/verify/phone

Body: raw/JSON

{
    "country_code": "DE",
    "phone_number": "176xxxxxxxx"
}

Note: phone number is without any 0.

In the body of the answer, you get a UUID in a param token, and of course an SMS message to the provided phone number.

{
"token": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}

2 - Verify OTP

This request gets nothing in the answer, but is necessary so that the token works. The code should be the value received by SMS.

POST request to https://api.voiapp.io/v1/auth/verify/code

Body: raw/JSON

{
    "code": "123456",
    "token": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}

Answer is 204 with no content.

3 - Get first authToken

POST request to https://api.voiapp.io/v1/auth/verify/presence

Body: raw/JSON:

{
    "email": "xxx@xxx.com",
    "token": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}

(the email should apparently be valid) Answer will be:

{
    "authenticationToken": "xxxxxxxxxxxxxxxx"
}

(the token is really super long)

4 - Open Session

POST request to https://api.voiapp.io/v1/auth/session

Body: raw/JSON

{
    "authenticationToken": "xxxxxxxxxxxxxxxx"
}

Answer will be:

{
    "accessToken": "yyyyyyyyyyyyyyyyy",
    "authenticationToken": "zzzzzzzzzzzzzzzzzzz"
}

You will then use the accessToken to query the data, and the authenticationToken to open the next session, so that you don’t have to re-do step 1-2-3

Access scooter data

Once you have an Access Token, you can query the zones info, or if you already know which zone you want to query, get the scooters of the zone.

Get zones info

GET request to https://api.voiapp.io/v1/zones In the headers you need the access token you got when opening a session: x-access-token: yyyyyyyyyyyyyyyyy

Answer: a long json with all the zones where VOI is currently operating, with details on the prices and forbidden zones, the max speed, etc. See here an example of the full zones json retrieved on Dec 20th, 2019: https://gist.github.com/hawisizu/4d54000dc4d5d6d2e39f6994006b74d2

Notes:

Get Scooter info

GET request to https://api.voiapp.io/v2/rides/vehicles?zone_id=<ZONE_ID>

<ZONE_ID> has to be the ID of one of the zones.

In the headers you need the access token you got when opening a session: x-access-token: yyyyyyyyyyyyyyyyy

Answer:

{
  "data": {
    "vehicle_groups": [
      {
        "price_token": "...",
        "group_type": "scooter",
        "vehicles": [
          {
            "id": "274db72d-f108-417a-93e3-46acb61cfd26",
            "short": "kpne",
            "battery": 55,
            "location": {
              "lng": 18.11346435546875,
              "lat": 59.34138107299805
            },
            "zone_id": "1"
          },
          {
            "id": "3bd0b7bf-15c0-46f8-9d3b-ecb962f1f5d5",
            "short": "bnjs",
            "battery": 78,
            "location": {
              "lng": 18.088924407958984,
              "lat": 59.354530334472656
            },
            "zone_id": "1"
          }
        ]
      }
    ]
  }
}

The response is a nested object with information about each scooter, in a JSON format. Here is a list of the parameters in each scooter object and information about what they (most likely) do:

id: A scooter ID that most likely is used internally.

short: A four-character shortcode of the VOI scooter, which is used to unlock it in the app if you don´t scan the QR code on the scooter.

battery: An integer representing the battery percentage of the scooter.

location: An object of the scooter location.

zone_id: This is most likely an indication of what zone the scooter is located in. Each VOI zone is represented by an integer.