Overview

Park and Ride is one of the solutions to tackle Helsinki regions growing population and traffic by encouraging citizens to leave their cars outside of the most congested areas and continuing their trip with public transportation. HSL Park and Ride application contains all the important information about parking facilities and their services near public transportation hubs. The application is used by HSL, parking operators, roadside displays and third party applications. All data is provided free of charge under the CC BY 4.0 license.

API follows REST conventions roughly. Resources are divided into collection and item URLs. Collection resources typically accept GET-parameters for filtering, paging and sorting items. Reading data uses GET-method and doesn’t require authorization - except for user management. Restricted modifications use either POST on collection-URL for creating new items and PUT on item URL for updates.

DELETE is not directly supported currently but the goal is achieved using e.g. a status field. However, if sometime in the future we need to delete something for reason or another, please prepare for 404 on a resource that has previously returned a result.

Somewhat contrary to strict REST ideology we provide all dependent (deep) information directly from item URLs. You need not get basic relations using nested calls. Shared resources are referenced using IDs (not URIs), and until HATEOAS-type links are implemented one needs to know and construct URIs using templates in order get details of such shared resources (e.g. operator or contacts). For most cases there exists an ID-based filtering parameter (ids) for collection URLs that allow getting basic information of all referred resources with single request.

Changes to the API

We aim to develop the API in a backwards compatible manner, i.e. features are only added while maintaining old semantics. However, we appreciate your feedback and will take it into account in future development. In the end, this may lead to a need to refactor the APIs. Unless such a breaking change is due to some critical security related issue, we will give you a warning about it well in advance. _Upcoming: Please register yourself and your app to a mailing list in order to receive announcements of coming changes. For now, you can contact markku.huotari@hsl.fi.

Development

Park and Ride application is developed as an Open Source project in GitHub: https://github.com/HSLdevcom/parkandrideAPI.

Please, report bugs and feature requests as GitHub issues.

Examples

Most API-features are used by the Park and Ride maintenance UI and its source code contains real life example.

Upcoming features can be tested in https://test.liipi.hsldev.com/

License

Source code is licensed under AGPL and EUPL licenses. For details, see https://github.com/HSLdevcom/parkandrideAPI#license.

General Features

Authentication

Mutable operations require authentication using the Authorization header as shown in the following example. The value is the string Bearer followed by the API user’s token. Operators can create API users and tokens for them through the user administration page.

PUT /api/v1/facilities/1/utilization HTTP/1.1
Content-Type: application/json
Authorization: Bearer P|1|1651752664903|qpUuUUN-f5IA3NU5CqUf5gkQr12TRJjb-thFo6LhK9c

[]
Note
Authentication is not needed for read-only (GET) methods.

Usage tracking

API usage is tracked by logging all incoming requests per application. To enable tracking for your specific application’s needs, please include the Liipi-Application-Id header in your requests. The header values must match the following pattern: [a-zA-Z0-9_\-\./]{3,20}. If no header is specified, the request will still be logged with null application id. For example, the web user interface uses liipi-ui as its identifier.

GET /api/v1/facilities HTTP/1.1
Content-Type: application/json
Liipi-Application-Id: liipi-ui

[]

Supported Formats

Both JSON and GeoJSON (Feature/FeatureCollection) are supported for facilities and hubs. In JSON format locations are provided using GeoJSON Geometries (Point or Polygon). GeoJSON’s feature centric view contains only basic metadata of given entity.

Required format is specified either with .json or .geojson suffix or by using Accept header with application/json or application/vnd.geo+json value.

$ curl 'https://p.hsl.fi/api/v1/facilities.json' -i -X GET
$ curl 'https://p.hsl.fi/api/v1/facilities.geojson' -i -X GET
$ curl 'https://p.hsl.fi/api/v1/facilities' -i -X GET \
    -H 'Accept: application/json'
$ curl 'https://p.hsl.fi/api/v1/hubs' -i -X GET \
    -H 'Accept: application/vnd.geo+json;charset=UTF-8'

If no suffix or Accept header is given, JSON is used by default.

$ curl 'https://p.hsl.fi/api/v1/facilities' -i -X GET

General Search Features

While simple listings (e.g. enums) may return arrays of values directly, searches return results that are wrapped within an object. This result object has boolean field hasMore that indicates whether or not there’s more result rows available:

{
  "results": [...]
  "hasMore": false
}

Limiting result size is done via limit and offset int-parameters. Limit defines the maximum number of items to be returned and offset the zero-based index of the first row to be returned. Use negative value for limit to get all the results.

Ordering of result items is done via sort.by and sort.dir parameters. Allowed values of sort.by is resource dependent but typically at least name.fi, name.sv and name.en are supported. Direction is given as ASC or DESC.

$ curl 'https://p.hsl.fi/api/v1/facilities?limit=10&offset=4&sort.by=name.fi&sort.dir=ASC' -i -X GET

Localization

Park and Ride data is localized in Finnish, Swedish and English. Localized fields are represented as objects with fi, sv and en fields:

{
  "name": {
    "fi": "Nimi",
    "sv": "Namn",
    "en": "Name"
  }
}

Optional localized fields are either null or localized for all supported languages. For example missing (optional) info:

{
  "info": null
}
Warning
None of the textual fields may contain HTML-markup, and must be escaped before rendering.

Enumerations

Park and Ride utilizes enumerated values for much of it’s metadata. Current value-sets are available via REST.

Capacity type defines different kind of parking slot types:

GET /api/v1/capacity-types HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json

[ "CAR", "DISABLED", "ELECTRIC_CAR", "MOTORCYCLE", "BICYCLE", "BICYCLE_SECURE_SPACE" ]

Usage specifies the purpose of the capacity. See Capacity.

GET /api/v1/usages HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json

[ "PARK_AND_RIDE", "COMMERCIAL" ]

Day type is a rough categorization of day types with different opening hours and/or pricing:

GET /api/v1/day-types HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json

[ "BUSINESS_DAY", "SATURDAY", "SUNDAY" ]

Authentication methods available in a facility:

GET /api/v1/authentication-methods HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json

[ "HSL_TICKET", "VR_TICKET" ]

Services provided by a facility:

GET /api/v1/services HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json

[ "LIGHTING", "COVERED", "SURVEILLANCE_CAMERAS", "PAYMENT_AT_GATE", "ENGINE_IGNITION_AID", "BICYCLE_FRAME_LOCK" ]

Payment methods accepted by a facility:

GET /api/v1/payment-methods HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json

[ "COINS", "NOTES", "DEBIT_CARD", "MOBILE_PAYMENT", "OTHER" ]

Facility status indicates whether the facility is operating normally or is exceptionally closed. See Status.

GET /api/v1/facility-statuses HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json

[ "IN_OPERATION", "INACTIVE", "TEMPORARILY_CLOSED", "EXCEPTIONAL_SITUATION" ]

Pricing method is a shortcut for maintaining actual facility pricing information. See Pricing.

GET /api/v1/pricing-methods HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json

[ "PARK_AND_RIDE_247_FREE", "FREE_10H", "FREE_12H", "PAID_10H", "PAID_12H", "PAID_16H", "PAID_24H", "PAID_16H_24H_48H", "CUSTOM" ]

Operators

All facilities are operated by an operator. Operator can be listed with:

GET /api/v1/operators HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json

{
  "results" : [ {
    "id" : 1,
    "name" : {
      "fi" : "SMOOTH0439",
      "sv" : "SMOOTH0439",
      "en" : "SMOOTH0439"
    },
    "regionId" : null
  } ],
  "hasMore" : false
}

Details of an operator can be fetched with:

GET /api/v1/operators/1 HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json

{
  "id" : 1,
  "name" : {
    "fi" : "SMOOTH0434",
    "sv" : "SMOOTH0434",
    "en" : "SMOOTH0434"
  },
  "regionId" : null
}

Summary of Operator Model

Path Type Description

id

Number

Contact ID: /api/v1/operators/{id}

name

Object

Localized name

regionId

Null

The region that operator resides

Contacts

Facilities have emergency, operator and service contacts, where the two first are mandatory and service contact optional. Contacts are either general, maintained by HSL and shared by all operators, or operator specific. Operator specific contacts have operatorId property.

GET /api/v1/contacts HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json

{
  "results" : [ {
    "id" : 1,
    "name" : {
      "fi" : "TEST 0395",
      "sv" : "TEST 0395",
      "en" : "TEST 0395"
    },
    "operatorId" : null,
    "phone" : "09 47664000",
    "email" : "test@example.com",
    "address" : {
      "streetAddress" : {
        "fi" : "street",
        "sv" : "street",
        "en" : "street"
      },
      "postalCode" : "00100",
      "city" : {
        "fi" : "city",
        "sv" : "city",
        "en" : "city"
      }
    },
    "openingHours" : {
      "fi" : "opening hours",
      "sv" : "opening hours",
      "en" : "opening hours"
    },
    "info" : {
      "fi" : "info",
      "sv" : "info",
      "en" : "info"
    }
  }, {
    "id" : 2,
    "name" : {
      "fi" : "TEST 0396",
      "sv" : "TEST 0396",
      "en" : "TEST 0396"
    },
    "operatorId" : null,
    "phone" : "09 47664000",
    "email" : "test@example.com",
    "address" : {
      "streetAddress" : {
        "fi" : "street",
        "sv" : "street",
        "en" : "street"
      },
      "postalCode" : "00100",
      "city" : {
        "fi" : "city",
        "sv" : "city",
        "en" : "city"
      }
    },
    "openingHours" : {
      "fi" : "opening hours",
      "sv" : "opening hours",
      "en" : "opening hours"
    },
    "info" : {
      "fi" : "info",
      "sv" : "info",
      "en" : "info"
    }
  }, {
    "id" : 3,
    "name" : {
      "fi" : "TEST 0397",
      "sv" : "TEST 0397",
      "en" : "TEST 0397"
    },
    "operatorId" : null,
    "phone" : "09 47664000",
    "email" : "test@example.com",
    "address" : {
      "streetAddress" : {
        "fi" : "street",
        "sv" : "street",
        "en" : "street"
      },
      "postalCode" : "00100",
      "city" : {
        "fi" : "city",
        "sv" : "city",
        "en" : "city"
      }
    },
    "openingHours" : {
      "fi" : "opening hours",
      "sv" : "opening hours",
      "en" : "opening hours"
    },
    "info" : {
      "fi" : "info",
      "sv" : "info",
      "en" : "info"
    }
  } ],
  "hasMore" : false
}

Contacts can be searched with optional ids [0..n] and operatorId [0..1] parameters:

GET /api/v1/contacts?ids=101&ids=102 HTTP/1.1
GET /api/v1/contacts?operatorId=42 HTTP/1.1

Contact details can fetched by id:

GET /api/v1/contacts/1 HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json

{
  "id" : 1,
  "name" : {
    "fi" : "TEST 0365",
    "sv" : "TEST 0365",
    "en" : "TEST 0365"
  },
  "operatorId" : null,
  "phone" : "09 47664000",
  "email" : "test@example.com",
  "address" : {
    "streetAddress" : {
      "fi" : "street",
      "sv" : "street",
      "en" : "street"
    },
    "postalCode" : "00100",
    "city" : {
      "fi" : "city",
      "sv" : "city",
      "en" : "city"
    }
  },
  "openingHours" : {
    "fi" : "opening hours",
    "sv" : "opening hours",
    "en" : "opening hours"
  },
  "info" : {
    "fi" : "info",
    "sv" : "info",
    "en" : "info"
  }
}

Summary of Contacts Model

Path Type Description

id

Number

Contact ID: /api/v1/contacts/{id}

name

Object

Localized name

operatorId

NUMBER

Contact operator ID: /api/v1/operators/{operatorId} (OPTIONAL)

email

String

Email address (OPTIONAL)

phone

String

Phone number (OPTIONAL)

address

Object

Contact address (OPTIONAL)

address.streetAddress

Object

Localized street name (OPTIONAL)

address.postalCode

String

Postal code (OPTIONAL)

address.city

Object

Localized city name (OPTIONAL)

openingHours

Object

Localized opening hours (OPTIONAL)

info

Object

Localized information (OPTIONAL)

Facilities

Facility collection resource allows filtering returned items by status, ids and location. These parameters can be mixed and matched to suite your use-case.

By Status

Use multi-valued statuses parameter to filter by status, e.g. only facilities that are IN_OPERATION or have some EXCEPTIONAL_SITUATION:

GET /api/v1/facilities?statuses=IN_OPERATION&statuses=EXCEPTIONAL_SITUATION HTTP/1.1

For status details, e.g. information about EXCEPTIONAL_SITUATION, see statusDescription.

By Ids

Sometimes you know IDs of multiple facilities and want to get their basic information as quickly as possible. This is the case with hubs, that only know the facilityIds of related facilities. Multi-valued ids -parameter is made for just this:

GET /api/v1/facilities?ids=11&ids=12 HTTP/1.1

Facilities have a location that is a Polygon in WGS84 (or EPSG:4326) projection. Facilities can be searched using WKT-formatted geometry query parameter. Supported geometry types are

  • Point

  • LineString

  • Polygon

  • MultiPoint

  • MultiLineString

  • MultiPolygon

You may test spatial searches with Search Demo.

Within Shape

If only geometry is specified, facilities whose location overlaps with it are returned.

GET /api/v1/facilities?geometry=POLYGON((25.011942+60.251343,25.011717+60.250454,25.013487+60.250848,25.011942+60.251343)) HTTP/1.1
Within Max Distance

If maxDistance (double) is specified along side geometry then facilities whose location is within given max distance (meters) are returned.

GET /api/v1/facilities?geometry=POLYGON((25.011942+60.251343,25.011717+60.250454,25.013487+60.250848,25.011942+60.251343))&maxDistance=123.45 HTTP/1.1

Summary of Matching Facilities

An existence of a special parameter named summary transforms results into a summary of matched facilities. This summary consists of facilityCount and sum of capacity by type.

GET /api/v1/facilities?summary=true HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json

{
  "facilityCount" : 1,
  "capacities" : {
    "ELECTRIC_CAR" : 2,
    "CAR" : 50
  }
}

Facility Details

GET /api/v1/facilities/1 HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json

{
  "id" : 1,
  "name" : {
    "fi" : "Facility 0433",
    "sv" : "Facility 0433",
    "en" : "Facility 0433"
  },
  "location" : {"crs":{"type":"name","properties":{"name":"EPSG:4326"}},"bbox":[25.010822,60.250023,25.012479,60.250885],"type":"Polygon","coordinates":[[[25.010822,60.25054],[25.010822,60.250023],[25.012479,60.250337],[25.011449,60.250885],[25.010822,60.25054]]]},
  "operatorId" : 1,
  "type" : "CAR",
  "status" : "EXCEPTIONAL_SITUATION",
  "pricingMethod" : "CUSTOM",
  "statusDescription" : {
    "fi" : "Status description",
    "sv" : "Status description",
    "en" : "Status description"
  },
  "softDeletedAt" : null,
  "builtCapacity" : {
    "ELECTRIC_CAR" : 2,
    "CAR" : 50
  },
  "usages" : [ "PARK_AND_RIDE" ],
  "services" : [ "LIGHTING", "COVERED", "SURVEILLANCE_CAMERAS" ],
  "authenticationMethods" : [ ],
  "surveyOptions" : [ ],
  "pricing" : [ {
    "usage" : "PARK_AND_RIDE",
    "capacityType" : "CAR",
    "maxCapacity" : 50,
    "dayType" : "SATURDAY",
    "time" : {
      "from" : "08",
      "until" : "18"
    },
    "price" : {
      "fi" : "2 EUR/H",
      "sv" : "2 EUR/H",
      "en" : "2 EUR/H"
    },
    "priceExtra" : null,
    "priceOther" : null
  }, {
    "usage" : "PARK_AND_RIDE",
    "capacityType" : "CAR",
    "maxCapacity" : 50,
    "dayType" : "SUNDAY",
    "time" : {
      "from" : "08",
      "until" : "18"
    },
    "price" : {
      "fi" : "1 EUR/H",
      "sv" : "1 EUR/H",
      "en" : "1 EUR/H"
    },
    "priceExtra" : null,
    "priceOther" : null
  } ],
  "paymentInfo" : {
    "detail" : {
      "fi" : "Payment details",
      "sv" : "Payment details",
      "en" : "Payment details"
    },
    "url" : {
      "fi" : "http://www.hsl.fi",
      "sv" : "http://www.hsl.fi",
      "en" : "http://www.hsl.fi"
    },
    "paymentMethods" : [ ]
  },
  "openingHours" : {
    "openNow" : false,
    "byDayType" : {
      "SATURDAY" : {
        "from" : "08",
        "until" : "18"
      },
      "SUNDAY" : {
        "from" : "08",
        "until" : "18"
      }
    },
    "liipyByDayType" : {
      "SATURDAY" : {
        "from" : "08",
        "until" : "18"
      },
      "SUNDAY" : {
        "from" : "08",
        "until" : "18"
      }
    },
    "info" : {
      "fi" : "Opening Hours",
      "sv" : "Opening Hours",
      "en" : "Opening Hours"
    },
    "url" : {
      "fi" : "http://www.hsl.fi",
      "sv" : "http://www.hsl.fi",
      "en" : "http://www.hsl.fi"
    }
  },
  "unavailableCapacities" : [ {
    "capacityType" : "CAR",
    "usage" : "PARK_AND_RIDE",
    "capacity" : 1
  } ],
  "aliases" : [ "alias", "blias" ],
  "ports" : [ {
    "location" : {"crs":{"type":"name","properties":{"name":"EPSG:4326"}},"type":"Point","coordinates":[25.010822,60.25054]},
    "entry" : true,
    "exit" : false,
    "pedestrian" : true,
    "bicycle" : false,
    "address" : {
      "streetAddress" : {
        "fi" : "street",
        "sv" : "street",
        "en" : "street"
      },
      "postalCode" : "00100",
      "city" : {
        "fi" : "city",
        "sv" : "city",
        "en" : "city"
      }
    },
    "info" : {
      "fi" : "info",
      "sv" : "info",
      "en" : "info"
    }
  } ],
  "contacts" : {
    "emergency" : 1,
    "operator" : 2,
    "service" : 3
  },
  "softDeletedBy" : null,
  "deletedAt" : null,
  "deletedBy" : null,
  "modifiedAt" : null,
  "modifiedBy" : null
}
Path Type Description

id

Number

Facility ID: /api/v1/facilities/{id}

name

Object

Localized name

location

Object

Facility location, GeoJSON Polygon

operatorId

Number

Facility operator ID: /api/v1/operators/{operatorId}

status

String

Status, one of /api/v1/facility-statuses

pricingMethod

String

Pricing method, one of /api/v1/pricing-methods

statusDescription

Object

Localized description of status (OPTIONAL)

builtCapacity

Object

Built capacity by CapacityType, may be split or shared by different Usage types as defined by pricing

usages

Array

Read-only summary of distinct pricing rows' usages

pricing[].usage

String

Usage type, one of /api/v1/usages

pricing[].capacityType

String

Capacity type, one of /api/v1/capacity-types

pricing[].maxCapacity

Number

Max capacity

pricing[].dayType

String

Day type, one of /api/v1/day-types

pricing[].time.from

String

Start time hh[:mm]

pricing[].time.until

String

End time hh[:mm], exclusive

pricing[].price

Object

Localized description of price (OPTIONAL)

pricing[].priceExtra

Null

Description of extra price after a certain hour (OPTIONAL)

pricing[].priceOther

Null

Description of other price than Liipi (OPTIONAL)

unavailableCapacities[].capacityType

String

Unavailable capacity type

unavailableCapacities[].usage

String

Unavailable usage

unavailableCapacities[].capacity

Number

Unavailable capacity

aliases

Array

Alternative labels, list of strings

ports[].location

Object

Port location, GeoJSON Point

ports[].entry

Boolean

Entry for cars

ports[].exit

Boolean

Exit for cars

ports[].pedestrian

Boolean

Entry/exit by foot

ports[].bicycle

Boolean

Entry/exit for bicycles

ports[].address

Object

Port address (OPTIONAL)

ports[].info

Object

Localized port info (OPTIONAL)

services

Array

List of services provided, /api/v1/services

contacts.emergency

Number

Emergency contact ID, /api/v1/contacts/{contactId}

contacts.operator

Number

Operator contact ID, /api/v1/contacts/{contactId}

contacts.service

Number

Service contact ID, /api/v1/contacts/{contactId}

paymentInfo.detail

Object

Localized details of payment options (OPTIONAL)

paymentInfo.url

Object

Localized link to payment options (OPTIONAL)

paymentInfo.paymentMethods

Array

Allowed payment methods

surveyOptions

Array

Options for survey

type

String

The type of the facility. E.g. car, bicycle, car and commercial

authenticationMethods

Array

Authentication methods of the facility

openingHours.openNow

Boolean

Read-only summary of whether the facility is open right now

openingHours.byDayType

Object

Read-only summary of pricing rows' opening hours

openingHours.liipyByDayType

Object

Read-only summary of liipy type pricing rows' opening hours

openingHours.info

Object

Localized info about opening hours (OPTIONAL)

openingHours.url

Object

Localized link to opening hours info (OPTIONAL)

softDeletedAt

Datetime

Read-only timestamp of soft delete

softDeletedBy

Number

Read-only id of user who soft deleted facility

deletedAt

Datetime

Read-only timestamp of delete

deletedBy

Number

Read-only id of user who deleted facility

modifiedAt

Datetime

Read-only timestamp of last modification

modifiedBy

Number

Read-only id of user who modified facility

Status

The status of a facility indicates whether the facility is operating normally or not.

IN_OPERATION

Facility is operating normally and is open according to the regular opening hours. See the facility’s openingHours field to find out whether the facility is open right now.

INACTIVE

Facility has been decommissioned or has not yet been opened.

TEMPORARILY_CLOSED

Facility is currently closed, ignoring the opening hours, but will be opened again in near future.

EXCEPTIONAL_SITUATION

There is something exceptional happening, but the facility is still open. For example one gate or floor is closed, but the rest of the facility is working normally. See the statusDescription field for an explanation of what is happening.

Capacity

Facilities have built capacity for different types of vehicles. This capacity may be divided for different purposes (usage). At the time of writing this document, we have identified three different usage types.

PARK_AND_RIDE

Subsidized parking slots for commuters and other people to continue their travel by public transport. Not allowed for other people (e.g. visiting a nearby shop by foot). Typically free or very low cost. Example: open field next to a train station.

COMMERCIAL

Normal parking facility without restrictions for purpose of use. Normal price.

HSL_TRAVEL_CARD

This option is deprecated. Usage is set automatically to PARK_AND_RIDE when trying to save utilization with this option See Utilization.

Pricing

Park and Ride facility model supports basic pricing use cases: by capacityType, usage, dayType and time (of day). There may be limitations to maxCapacity available for different usage types when comparing to builtCapacity. There are no overlapping pricing rows and full opening hours are accounted. Time is an interval of hh[:mm] - hour of day (00-24) and optional minute (00-59). Actual prices are described as localized text, while null price means that parking is free-of-charge. Additional pricing details may be found following paymentInfo.url (localized) link or as text from paymentInfo.detail field.

As there are many free 24 hours a day, 7 days a week parking facilities near public transportation hubs, there exists a short cut for that: pricingMethod with value PARK_AND_RIDE_247_FREE. However, even in this case all implied pricing rows are accounted for all specified buildCapacity types.

Unavailable Capacity

Temporarily unavailable capacity is defined in unavailableCapacities with at most one entry for capacityType-usage pair. This should be discounted from pricing[].maxCapacity.

Note
This information is mainly useful for facilities from which there is no dynamic utilization information available. Otherwise one should refer to utilization and prediction.

Utilization

If available, the latest known number of available parking places is reported.

GET /api/v1/facilities/1/utilization HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json

[ {
  "facilityId" : 1,
  "capacityType" : "CAR",
  "usage" : "PARK_AND_RIDE",
  "timestamp" : "2022-04-25T15:10:56.318+03:00",
  "spacesAvailable" : 30,
  "capacity" : 50,
  "openNow" : false
} ]
Path Type Description

[]facilityId

Number

The facility

[]capacityType

String

The capacity type

[]usage

String

The usage

[]timestamp

String

When this information was last updated

[]spacesAvailable

Number

Number of available parking spaces for this facility, capacity type and usage combination

[]capacity

Number

Number of parking spaces (both reserved and available) for this facility, capacity type and usage combination

[]openNow

Boolean

Boolean, true if facility is currently open for given capacityType and usage

A single facility may contain many different capacity type and usage combinations. This API will show all distinct combinations which have utilization data and which are listed in the facility’s pricing field.

GET /api/v1/facilities/1/utilization HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json

[ {
  "facilityId" : 1,
  "capacityType" : "CAR",
  "usage" : "PARK_AND_RIDE",
  "timestamp" : "2022-04-25T15:10:56.318+03:00",
  "spacesAvailable" : 351,
  "capacity" : 400,
  "openNow" : true
}, {
  "facilityId" : 1,
  "capacityType" : "CAR",
  "usage" : "COMMERCIAL",
  "timestamp" : "2022-04-25T15:10:56.318+03:00",
  "spacesAvailable" : 786,
  "capacity" : 800,
  "openNow" : true
} ]

There is also an API for retrieving the latest utilization for all facilities with one request.

GET /api/v1/utilizations HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json

[ {
  "facilityId" : 1,
  "capacityType" : "CAR",
  "usage" : "PARK_AND_RIDE",
  "timestamp" : "2022-04-25T15:10:56.318+03:00",
  "spacesAvailable" : 30,
  "capacity" : 50,
  "openNow" : false
}, {
  "facilityId" : 2,
  "capacityType" : "CAR",
  "usage" : "PARK_AND_RIDE",
  "timestamp" : "2022-04-25T15:10:56.318+03:00",
  "spacesAvailable" : 30,
  "capacity" : 50,
  "openNow" : false
} ]

Updating

Authenticated operators may update the utilization for their facilities.

In case of network failure, the updater should keep a copy of the utilization snapshots and retry sending them later. It is possible to batch insert multiple utilization snapshots with a single request per facility; just have multiple objects inside the request payload’s top-level JSON array.

The API allows inputting also old utilization data, but to avoid prediction hiccups, the utilization should be inputted in timestamp order, oldest first. Utilizations with future timestamps are not allowed. The timestamps must be in ISO 8601 date time format, with timezone. The Authorization and Content-Type headers are required. The response reports the latest utilization, same as with a GET request.

$ curl 'https://p.hsl.fi/api/v1/facilities/1/utilization' -i -X PUT \
    -H 'Content-Type: application/json' \
    -H 'Authorization: Bearer P|1|1651752668013|_YygUFpE6DHaQE-8dgT_aU_dhpvUfIki5e17IvTfud8' \
    -d '[ {
  "capacityType" : "CAR",
  "usage" : "PARK_AND_RIDE",
  "timestamp" : "2022-04-25T15:10:56.318+03:00",
  "spacesAvailable" : 30,
  "capacity" : 50
} ]'
PUT /api/v1/facilities/1/utilization HTTP/1.1
Content-Type: application/json
Authorization: Bearer P|1|1651752668013|_YygUFpE6DHaQE-8dgT_aU_dhpvUfIki5e17IvTfud8

[ {
  "capacityType" : "CAR",
  "usage" : "PARK_AND_RIDE",
  "timestamp" : "2022-04-25T15:10:56.318+03:00",
  "spacesAvailable" : 30,
  "capacity" : 50
} ]
HTTP/1.1 200 OK
Content-Type: application/json

[ {
  "facilityId" : 1,
  "capacityType" : "CAR",
  "usage" : "PARK_AND_RIDE",
  "timestamp" : "2022-04-25T15:10:56.318+03:00",
  "spacesAvailable" : 30,
  "capacity" : 50
} ]

Example of updating the utilization of multiple usage types within the same facility:

PUT /api/v1/facilities/1/utilization HTTP/1.1
Content-Type: application/json
Authorization: Bearer P|1|1651752667033|cG1HVN2jQdhwNAwKdRVgrdw2eLCx52K5cB-d7xMa1DY

[ {
  "capacityType" : "CAR",
  "usage" : "PARK_AND_RIDE",
  "timestamp" : "2022-04-25T15:10:56.318+03:00",
  "spacesAvailable" : 351,
  "capacity" : 400
}, {
  "capacityType" : "CAR",
  "usage" : "COMMERCIAL",
  "timestamp" : "2022-04-25T15:10:56.318+03:00",
  "spacesAvailable" : 786,
  "capacity" : 800
} ]

Prediction

Utilization predictions are available for all facilities which have enough utilization data history. The predictions are updated at regular intervals (e.g. 5 min) and they are available for up to 24 hours into the future. It is possible to query predictions using relative time (after parameter in hh:mm format or in minutes) or absolute time (at parameter in ISO 8601 date time format).

GET /api/v1/facilities/1/prediction?after=01:30 HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json

[ ]
GET /api/v1/facilities/1/prediction?after=90 HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json

[ ]
GET /api/v1/facilities/1/prediction?at=2022-04-25T16:40:56.318+03:00&at=2022-04-25T16%3A40%3A56.318%2B03%3A00 HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json

[ ]

Facility GeoJSON Example

GeoJSON of a single facility contains only basic information of a facility, not full details:

$ curl 'https://p.hsl.fi/api/v1/facilities/1.geojson' -i -X GET
HTTP/1.1 200 OK
Content-Type: application/vnd.geo+json;charset=UTF-8

{
  "id" : 1,
  "geometry" : {"crs":{"type":"name","properties":{"name":"EPSG:4326"}},"bbox":[25.010822,60.250023,25.012479,60.250885],"type":"Polygon","coordinates":[[[25.010822,60.25054],[25.010822,60.250023],[25.012479,60.250337],[25.011449,60.250885],[25.010822,60.25054]]]},
  "properties" : {
    "name" : {
      "fi" : "Facility 0498",
      "sv" : "Facility 0498",
      "en" : "Facility 0498"
    },
    "status" : "EXCEPTIONAL_SITUATION",
    "operatorId" : 1,
    "builtCapacity" : {
      "ELECTRIC_CAR" : 2,
      "CAR" : 50
    },
    "usages" : [ "PARK_AND_RIDE" ],
    "statusDescription" : {
      "fi" : "Status description",
      "sv" : "Status description",
      "en" : "Status description"
    }
  },
  "type" : "Feature"
}

GeoJSON FeatureCollection of facilities:

$ curl 'https://p.hsl.fi/api/v1/facilities.geojson' -i -X GET
HTTP/1.1 200 OK
Content-Type: application/vnd.geo+json;charset=UTF-8

{
  "hasMore" : false,
  "features" : [ {
    "id" : 1,
    "geometry" : {"crs":{"type":"name","properties":{"name":"EPSG:4326"}},"bbox":[25.010822,60.250023,25.012479,60.250885],"type":"Polygon","coordinates":[[[25.010822,60.25054],[25.010822,60.250023],[25.012479,60.250337],[25.011449,60.250885],[25.010822,60.25054]]]},
    "properties" : {
      "name" : {
        "fi" : "Facility 0483",
        "sv" : "Facility 0483",
        "en" : "Facility 0483"
      },
      "status" : "EXCEPTIONAL_SITUATION",
      "operatorId" : 1,
      "builtCapacity" : {
        "ELECTRIC_CAR" : 2,
        "CAR" : 50
      },
      "usages" : [ "PARK_AND_RIDE" ],
      "statusDescription" : {
        "fi" : "Status description",
        "sv" : "Status description",
        "en" : "Status description"
      }
    },
    "type" : "Feature"
  } ],
  "type" : "FeatureCollection"
}

Hubs

Public transportation hubs are places where trains, buses, cars and bicycles converge. From a hub one may continue to all places reachable via public transportation. Hubs are named and defined as a location with optional address as well as a list of facilityIds that refer to parking facilities that are easily reachable from the hub. Basic information of those facilities may be searched from the facilities resource using the ids parameter, or by querying for details of each facility separately.

GET /api/v1/hubs HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json

{
  "results" : [ {
    "id" : 1,
    "name" : {
      "fi" : "Malmi",
      "sv" : "Malmi",
      "en" : "Malmi"
    },
    "location" : {"crs":{"type":"name","properties":{"name":"EPSG:4326"}},"type":"Point","coordinates":[25.010563,60.251022]},
    "facilityIds" : [ ],
    "address" : {
      "streetAddress" : {
        "fi" : "street",
        "sv" : "street",
        "en" : "street"
      },
      "postalCode" : "00100",
      "city" : {
        "fi" : "city",
        "sv" : "city",
        "en" : "city"
      }
    },
    "modifiedAt" : null,
    "modifiedBy" : null
  } ],
  "hasMore" : false
}

Hubs may be searched by (hub) ids, facilityIds and geometry within optional maxDistance. Spatial Search of hubs works similarly to facilities.

GET /api/v1/hubs?ids=11&ids=12 HTTP/1.1
GET /api/v1/hubs?facilityIds=11&facilityIds=12 HTTP/1.1
GET /api/v1/hubs?geometry=POLYGON((25.011942+60.251343,25.011717+60.250454,25.013487+60.250848,25.011942+60.251343)) HTTP/1.1
GET /api/v1/hubs?geometry=POLYGON((25.011942+60.251343,25.011717+60.250454,25.013487+60.250848,25.011942+60.251343))&maxDistance=123.45 HTTP/1.1

Hub Details

At the time of writing this document there is no structural difference between individual hub resource (hubs/123) and an item in hubs collection resource.

GET /api/v1/hubs/1 HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json

{
  "id" : 1,
  "name" : {
    "fi" : "Malmi",
    "sv" : "Malmi",
    "en" : "Malmi"
  },
  "location" : {"crs":{"type":"name","properties":{"name":"EPSG:4326"}},"type":"Point","coordinates":[25.010563,60.251022]},
  "facilityIds" : [ ],
  "address" : {
    "streetAddress" : {
      "fi" : "street",
      "sv" : "street",
      "en" : "street"
    },
    "postalCode" : "00100",
    "city" : {
      "fi" : "city",
      "sv" : "city",
      "en" : "city"
    }
  },
  "modifiedAt" : null,
  "modifiedBy" : null
}

Hub GeoJSON Example

GeoJSON of a single hub:

$ curl 'https://p.hsl.fi/api/v1/hubs/1.geojson' -i -X GET
HTTP/1.1 200 OK
Content-Type: application/vnd.geo+json;charset=UTF-8

{
  "id" : 1,
  "geometry" : {"crs":{"type":"name","properties":{"name":"EPSG:4326"}},"type":"Point","coordinates":[25.010563,60.251022]},
  "properties" : {
    "name" : {
      "fi" : "Malmi",
      "sv" : "Malmi",
      "en" : "Malmi"
    },
    "facilityIds" : [ ]
  },
  "type" : "Feature"
}

GeoJSON FeatureCollection of hubs:

$ curl 'https://p.hsl.fi/api/v1/hubs' -i -X GET \
    -H 'Accept: application/vnd.geo+json;charset=UTF-8'
HTTP/1.1 200 OK
Content-Type: application/vnd.geo+json;charset=UTF-8

{
  "hasMore" : false,
  "features" : [ {
    "id" : 1,
    "geometry" : {"crs":{"type":"name","properties":{"name":"EPSG:4326"}},"type":"Point","coordinates":[25.010563,60.251022]},
    "properties" : {
      "name" : {
        "fi" : "Malmi",
        "sv" : "Malmi",
        "en" : "Malmi"
      },
      "facilityIds" : [ ]
    },
    "type" : "Feature"
  } ],
  "type" : "FeatureCollection"
}

Summary of Hub Model

Path Type Description

id

Number

Hub ID: /api/v1/hubs/{id}

name

Object

Localized name

location

Object

Hub location, GeoJSON Point

address

Object

Hub address (OPTIONAL)

address.streetAddress

Object

Localized street name (OPTIONAL)

address.postalCode

String

Postal code (OPTIONAL)

address.city

Object

Localized city name (OPTIONAL)

facilityIds

Array

A list of facility IDs (number), /api/v1/facilities/{id}

modifiedAt

Datetime

Read-only timestamp of last modification

modifiedBy

Number

Read-only id of user who modified hub

Prediction

Utilization predictions are available for all hubs which have facilities with enough utilization data history. The hubs' predictions are simply sums of the related facilities' predictions.

GET /api/v1/hubs/1/prediction?after=01:30 HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json

[ ]
GET /api/v1/hubs/1/prediction?after=90 HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json

[ ]
GET /api/v1/hubs/1/prediction?at=2022-04-25T16:40:56.318+03:00&at=2022-04-25T16%3A40%3A56.318%2B03%3A00 HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json

[ ]

Use-Case Examples

Park and Ride With a Navigator

A navigation app may search for hubs within maxDistance of 1000 m of the selected route. A route is defined as a LineString geometry which is in essence just a list of coorinates. From the result a list of recommended facilities may be extracted and then prediction of spaces available at the estimated arrival time.

© Copyright HSL