MOIA API
API Endpoint
https://api.moia.io
Endpoint for Testing
https://api-sandbox.moia.io
MOIA provides an API to easily integrate our services with other apps. This pages guides you through our endpoints and how to use them.
Public Endpoints
The following endpoints are public and can be used by anyone. They are, however, throttled. If you plan to use them for production purposes, please contact us for an API Key.
/estimate
to receive an estimate time to arrival and price range/pickup-estimate
to receive an estimate time of when a customer can be picked up
Closed Endpoints
The following endpoints are for partners who use our service with their own user pool:
/auth
for authentication as tenant or customer/customer
to create new customers/serviceareas
for information about the service areas/servicehours
to request the service hours for a specific service area/trip
to plan, book and cancel a trip and to give feedback/webhook
for updates about vehicle location and customer interaction
The API is organized around REST. Our API has predictable, resource-oriented URLs, and uses HTTP response codes to indicate API errors. We use built-in HTTP features, like HTTP media types and HTTP verbs, which are understood by off-the-shelf HTTP clients.
Most endpoints support Protobuf and JSON as content types. You can find the current protobuf files at github.com/moia-dev/api.
Each resource has its own release cycle and can therefore have its own content-type-version.
Change Log
Changes to this document will be listed here.
Date | Change |
---|---|
2018-12-11 | Update Error Codes. |
2019-07-01 | Update /serviceareas to Version 2. |
2019-07-01 | Remove /trip/inquiry endpoint. |
2019-07-01 | Add Events v2, deprecate v1. |
2019-07-10 | Update Error Codes. |
2019-07-11 | Update /offer response: fix offerSignature , add priceMetadata , add destination . |
2019-07-12 | Add docs for /trip/last endpoint. |
2019-07-16 | Remove traceId from events. |
2019-07-22 | Remove paymentNonce and couponInformation (internal APIs). |
2019-09-20 | Add documentation for the DIRECT_WALK_IS_FASTER error code. |
2019-09-20 | Remove documentation for the deprecated feedback error codes. |
2019-11-18 | Added estimate-endpoint. |
2019-12-10 | Add estimatedVehicleArrival to estimate-endpoint response. |
2019-12-10 | Move error codes into their respective endpoint documentation and add errors to estimate-endpoint. |
2020-01-13 | Add estimateId to estimate-endpoint response. |
2020-01-22 | Add etaAvg to estimate-endpoint response. |
2020-03-02 | Add retry behavior of payment related events and improve description for the fields of payment related events. |
2020-05-25 | Add TRIP_COMMITTED , TRIP_REJECTED , PICKUP_STOP_FIXED , DELIVERY_STOP_FIXED and VEHICLE_FIXED event preview. |
2020-05-29 | Add preview of v6 of /trip/ endpoints. |
2020-06-23 | Restructure /offer response and /order input. |
2020-07-06 | Add stop.walkingDuration and stop.walkingDistance to PICKUP_STOP_FIXED and DELIVERY_STOP_FIXED. |
2020-07-06 | Add CUSTOMER_NOT_SHOWN and SERVICE_ABORTED events that are to replace TRIP_CANCELED_BY_HUB and TRIP_CANCELED_CUSTOMER_NOT_SHOWN respectively. |
2020-07-15 | Fix the supported json media type for calls to the /trip endpoint. |
2020-08-13 | Add offers.id , change tripRequest.walkingDuration , rename guaranteedPrice to signedPrice , rename selectedOffer to offer and updated error codes for v6 /trip/offer and /trip/order . |
2020-08-14 | Add error codes to /cancel endpoint for v6. |
2020-09-23 | Add OrderTripError.Code.CODE_DISPATCHING_ERROR and remove /trip/last endpoint for v6. |
2020-09-29 | Remove CODE_SAME_PICKUP_AND_DELIVERY_STOP from TripRequest errors for v6. |
2020-10-09 | Rename CODE_DIRECT_WALK_IS_FASTER to CODE_WALK_IS_FASTER from TripRequest errors for v6. |
2020-10-29 | Remove /trip/last endpoint. |
2020-12-04 | Add CODE_KILL_SWITCH_ACTIVE to errors for requests to trip/offer and trip/order . |
2021-02-09 | Remove v5 of /trip/ endpoints. |
2021-02-10 | Add v7 of /trip/offer/ and /trip/order/ endpoints. |
2021-03-25 | Remove v6 of /trip/offer/ and /trip/order/ endpoints. |
2021-04-20 | Add v1 of pickup-estimate endpoint. |
2022-04-29 | Remove TRIP_CANCELED_BY_HUB and TRIP_CANCELED_CUSTOMER_NOT_SHOWN events. |
2022-09-20 | Enhance documentation for estimate , /trip/offer/ and /trip/order/ for wheelchair support. |
2023-06-15 | Refine wording for TRIP_COMMITTED and VEHICLE_FIXED event description. |
2023-10-13 | Add price parts to offers. Add offer metadata field. Deprecate price metadata. |
2023-11-16 | Add a description field to the price parts. |
2024-02-09 | Deprecate disjoint offer lists in favour of the new allOffers in /trip/offer . Add Express offers. |
Media Types
The following media types are supported by all endpoints (with varying versions):
application/json
application/vnd.moia+json
application/vnd.moia.v1+json
The /trip
endpoint additionally supports
application/x-protobuf
application/vnd.moia+x-protobuf
application/vnd.moia.v7+x-protobuf
It is recommended to declare one of the supported media types as part of the Accept
header. The response body will be returned accordingly. If no Accept
header is specified, the latest Protobuf version will be returned. More information about versioning is described in the section Versioning.
If the HTTP request contains payload in the body, the Content-Type
header needs to be set as well. Otherwise, a 415 Unsupported Media Type
is returned.
Versioning
To enable a strong versioning scheme for HTTP, MOIA uses vendor-specific media types. A good explanation of this can be found here.
With a media type, the client can query a specific version of the content from a server. It defines the expected major version via the Accept
header. If the media type does not include a version, e.g. application/json
, the latest major version is assumed.
MOIA uses a major.minor
version concept which is best explained in the following example.
Example Request: Version 1.0
curl https://api.moia.io/customer \
-H "accept: application/vnd.moia.v1+json"
Example Response: Version 1.0
{
"id": "123",
"email": "max@mustermann.de",
"name": "Max Mustermann"
}
Let’s assume an HTTP endpoint to retrieve customer information. The endpoint in version 1.0 has declared the fields id
, email
and name
.
On the right you can see that only the major version is specified in the Accept
header.
Now, let’s assume the server updates the version to 1.1 by adding the field phones
. The Accept
header application/vnd.moia.v1+json
will now return the new field phones
as well:
Example Response: Version 1.1
{
"id": "123",
"email": "max@mustermann.de",
"name": "Max Mustermann",
"phones": [
{
"number": "+12345",
"type": "Mobile"
}
]
}
In other words, the Accept
header specifies the major version of the response, not the minor version. The server will always return the latest minor version. Minor version are compatible with each other. In our example, if the client only understands version 1.0 and the server replies with version 1.1, the client parser will ignore the phones
field.
Versioning support
The design has some important consequences. The client that uses the MOIA API:
- Defines the major version it understands
- Decides when it uses a newer major version
This means that MOIA will support multiple major versions. Once a version is introduced, it will be supported for 6 months.
Errors
MOIA uses conventional HTTP response codes to indicate the success or failure of an API request. In general: Codes in the 2xx
range indicate success. Codes in the 4xx
range indicate an error that failed given the information provided, e.g. a required parameter was omitted. Codes in the 5xx
range indicate an error with MOIA’s servers.
Dispatching Error (status code 400)
{
"code": "DISPATCHING_ERROR",
"message": "We failed to find a vehicle to fulfil the offer or order request."
}
Malformed request (status code 400)
The request content was malformed:
Entity could not be unmarshalled.
Unauthorized request (status code 401)
{
"message": "Unauthorized"
}
Resource not found (status code 404)
The requested resource could not be found.
Missing field in request (status code 422)
{
"errors": [
{
"path": "/destination",
"message": "Value is required."
}
]
}
Unsupported Media Type (status code 415)
The request's Content-Type is not supported. Expected:
application/vnd.moia.v5.0+json or application/json or
application/vnd.moia+x-protobuf or application/x-protobuf or
application/vnd.moia+json or application/vnd.moia.v5.0+x-protobuf
Code | Description | |
---|---|---|
200 | OK | Everything worked as expected. |
400 | BadRequest | The request is malformed or cannot be fulfilled, e.g. - no vehicle is available, - a service area cannot be resolved, - an offer expired. |
401 | Unauthorized | The Moia-Auth header is empty or the provided API key is not valid. |
404 | Not Found | The requested resource doesn’t exist. |
415 | Unsupported Media Type | The Content-Type for the request payload is either not set or not supported. |
422 | Unprocessable Entity | The server cannot process the request due to an apparent client error (e.g., field is missing in the request, a field value is negative but only positive numbers are allowed). |
429 | Too Many Requests | Too many requests hit the API too quickly. Retry again with a back-off according to the Retry-After response header. |
503 | Service Unavailable | The service is not available for the short time. Retry again with a back-off according to the Retry-After response header if present or exponentially otherwise. |
500, 502, 504 | Server Errors | Something went wrong on MOIA’s end. |
The payload is formatted differently for different errors.
400 BadRequest
errors either indicate a malformed payload (see second example) or include an error code, e.g. DISPATCHING_ERROR
, so that these errors can be handled programmatically. For a list of possible error codes, see the chapters for specific endpoints below.
401 Unauthorized
errors include a message.
422 Unprocessable Entity
errors include an error list. Each error object contains a path
and message
to indicate which field in the request body could not be processed. Note that this list might not be exhaustive.
Error Codes
We try to return helpful error codes that can be handled programmatically. Every route lists its possible error codes in the respective documentation.
/estimate
POST https://api.moia.io/estimate
Supported Versions
application/x-protobuf
application/vnd.moia+x-protobuf
application/vnd.moia.v1+x-protobuf
application/json
application/vnd.moia+json
application/vnd.moia.v1+json
This endpoint takes two coordinates, origin
and destination
, and returns the estimated range of minutes it takes a MOIA to go from origin
to destination
and the estimated vehicle arrival time. An optional boolean parameter wheelchairAccessible
can be set to true if estimates are for wheelchair accessible vehicles. It also returns an estimation for the current price and a link which will let the user open the MOIA app with prefilled coordinates. If the MOIA app is not installed, the user will be led to the Apple App Store or Google Play Store respectively. If you use an API Key, the link contains information to track the conversion from your service.
Request
Example Request
curl --request POST \
--url https://api.moia.io/estimate/ \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--header 'x-api-key: public' \
--data '{
"origin": {
"lat": 53.549576,
"lon": 9.962196
},
"destination": {
"lat": 53.552679,
"lon": 10.006687
},
"wheelchairAccessible": false
}'
Field Name | Description |
---|---|
origin required |
The starting point, as latitude and longitude. |
destination required |
The destination, as latitude and longitude. |
wheelchairAccessible optional |
Boolean indicating if the estimate is for a wheelchair accesible vehicle. Default: false |
Response
Example Response
{
"etaMin": 16,
"etaAvg": 20,
"etaMax": 25,
"estimatedVehicleArrival": 5,
"price": {
"amountMin": "5.00",
"amountMax": "6.00",
"currency": "EUR"
},
"deepLink": "https://www.moia.io/de-DE/app/tripPreferences?id=public_6a0ade94-e4db-4f2e-913e-bf90b9988565&origin_lat=53.549576&origin_lng=9.962196&dest_lat=53.552679&dest_lng=10.006687",
"estimateId": "public_6a0ade94-e4db-4f2e-913e-bf90b9988565"
}
Field Name | Description |
---|---|
etaMin / etaMax |
Minimum / maximum amount of minutes until delivery, starting from now. |
etaAvg |
A weighted average of the etaMin and etaMax. Showing etaMin and etaMax is strongly preferred! |
estimatedVehicleArrival |
Estimated amount of minutes until vehicle arrival, starting from now. |
price |
Lower and upper bound for the current price for this trip, rounded to full euros. |
deepLink |
A link to open the prefilled MOIA app on iOS or Android. |
estimateId |
Unique identifier of the estimate. |
Errors
See Errors for the general error strategy of the api. The following types of error codes can be returned from this route.
Error Code | Description |
---|---|
GENERAL_ERROR | An internal, technical error occurred. |
NOT_WITHIN_SERVICE_AREA | The requested location is not inside a known service area. |
NOT_WITHIN_SERVICE_HOURS | The requested ride time is not within the service hours. |
WHEELCHAIR_ACCESSIBLE_SERVICE_NOT_AVAILABLE | A wheelchair accessible service is not available in this service area. |
API Key
Note that while this endpoint is public, it is throttled. If you intend to use it for production use cases, please contact us for an API Key to send as x-api-key
header.
Response time
You can expect an average response time of 200ms, and peaks of up to 400ms for some requests.
Example
We have provided an example application at https://moia-dev.github.io/trip-estimate-example/. You can find the code at https://github.com/moia-dev/trip-estimate-example.
/pickup-estimate
POST https://api.moia.io/pickup-estimate
Supported Versions
application/x-protobuf
application/vnd.moia+x-protobuf
application/vnd.moia.v1+x-protobuf
application/json
application/vnd.moia+json
application/vnd.moia.v1+json
This endpoint takes a coordinate pair, lat
and lon
, of a customer location and returns the estimated number of minutes until a customer can be picked up.
Request
Example Request
curl --request POST \
--url https://api.moia.io/pickup-estimate/ \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--header 'x-api-key: public' \
--data '{
"lat": 53.549576,
"lon": 9.962196
}'
Field Name | Description |
---|---|
lat required |
The latitude of the starting location. |
lon required |
The longitude of the starting location. |
Response
Example Response
{
"minutes": 5
}
Field Name | Description |
---|---|
minutes |
Estimated number of minutes until the pickup. |
Errors
See Errors for the general error strategy of the api. The following types of error codes can be returned from this route.
Error Code | Description |
---|---|
GENERAL_ERROR | An internal, technical error occurred. |
NOT_WITHIN_SERVICE_AREA | The requested location is not inside a known service area. |
NOT_WITHIN_SERVICE_HOURS | The request is not within the service hours. |
API Key
Note that while this endpoint is public, it is throttled. If you intend to use it for production use cases, please contact us for an API Key to send as x-api-key
header.
Response time
You can expect an average response time of 200ms, and peaks of up to 400ms for some requests.
/auth
Supported Versions
application/json
application/vnd.moia+json
application/vnd.moia.v1+json
All calls to our API require a valid token in the Moia-Auth
header. There are two kinds of tokens: general client_credentials
-tokens which allow actions such as
- creating customers,
- requesting service areas and service hours,
- requesting an offer for a trip
- registering a web hook to receive update-events
and customer-specific tokens which can be used to
- request an offer for a trip,
- order a trip,
- cancel a trip,
- give feedback for a trip,
- load the last trip.
To receive a token, you need to send a POST
request to https://api.moia.io/auth/token
that includes your Partner API credentials as HTTP basic access authorization header and the requested grant_type
as payload.
All API requests must be made over HTTPS. Calls made over plain HTTP will fail. API requests without authentication will also fail.
To retrieve partner API credentials please contact us. Do not share these credentials in publicly accessible areas such GitHub, client-side code, and so forth.
Authenticating as Client
POST https://api.moia.io/auth/token
A client can authenticate itself with the client_credentials
grant.
In this case no specific user is involved, but the client acts in a global context.
This is mainly used for account/customer management actions.
In short, the client exchanges its client id and client secret for a token.
An id token is used in our API for this flow.
This id token must be sent along in the Moia-Auth
header when using APIs in a global context.
The request must contain an HTTP basic access authorization header, with the client id as username and the client secret as password.
Request
Example Request
curl https://api.moia.io/auth/token \
-X POST \
-H "accept: application/vnd.moia+json" \
-H "content-type: application/vnd.moia+json" \
-u 'client-id:secret' \
-d '
{
"grant_type": "client_credentials"
}'
Field Name | Description |
---|---|
grant_type required |
Valid values: - client_credentials |
Response
Example Response
{
"token_type": "bearer",
"id_token": "ABCDE...",
"expires_in": 3600
}
Field Name | Description |
---|---|
id_token |
The id token for the client |
expires_in |
The remaining live time of the access token in seconds. |
token_type |
Valid values: - bearer |
Authenticating on behalf of a customer
POST https://api.moia.io/auth/token
In order to access the API in behalf of a customer, a client has to authenticate with an id token linking itself to the customer. To obtain such an id token, one can directly use the username and the password of a customer to get this token. You get these credentials when creating a new customer.
Note that the client must authenticate itself using HTTP basic access authentication with its client id as username and its client secret as password.
Request
Example Request
curl https://api.moia.io/auth/token \
-X POST \
-H "accept: application/vnd.moia.v1+json" \
-H "content-type: application/vnd.moia.v1+json" \
-u 'client-id:secret' \
-d '
{
"grant_type": "password",
"username": "f9c2a5cf-da9b-.....",
"password": "test1234"
}'
Field Name | Description |
---|---|
username required |
The MOIA account’s customer id. |
password required |
The MOIA account’s password. |
grant_type required |
Valid values: - password |
Response
Example Response
{
"token_type": "bearer",
"id_token": "ABCDE...",
"expires_in": 3600
}
Field Name | Description |
---|---|
id_token |
The id token for the current customer |
expires_in |
The remaining live time of the access token in seconds. |
token_type |
Valid values: - bearer |
/customer
Supported Versions
application/json
application/vnd.moia+json
application/vnd.moia.v1+json
The customer endpoint provides an API to programmatically create new accounts for customers as well as update customer details. All requests to the customer API require client authentication.
Create a new customer
POST https://api.moia.io/customer
This endpoint provides functionality to create a new customer.
Request
Example Request
curl https://api.moia.io/customer \
-X POST \
-H "accept: application/vnd.moia.v1+json" \
-H "content-type: application/vnd.moia.v1+json" \
-H "moia-auth: CLIENT_ID_TOKEN" \
-d '
{
"email": "test@moia.io",
"phoneNumber": "+49 172 12345678",
"firstName": "Max",
"lastName": "Mustermann",
"locale": "de"
}'
Field Name | Description |
---|---|
email required |
The MOIA customer e-mail address (has to be unique). |
phoneNumber required |
The MOIA customer phone number. |
firstName required |
The MOIA customer first name. |
lastName required |
The MOIA customer last name. |
locale required |
The MOIA customer locale. |
Response
Example Response
{
"id": "fdd3729c-118b-46c4-8dc1....",
"password": "ce5asaoYuu....."
}
Field Name | Description |
---|---|
id |
The id/username of the created customer |
password |
The password of the created customer |
Update an existing customer
PUT https://api.moia.io/customer/{customerId}
This endpoint provides functionality to update an existing customer.
Request
Example Request
curl https://api.moia.io/customer/{customerId} \
-X PUT \
-H "accept: application/vnd.moia.v1+json" \
-H "content-type: application/vnd.moia.v1+json" \
-H "moia-auth: CLIENT_ID_TOKEN" \
-d '
{
"email": "test@moia.io",
"phoneNumber": "+49 172 12345678",
"firstName": "Max",
"lastName": "Mustermann",
"locale": "de"
}'
Field Name | Description |
---|---|
email required |
The MOIA customer e-mail address. |
phoneNumber required |
The MOIA customer phone number. |
firstName required |
The MOIA customer first name. |
lastName required |
The MOIA customer last name. |
locale required |
The MOIA customer locale. |
Response
Example Response
{
"email": "test@moia.io",
"phoneNumber": "+49 172 12345678",
"firstName": "Max",
"lastName": "Mustermann",
"locale": "de"
}
Field Name | Description |
---|---|
email |
The e-mail address of the updated customer. |
phoneNumber |
The phone number of the updated customer. |
firstName |
The first name of the updated customer. |
lastName |
The last name of the updated customer. |
locale |
The locale of the updated customer. |
Get consent information
GET https://api.moia.io/customer/{customerId}/consentVersions
This endpoint provides information regarding a customer’s consent to certain conditions of use for the MOIA service. The endpoint also provides the latest available version of the terms and a link to the respective document.
(Currently this reflects Terms & Conditions)
Request
Example Request
curl https://api.moia.io/customer/{customerId}/consentVersions \
-X GET \
-H "accept: application/vnd.moia.v1+json" \
-H "content-type: application/vnd.moia.v1+json" \
-H "moia-auth: CLIENT_ID_TOKEN"
The request does not need a body.
Response
Example Response
{
"termsAndConditionsVersion": "1",
"termsAndConditionsConfirmationDate": "2018-12-03T10:29:21+0000",
"latestTermsAndConditionsVersion": "1",
"latestTermsAndConditionsCreationDate": "2018-07-02T10:48:33+0000",
"latestTermsAndConditionsContent": {
"de": "https://versions.customer.int.moia-group.io/de_tc_v_1.html",
"en": "https://versions.customer.int.moia-group.io/en_tc_v_1.html"
}
}
Field Name | Description |
---|---|
termsAndConditionsVersion |
The Terms & Conditions version that a customer has confirmed. Empty in the case that customer has not yet confirmed any version. |
termsAndConditionsConfirmationDate |
Date that the customer has confirmed this version of Terms & Conditions |
latestTermsAndConditionsVersion |
Latest available version of the MOIA Terms & Conditions |
latestTermsAndConditionsCreationDate |
Date of issue of the latest MOIA Terms & Conditions |
latestTermsAndConditionsContent |
Map containing links to localized texts of latest Terms & Conditions with locale as key |
Confirm “Terms & Conditions”
PUT https://api.moia.io/customer/{customerId}/confirmTermsAndConditions
Customers have to confirm to MOIAs Terms & Conditions to access the provided service. Use this endpoint to submit the version that a customer has confirmed.
Request
Example Request
curl https://api.moia.io/customer/{customerId}/confirmTermsAndConditions \
-X PUT \
-H "accept: application/vnd.moia.v1+json" \
-H "content-type: application/vnd.moia.v1+json" \
-H "moia-auth: CLIENT_ID_TOKEN" \
-d '
{
"version": "1"
}'
Field Name | Description |
---|---|
version |
The version of Terms & Conditions the customer confirmed. |
Response
Example Response
{
"version": "1",
"confirmationDate": "2018-12-03T10:29:21+0000"
}
Field Name | Description |
---|---|
version |
The version of Terms & Conditions the customer confirmed. |
confirmationDate |
Date of customer’s confirmation to this version. |
/serviceareas
Supported Versions
application/json
application/vnd.moia+json
application/vnd.moia.v1+json
application/x-protobuf
application/vnd.moia+x-protobuf
application/vnd.moia.v1+x-protobuf
The serviceareas
endpoint provides the list of service areas you have access to.
Carefully notice that each service area has a unique id
and a specific validFrom
from which the service area is valid.
Moreover, a service area can have multiple versions - identified by their version.versionId
- but only 1 will ever be published/activated/released at a time.
By storing the versionId
, one can quickly find out if this service area differs, without looking at the individual attributes.
Requests to this endpoint require client authentication.
Example Request
curl https://api.moia.io/serviceareas \
-X GET \
-H "accept: application/json" \
-H "moia-auth: CLIENT_ID_TOKEN"
Response
Example Response
{
"serviceAreas": [
{
"id": "de-hamburg-01",
"legacyUuid": "f89ee35c-10ff-4d3b-959e-07d2e7637119",
"version": {
"versionId": "1561375291637",
"versionLabel": "draft-1",
"publishedDate": "2019-06-24T11:21:31.835807Z"
},
"locationAttributes": {
"area": {
"locations": [
{
"lat": 52.340704,
"lon": 9.756997
},
{
"lat": 52.341027,
"lon": 9.761054
},
{
"lat": 52.343193,
"lon": 9.775219
}
]
},
"topLeft": {
"lat": 53.69651479,
"lon": 9.71578068
},
"bottomRight": {
"lat": 52.34,
"lon": 10.2685932
},
"timeZone": "Europe/Berlin",
"city": "Hamburg",
"country": "DE"
},
"created": "2019-06-24T11:21:31.637311Z",
"modified": "2019-06-24T11:21:31.835807Z",
"validFrom": "2019-06-24T11:21:41.352591Z",
"defaultLanguage": "de",
"displayNames": {
"de": "Hamburg",
"en": "Hamburg"
},
"serviceParameters": {
"maxSeats": 6,
"childSeats": 1,
"wheelchairSeats": 1
}
}
]
}
Field Name | Description |
---|---|
id |
Unique identifier of a service area, in human-readable format. |
legacyUuid |
Legacy Unique identifier of a service area, in UUID format. |
version |
Service areas can have multiple versions, where only one is exclusively activate. |
locationAttributes |
Location of the service area. |
created |
Service area creation date. |
modified |
Service area last modified date. |
validFrom |
Date when the service area is valid from. |
defaultLanguage |
Service Area default language. |
displayNames |
List of Service Area names in different locales. Currently only de and en are supported. |
serviceParameters |
Different parameters for the service area. |
Version
Field Name | Description |
---|---|
versionId |
Id of the service area version, A number that increases in a non-iterative order. |
versionLabel |
Label or name of the service area version, enter by a person. |
publishedDate |
When this version was published/activated/released. Date format is UTC . |
locationAttributes
Field Name | Description |
---|---|
area |
Polygon with an array of points (lat and lon) delineating the exact boundaries of the service area. |
topLeft bottomRight |
Latitude and Longitude of rectangle that surrounds the service area. The boundaries of the service area are all contained inside this rectangle. |
timeZone |
Timezone of location where the service area is, in accordance with the tz database. |
city |
City where the service area is, written in English. |
country |
Country where the service area is, written in English. |
serviceParameters
Field Name | Description |
---|---|
maxSeats |
Max number of seats that can be booked in a vehicle operating inside this service area. |
childSeats |
Max number of child seats that can be booked in a vehicle operating inside this service area. |
wheelchairSeats |
Max number of wheel chair seats that can be booked in a vehicle operating inside this service area. |
/servicehours
Supported Versions
application/json
application/vnd.moia+json
application/vnd.moia.v1+json
Request
curl https://api.moia.io/servicehours/hamburg \
-X GET \
-H "accept: application/vnd.moia.v1+json" \
-H "content-type: application/vnd.moia.v1+json" \
-H "moia-auth: CLIENT_ID_TOKEN"
The servicehours
endpoint provides the service hours for the specified service area.
Requests to this endpoint requires client authentication.
/trip
A trip represents the customer journey from booking a trip, getting picked up and delivered by a vehicle and giving feedback for a trip.
The trip resource bundles HTTP calls with typical request / response cycle. For asynchronous events that are pushed to the partner backend, use the /events resource.
All endpoints require customer authentication.
/offer
POST https://api.moia.io/trip/offer
Supported Versions
application/x-protobuf
application/vnd.moia+x-protobuf
application/vnd.moia.v7+x-protobuf
application/json
application/vnd.moia+json
application/vnd.moia.v7+x-json
Make a trip offer based on origin and destination. The returned message contains one or more offers consisting of stop areas and time-windows for pickup and delivery as well as a price. One of them can be selected and used to make an order.
Request
Example Request
curl https://api.moia.io/trip/offer \
-X POST \
-H "accept: application/vnd.moia.v7+x-json" \
-H "content-type: application/vnd.moia.v7+x-json" \
-H "moia-auth: CUSTOMER_ID_TOKEN" \
-d '
{
"origin": {
"location": {
"lat": 53.554415,
"lon": 10.007321
},
"primaryAddress": "Heidi-Kabel-Platz 12",
"secondaryAddress": "20099 Hamburg, Deutschland",
"primaryPoiName": "Hamburg Hauptbahnhof",
"secondaryPoiName": "Hamburg, Deutschland"
},
"destination":{
"location":{
"lat": 53.551324,
"lon": 9.986031
},
"primaryAddress": "Stadthausbrücke 8",
"secondaryAddress": "20355 Hamburg, Deutschland",
"primaryPoiName": "MOIA Hamburg"
},
"seatInfo": {
"adults": 1,
"children": 0,
"seats": 1,
"childSeats": 0,
"boosterSeats": 0,
"wheelchairs": 0
}
}'
Field Name | Description |
---|---|
origin required |
The starting point, see Named Location. |
destination required |
The destination, see Named Location. |
seatInfo required |
The seat info, see Seat Info |
Named Location (origin & destination)
The origin
and destination
message contains the following attributes:
Field Name | Description |
---|---|
location required |
The latitude and longitude of the starting point. Selection of the nearest stop is based on this. |
primaryAddress required |
Street name. This is not used by the backend but will be returned in the response-object. |
secondaryAddress optional |
City name. This is not used by the backend but will be returned in the response-object. |
primaryPoiName optional |
Place of interest. This is not used by the backend but will be returned in the response-object. |
secondaryPoiName optional |
Place of interest. This is not used by the backend but will be returned in the response-object. |
Seat Info
The seatInfo
message contains the following attributes:
Field Name | Description |
---|---|
adults required |
The number of adults (aged 15 or older). |
children required |
The number of children (younger than 15). |
seats required |
The total number of seats required, includes childSeats , boosterSeats , and wheelchairs . |
childSeats optional |
The number of child seats (child 9-36kg). |
boosterSeats optional |
The number of booster seats (child >125cm / >22kg). |
wheelchairs optional |
The number of wheelchairs. |
For example, a request for one adult with a wheelchair would have the following seatInfo
:
{
"seatInfo": {
"adults": 1,
"children": 0,
"seats": 1,
"childSeats": 0,
"boosterSeats": 0,
"wheelchairs": 1
}
}
Response
Example Response
{
"tripRequest": {
"tripId": "db6260fa-23e7-49c5-9dfb-df8cc25e2435",
"serviceAreaUuid": "f89ee35c-10ff-4d3b-959e-07d2e7637119",
"origin": {
"location": {
"lat": 53.554415,
"lon": 10.007321
},
"primaryAddress": "Heidi-Kabel-Platz 12",
"secondaryAddress": "20099 Hamburg, Deutschland"
},
"destination": {
"location": {
"lat": 53.551324,
"lon": 9.986031
},
"primaryAddress": "Stadthausbrücke 8",
"secondaryAddress": "20355 Hamburg, Deutschland"
},
"seatInfo": {
"adults": 1,
"children": 1,
"seats": 2,
"childSeats": 0,
"boosterSeats": 0,
"wheelchairs": 0
},
"requestTime": "2024-02-09T08:33:57.66Z"
},
"offers": [
{
"id": "09040572-34be-4cca-9fa4-38606be8a55b",
"pickupArea": {
"centerPoint": {
"lat": 53.554415,
"lon": 10.007321
},
"radius": 209,
"walkingDuration": {
"durationRange": {
"minutesMin": 1,
"minutesMax": 4
}
}
},
"deliveryArea": {
"centerPoint": {
"lat": 53.551324,
"lon": 9.986031
},
"radius": 345,
"walkingDuration": {
"singleDuration": {
"minutes": 3
}
}
},
"pickupTimeRange": {
"start": "2024-02-09T08:43:57.775Z",
"end": "2024-02-09T08:53:57.775Z"
},
"deliveryTimeRange": {
"start": "2024-02-09T08:57:42.775Z",
"end": "2024-02-09T09:07:27.788Z"
},
"signedPrice": {
"price": {
"amount": "10.30",
"currency": "EUR"
},
"signature": "763383308658400b6c5df5c2dc1454abc1de7d1951e30b798b268a95e09240e7",
"priceParts": [
{
"type": "PRICE_TYPE_BASE_FEE",
"price": {
"amount": "4.00",
"currency": "EUR"
},
"isDiscount": false,
"description": {
"en": {
"header": "Base price for 1 adult",
"text": ""
},
"de": {
"header": "Basispreis für 1 Erwachsenen",
"text": ""
}
}
},
{
"type": "PRICE_TYPE_SERVICE_FEE",
"price": {
"amount": "6.30",
"currency": "EUR"
},
"isDiscount": false,
"description": {
"en": {
"header": "Flexible price",
"text": ""
},
"de": {
"header": "Flexibler Preis",
"text": ""
}
}
},
{
"type": "PRICE_TYPE_CHILDREN_DISCOUNT",
"price": {
"amount": "0.00",
"currency": "EUR"
},
"isDiscount": false,
"description": {
"en": {
"header": "Child",
"text": "Rides free with you"
},
"de": {
"header": "Kind",
"text": "Kostenlose Mitfahrt"
}
}
},
{
"type": "PRICE_TYPE_FUNDING_AREA_DISCOUNT",
"price": {
"amount": "-1.00",
"currency": "EUR"
},
"isDiscount": true,
"description": {
"en": {
"header": "Hamburg-Takt",
"text": "Trips from this area are funded by the Federal Ministry of Digital Affairs and Transport"
},
"de": {
"header": "Hamburg-Takt",
"text": "Fahrten aus dem gewählten Stadtteil werden von dem Ministerium für Digitales und Verkehr gefördert"
}
}
}
],
"discountedPrice": {
"amount": "9.30",
"currency": "EUR"
}
},
"serviceClass": "SERVICE_CLASS_CLASSIC",
"metadata": "CgkIwRAQgKnOkwISVgoDCJ0IEAEaCQjgCBCAqc6TAiIAKkBPZmZlckNyZWF0b3JfRmxlZXRPcHRpbWl6YXRpb25TbWFydE9mZmVyc19IYXJkQ29kZWRGYWxsYmFja1ZhbHVlGgA="
}
],
"wheelchairOffers": [],
"allOffers": [
{
"id": "09040572-34be-4cca-9fa4-38606be8a55b",
"pickupArea": {
"centerPoint": {
"lat": 53.554415,
"lon": 10.007321
},
"radius": 209,
"walkingDuration": {
"durationRange": {
"minutesMin": 1,
"minutesMax": 4
}
}
},
"deliveryArea": {
"centerPoint": {
"lat": 53.551324,
"lon": 9.986031
},
"radius": 345,
"walkingDuration": {
"singleDuration": {
"minutes": 3
}
}
},
"pickupTimeRange": {
"start": "2024-02-09T08:43:57.775Z",
"end": "2024-02-09T08:53:57.775Z"
},
"deliveryTimeRange": {
"start": "2024-02-09T08:57:42.775Z",
"end": "2024-02-09T09:07:27.788Z"
},
"signedPrice": {
"price": {
"amount": "10.30",
"currency": "EUR"
},
"signature": "763383308658400b6c5df5c2dc1454abc1de7d1951e30b798b268a95e09240e7",
"priceParts": [
{
"type": "PRICE_TYPE_BASE_FEE",
"price": {
"amount": "4.00",
"currency": "EUR"
},
"isDiscount": false,
"description": {
"en": {
"header": "Base price for 1 adult",
"text": ""
},
"de": {
"header": "Basispreis für 1 Erwachsenen",
"text": ""
}
}
},
{
"type": "PRICE_TYPE_SERVICE_FEE",
"price": {
"amount": "6.30",
"currency": "EUR"
},
"isDiscount": false,
"description": {
"en": {
"header": "Flexible price",
"text": ""
},
"de": {
"header": "Flexibler Preis",
"text": ""
}
}
},
{
"type": "PRICE_TYPE_CHILDREN_DISCOUNT",
"price": {
"amount": "0.00",
"currency": "EUR"
},
"isDiscount": false,
"description": {
"en": {
"header": "Child",
"text": "Rides free with you"
},
"de": {
"header": "Kind",
"text": "Kostenlose Mitfahrt"
}
}
},
{
"type": "PRICE_TYPE_FUNDING_AREA_DISCOUNT",
"price": {
"amount": "-1.00",
"currency": "EUR"
},
"isDiscount": true,
"description": {
"en": {
"header": "Hamburg-Takt",
"text": "Trips from this area are funded by the Federal Ministry of Digital Affairs and Transport"
},
"de": {
"header": "Hamburg-Takt",
"text": "Fahrten aus dem gewählten Stadtteil werden von dem Ministerium für Digitales und Verkehr gefördert"
}
}
}
],
"discountedPrice": {
"amount": "9.30",
"currency": "EUR"
}
},
"serviceClass": "SERVICE_CLASS_CLASSIC",
"metadata": "CgkIwRAQgKnOkwISVgoDCJ0IEAEaCQjgCBCAqc6TAiIAKkBPZmZlckNyZWF0b3JfRmxlZXRPcHRpbWl6YXRpb25TbWFydE9mZmVyc19IYXJkQ29kZWRGYWxsYmFja1ZhbHVlGgA="
},
{
"id": "fba0b65e-aa25-4f71-89c9-2f69b653f3ac",
"pickupTimeRange": {
"start": "2024-02-09T08:43:57.775Z",
"end": "2024-02-09T08:49:57.775Z"
},
"deliveryTimeRange": {
"start": "2024-02-09T08:54:42.775Z",
"end": "2024-02-09T09:01:17.594Z"
},
"signedPrice": {
"price": {
"amount": "10.80",
"currency": "EUR"
},
"signature": "8de7d2da57995ae9bdda4052cf79213532c4007d22659a459c702933dc92e858",
"priceParts": [
{
"type": "PRICE_TYPE_BASE_FEE",
"price": {
"amount": "4.00",
"currency": "EUR"
},
"isDiscount": false,
"description": {
"en": {
"header": "Base price for 1 adult",
"text": ""
},
"de": {
"header": "Basispreis für 1 Erwachsenen",
"text": ""
}
}
},
{
"type": "PRICE_TYPE_SERVICE_FEE",
"price": {
"amount": "6.30",
"currency": "EUR"
},
"isDiscount": false,
"description": {
"en": {
"header": "Flexible price",
"text": ""
},
"de": {
"header": "Flexibler Preis",
"text": ""
}
}
},
{
"type": "PRICE_TYPE_EXPRESS_TRIP_FEE",
"price": {
"amount": "0.50",
"currency": "EUR"
},
"isDiscount": false,
"description": {
"en": {
"header": "Express fee",
"text": ""
},
"de": {
"header": "Express-Zuschlag",
"text": ""
}
}
},
{
"type": "PRICE_TYPE_CHILDREN_DISCOUNT",
"price": {
"amount": "0.00",
"currency": "EUR"
},
"isDiscount": false,
"description": {
"en": {
"header": "Child",
"text": "Rides free with you"
},
"de": {
"header": "Kind",
"text": "Kostenlose Mitfahrt"
}
}
},
{
"type": "PRICE_TYPE_FUNDING_AREA_DISCOUNT",
"price": {
"amount": "-1.00",
"currency": "EUR"
},
"isDiscount": true,
"description": {
"en": {
"header": "Hamburg-Takt",
"text": "Trips from this area are funded by the Federal Ministry of Digital Affairs and Transport"
},
"de": {
"header": "Hamburg-Takt",
"text": "Fahrten aus dem gewählten Stadtteil werden von dem Ministerium für Digitales und Verkehr gefördert"
}
}
}
],
"discountedPrice": {
"amount": "9.80",
"currency": "EUR"
}
},
"pickupStop": {
"id": "191458",
"name": {
"de": "Hauptbahnhof / Hachmannplatz",
"en": "Hauptbahnhof / Hachmannplatz"
},
"customerLocation": {
"lat": 53.553638,
"lon": 10.007842
},
"walkingDuration": "126s",
"walkingDistance": 175
},
"deliveryStop": {
"id": "216045",
"name": {
"de": "Stadthausbrücke 10",
"en": "Stadthausbrücke 10"
},
"customerLocation": {
"lat": 53.551441,
"lon": 9.985918
},
"walkingDuration": "60s",
"walkingDistance": 20
},
"serviceClass": "SERVICE_CLASS_EXPRESS",
"metadata": "CgkI0wcQwOXDhgMSZAoDCI0EEAEaCQiCBBDA5cOGAyIAKkBPZmZlckNyZWF0b3JfRmxlZXRPcHRpbWl6YXRpb25TbWFydE9mZmVyc19IYXJkQ29kZWRGYWxsYmFja1ZhbHVlOgwI9caXrgYQwbPtvQI="
}
]
}
Example Response for request with wheelchair in seatInfo
{
"tripRequest": {
"tripId": "db6260fa-23e7-49c5-9dfb-df8cc25e2435",
"serviceAreaUuid": "f89ee35c-10ff-4d3b-959e-07d2e7637119",
"origin": {
"location": {
"lat": 53.554415,
"lon": 10.007321
},
"primaryAddress": "Heidi-Kabel-Platz 12",
"secondaryAddress": "20099 Hamburg, Deutschland"
},
"destination": {
"location": {
"lat": 53.551324,
"lon": 9.986031
},
"primaryAddress": "Stadthausbrücke 8",
"secondaryAddress": "20355 Hamburg, Deutschland"
},
"seatInfo": {
"adults": 1,
"children": 0,
"seats": 1,
"childSeats": 0,
"boosterSeats": 0,
"wheelchairs": 1
},
"requestTime": "2020-05-28T17:50:25Z"
},
"offers": [],
"wheelchairOffers": [
{
"id": "51751ffa-776e-41cf-953e-93d0009a1aa2",
"pickupTimeRange": {
"start": "2022-08-19T07:28:38.434643542Z",
"end": "2022-08-19T07:38:38.434643542Z"
},
"deliveryTimeRange": {
"start": "2022-08-19T07:52:35.434643542Z",
"end": "2022-08-19T08:05:27.939824733Z"
},
"signedPrice": {
"price": {
"amount": "7.50",
"currency": "EUR"
},
"signature": "89145d4d5be334dacd7dfe4fc88dca937f234b8b774e8fe4f20eb5f11ed33b16",
...
},
"pickupStop": {
"id": "202305",
"name": {
"de": "Dorotheenstraße 29A",
"en": "Dorotheenstraße 29A"
},
"customerLocation": {
"lat": 53.580975,
"lon": 10.009604
},
"walkingDuration": "60s",
"walkingDistance": 28
},
"deliveryStop": {
"id": "216045",
"name": {
"de": "Stadthausbrücke 10",
"en": "Stadthausbrücke 10"
},
"customerLocation": {
"lat": 53.551441,
"lon": 9.985918
},
"walkingDuration": "60s",
"walkingDistance": 20
},
"serviceClass": "SERVICE_CLASS_WHEELCHAIR_ACCESSIBLE",
"metadata": ...
}
],
"allOffers": [
{
"id": "51751ffa-776e-41cf-953e-93d0009a1aa2",
"pickupTimeRange": {
"start": "2022-08-19T07:28:38.434643542Z",
"end": "2022-08-19T07:38:38.434643542Z"
},
"deliveryTimeRange": {
"start": "2022-08-19T07:52:35.434643542Z",
"end": "2022-08-19T08:05:27.939824733Z"
},
"signedPrice": {
"price": {
"amount": "7.50",
"currency": "EUR"
},
"signature": "89145d4d5be334dacd7dfe4fc88dca937f234b8b774e8fe4f20eb5f11ed33b16",
...
},
"pickupStop": {
"id": "202305",
"name": {
"de": "Dorotheenstraße 29A",
"en": "Dorotheenstraße 29A"
},
"customerLocation": {
"lat": 53.580975,
"lon": 10.009604
},
"walkingDuration": "60s",
"walkingDistance": 28
},
"deliveryStop": {
"id": "216045",
"name": {
"de": "Stadthausbrücke 10",
"en": "Stadthausbrücke 10"
},
"customerLocation": {
"lat": 53.551441,
"lon": 9.985918
},
"walkingDuration": "60s",
"walkingDistance": 20
},
"serviceClass": "SERVICE_CLASS_WHEELCHAIR_ACCESSIBLE",
"metadata": ...
}
]
}
Field Name | Description |
---|---|
tripRequest |
Identifies and contains information about the trip request. |
offers deprecated |
List of regular offers which contain different stop areas, time-windows and prices. This list is empty if wheelchairs were selected in the seat info of the request. Deprecated Use allOffers instead, filtering by service class SERVICE_CLASS_CLASSIC . |
wheelchairOffers deprecated |
List of wheelchair offers which contain different stops, time-windows and prices. This list is empty if wheelchairs were not selected in the seat info of the request. Deprecated Use allOffers instead, filtering by service class SERVICE_CLASS_WHEELCHAIR_ACCESSIBLE . |
allOffers |
List of all proposed offers, regarless of service class. |
Trip request
Field Name | Description |
---|---|
tripId |
Unique identifier for the trip. Needed to order and cancel a trip. |
serviceAreaUuid |
The unique identifier of the service area this trip is in (based on coordinates). |
origin |
The starting point, see Named Location. |
destination |
The destination, see Named Location. |
seatInfo |
The seat info, see Seat Info. |
requestTime |
A timestamp of when the offer was created. |
Offer
The response contains a list of offers. During /trip/order
, one of the offers from this allOffers
list needs to be selected. An offer consists of the following fields:
Field Name | Description |
---|---|
id |
The unique identifier of the offer. |
pickupArea |
The area around the requested origin where later a pickup stop can be selected from, see here. This field is only set if this is an offer of service class SERVICE_CLASS_CLASSIC . |
pickupStop |
The pickup stop, see here. This field is only set if this is an offer of service class SERVICE_CLASS_EXPRESS or SERVICE_CLASS_WHEELCHAIR_ACCESSIBLE . |
pickupTimeRange |
The time window in which the vehicle should arrive at the pickup stop. Note that the vehicle is only guaranteed to wait until the beginning of this time range. |
deliveryArea |
The area around the requested destination where later a delivery stop can be selected from, see here. |
deliveryStop |
The delivery stop, see here. This field is only set if this is an offer of service class SERVICE_CLASS_EXPRESS or SERVICE_CLASS_WHEELCHAIR_ACCESSIBLE . |
deliveryTimeRange |
The time window in which the vehicle should arrive to the delivery stop. |
signedPrice |
Contains the price information and a signature that may not be changed, see here for details. |
serviceClass |
The service class of the offer. The possible values are SERVICE_CLASS_CLASSIC , SERVICE_CLASS_EXPRESS and SERVICE_CLASS_WHEELCHAIR_ACCESSIBLE . |
metadata |
Opaque offer metadata used by MOIA systems for the execution of the offer. Needs to be included in the order request. |
An offer with service class SERVICE_CLASS_CLASSIC
is the standard service offer.
An offer with service class SERVICE_CLASS_EXPRESS
promises a faster delivery and contains defined stops that will be used for the trip, but this service class comes at an increased price for the customer, described by the price part PRICE_TYPE_EXPRESS_TRIP_FEE
.
An offer with service class SERVICE_CLASS_WHEELCHAIR_ACCESSIBLE
ensures a service that is accessible for customers using a wheelchair.
If the requested seat info includes a positive number of wheelchairs, only offers of this service class will be returned.
If no wheelchair spot is requested, an offer of this service class will not be returned.
If a trip offer could not be created due to a business reason, a 400 Bad Request
is returned.
Signed Price
A signed price consists of the following fields:
Arguments | Description |
---|---|
price |
The base (i.e. undiscounted) price of the offer. |
signature |
A signature for the offer that may not be changed. |
discountedPrice |
The discounted price of the offer, including all discounts listed in the price parts. |
priceParts |
The list of parts that make up the price. |
Price Parts
A price part consists of the following fields:
Name | Description |
---|---|
type |
The type of the price part (see table below). |
price |
The (partial) price amount that is covered by this part. Negative, if isDiscount is "true" . |
isDiscount |
A boolean flag indicating whether this price part is a discount "true" . |
description |
A description of the price part in different locales. Currently only "de" and "en" are supported.The description body consists of a header title and a potentially empty text with further details. |
Types of price parts:
Price Type | Description |
---|---|
PRICE_TYPE_BASE_FEE | The minimum payable tariff of the trip. |
PRICE_TYPE_SERVICE_FEE | The dynamic part of the price, depending on demand/supply, number of passengers, distance etc. |
PRICE_TYPE_EXPRESS_TRIP_FEE | The added surcharge in case the trip is express. |
PRICE_TYPE_CHILDREN_DISCOUNT | The discount for accompanied children (travelling with at least one adult). |
PRICE_TYPE_UNACCOMPANIED_CHILDREN_DISCOUNT | The discount for children travelling alone. |
PRICE_TYPE_CAMPAIGN_DISCOUNT | The discount coming from a MOIA campaign. |
PRICE_TYPE_FUNDING_AREA_DISCOUNT | A special discount in case the trip is to/from an area where MOIA gets funded by the goverment (see AWHT). |
PRICE_TYPE_SEVERELY_DISABLED_DISCOUNT | The discount for severely disabled people (they need a proof + they need to be registered at MOIA). |
PRICE_TYPE_PUBLIC_TRANSPORT_SUBSCRIPTION_DISCOUNT | The discount for HVV card holders. |
Pickup and delivery areas (for Classic offers)
The pickupArea
and deliveryArea
objects contain the following fields:
Field Name | Description |
---|---|
centerPoint |
Center-point of the circle. We expect that to be equal to the pin. |
radius |
Radius of the circle in meters. |
walkingDuration |
Estimated duration for the walk (to or from the closest and furthest stop). |
The walkingDuration
is either represented as a single duration or a duration range:
Field Name | Description |
---|---|
singleDuration optional |
The Walking Duration in minutes for one exact value. |
singleDuration.minutes |
Display as “X minutes” |
durationRange optional |
A range of two different values. Display as “X–Y minutes” |
durationRange.minutesMax |
Maximum walking duration |
durationRange.minutesMin |
Minimum walking duration |
Pickup and delivery stops (for Express and Wheelchair offers)
The pickupStop
and deliveryStop
objects contain the following fields:
Field Name | Description |
---|---|
id |
The id of the stop. |
name |
The name of the stop in German and English. |
customerLocation |
The coordinates of the stop. |
walkingDuration |
The duration in seconds to get to the stop. |
walkingDistance |
The distance to the stop in meters. |
Errors
See Errors for the general error strategy of the API. The following types of error codes can be returned from this route.
Error Code | Description |
---|---|
CODE_GENERAL_ERROR | An internal, technical error occurred. |
CODE_NOT_WITHIN_SERVICE_HOURS | The requested ride time is not within the service hours. |
CODE_NOT_WITHIN_SEATS_RANGE | Requested seats configuration can’t be served. |
CODE_NOT_WITHIN_SERVICE_AREA | The requested location is not inside a known service area. |
CODE_NO_PICKUP_STOPS_NEAR | No pickup stop found near the requested location. |
CODE_NO_DELIVERY_STOPS_NEAR | No delivery stop found near the requested location. |
CODE_NO_PICKUP_AND_DELIVERY_STOPS_NEAR | No pickup stop and no delivery stop found near requested locations. |
CODE_WALK_IS_FASTER | The combined walking distance to pickup and from delivery stop is longer than the distance of the trip. |
CODE_KILL_SWITCH_ACTIVE | The request was rejected due to an extremely high system load. |
/order
POST https://api.moia.io/trip/order
Supported Versions
application/x-protobuf
application/vnd.moia+x-protobuf
application/vnd.moia.v7+x-protobuf
application/json
application/vnd.moia+json
application/vnd.moia.v7+x-json
Request
Example Request
curl https://api.moia.io/trip/order \
-X POST \
-H "accept: application/vnd.moia.v7+x-json" \
-H "content-type: application/vnd.moia.v7+x-json" \
-H "moia-auth: CUSTOMER_ID_TOKEN" \
-d '{
"tripRequest": {
"tripId": "db6260fa-23e7-49c5-9dfb-df8cc25e2435",
"serviceAreaUuid": "f89ee35c-10ff-4d3b-959e-07d2e7637119",
"origin": {…},
"destination": {…},
"seatInfo": {…},
"requestTime": "2020-05-28T17:50:25Z"
},
"offer": {
"id": "09040572-34be-4cca-9fa4-38606be8a55b",
"pickupArea": {…},
"deliveryArea": {…},
"pickupTimeRange": {…},
"deliveryTimeRange": {…},
"signedPrice": {…},
"metadata": …
}
}'
With the /trip/order
endpoint an offer that the customer has selected is ordered.
Field Name | Description |
---|---|
tripRequest required |
Identifies and contains information about the trip request, see Trip request |
offer required |
The regular or wheelchair offer that the customer has selected, see Offer and Wheelchair Offer. |
Response
Example Response
{}
A response with code 200 signals that the order was received and is being processed.
A confirmation is sent asynchronously via the TRIP_COMMITTED
event (or TRIP_REJECTED
in case of failure).
The pickup- and delivery-stop will be sent in PICKUP_STOP_FIXED
and DELIVERY_STOP_FIXED
events,
the vehicle number in a VEHICLE_FIXED
event.
Errors
See Errors for the general error strategy of the api. The following types of error codes can be returned from this route.
Error Code | Description |
---|---|
CODE_GENERAL_ERROR | An internal, technical error occurred. |
CODE_TRIP_ACTIVE | A trip is already active for the given customer. |
CODE_TIMES_ARE_IN_THE_PAST | One or more of the requested times are already in the past. |
CODE_KILL_SWITCH_ACTIVE | The request was rejected due to an extremely high system load. |
/cancel
POST https://api.moia.io/trip/cancel
Supported Versions
application/x-protobuf
application/vnd.moia+x-protobuf
application/vnd.moia.v6+x-protobuf
application/json
application/vnd.moia+json
application/vnd.moia.v6+x-json
A booked offer can be cancelled by sending the tripId
that was contained in the offer
-response.
Request
Example Request
curl https://api.moia.io/trip/cancel \
-X POST \
-H "accept: application/vnd.moia.v6+x-json" \
-H "content-type: application/vnd.moia.v6+x-json" \
-H "moia-auth: CUSTOMER_ID_TOKEN" \
-d '{
"tripId": "db6260fa-23e7-49c5-9dfb-df8cc25e2435"
}'
Field Name | Description |
---|---|
tripId required |
The id from the offer response. |
Response
Example Response
{}
Response code 200 signals that everything is okay.
Errors
See Errors for the general error strategy of the api. The following types of error codes can be returned from this route.
Error Code | Description |
---|---|
CODE_GENERAL_ERROR | An internal, technical error occurred. |
CODE_TRIP_TO_CANCEL_NOT_FOUND | When the customer tries to cancel a trip that we don’t know. |
CODE_CANCEL_REJECTED | Cancellation of the trip was rejected because the trip is in a state where it cannot be cancelled not yet or no longer. |
/events
The Events API provides the ability to subscribe to realtime events related to trips via webhooks. This means that you can receive realtime pickup, delivery and other events of ongoing trips that have been created by your partner account.
/webhook
Register a Webhook
curl https://api.moia.io/events/webhook \
-X PUT \
-H "accept: application/vnd.moia+json" \
-H "content-type: application/vnd.moia+json" \
-H "moia-auth: CLIENT_ID_TOKEN" \
-d '{
"url": "https://www.mydomain.com/webhook/moia",
"secret": "SOME_SECRET",
"format": "json"
}'
To register a web hook url, send the url and a validation key to https://api.moia.io/events/webhook. Events will be sent as JSON
using HTTP POST
to that url. Note that the url cannot contain port numbers.
The header x-moia-signature
will contain the HMAC hex digest of the response body. The HMAC hex digest is generated using the sha256 hash function and the secret as the HMAC key.
Example of signature validation in JavaScript
For illustrative purposes, a JavaScript example is provided showing how to create an HMAC object and add data to it to produce a hex digest in order to verify a message signature using the pre-signed message from an HTTP request.
const compare = require("secure-compare"); // constant time compare to prevent timing attacks
const crypto = require("crypto");
const hmac = crypto.createHmac("sha256", "SOME_SECRET");
var requestBody = "..."; // body from HTTP request
var signatureHeader = "SIGNATURE"; // precomputed signature in the x-moia-signature header
hmac.update(requestBody);
var signature = hmac.digest("hex"); // re-computed signature for verification
if (compare(signature, signatureHeader)) {
console.log("Signature matches");
} else {
console.log("Signature does not match -> reject request");
}
Events
Example Delivery
curl https://www.mydomain.com/webhook/moia \
-X POST \
-H "content-type: application/json" \
-H "x-moia-signature: SIGNATURE" \
-d '{...}'
Payload
[
{
"id": "5479e5eb-9c7c-46c4-a514-0b3ba2d716ee",
"timestamp": "2019-04-15T12:23:34Z",
"eventType": "CUSTOMER_PICKED_UP",
"eventTypeVersion": "1.0",
"data": {
"tripId": "2b076baf-a253-4384-a743-fcc0662074eb",
"customerId": "d81705a2-ce44-4d2a-930a-238c5faed50b"
}
},
...
]
The format of the events is designed to incorporate data from different domains in a compatible and versioned way. They include a data
field for the main payload, as well as several metadata fields:
Field Name | Type | Description |
---|---|---|
id |
String (UUID) | A unique id that identifies this event. |
timestamp |
String (timestamp) | The date and time when this event occurred (not the time when it was sent), ISO 8601 formatted. |
eventType |
String, see list below | Identifies the format of the data field. |
eventTypeVersion |
String ({major.minor} ) |
Version for this particular eventType (each eventType has its own versioning). |
Event Types
Event Type | Current Version | Description |
---|---|---|
TRIP_COMMITTED | 1.0 | The trip was accepted and a vehicle will be dispatched. We may still select a different vehicle before pickup. |
TRIP_REJECTED | 1.0 | The trip was not committed and had to be rejected, no vehicle will be dispatched. |
PICKUP_STOP_FIXED | 1.0 | The pickup stop for a trip was selected. |
DELIVERY_STOP_FIXED | 1.0 | The delivery stop for a trip was selected. |
VEHICLE_FIXED | 1.0 | The final vehicle for this trip was selected shortly before or at pickup. The assigned vehicle will not change anymore. |
CUSTOMER_PICKED_UP | 1.0 | The customer was picked up by the vehicle. |
CUSTOMER_DELIVERED | 1.0 | The customer was delivered by the vehicle. |
CUSTOMER_NOT_SHOWN | 1.0 | The trip cannot be executed because the customer did not show up. |
SERVICE_ABORTED | 1.0 | The trip could not be fulfilled anymore (due to technical errors) |
VEHICLE_LOCATION_UPDATED | 1.0 | The current location of the vehicle was updated. |
TRIP_SCHEDULE_UPDATED | 1.0 | The estimated time of pickup and arrival were updated. |
TRIP_PAYMENT_CHARGEABLE | 1.0 | The customer should now be charged for the trip. |
TRIP_PAYMENT_REFUND_REQUESTED | 1.0 | The customer has requested a refund, which was accepted by customer support. |
TRIP_COMMITTED
TRIP_COMMITTED v1.0
{
"id": "5479e5eb-9c7c-46c4-a514-0b3ba2d716ee",
"timestamp": "2019-04-15T12:23:34Z",
"eventType": "TRIP_COMMITTED",
"eventTypeVersion": "1.0",
"data": {
"tripId": "2b076baf-a253-4384-a743-fcc0662074eb",
"customerId": "d81705a2-ce44-4d2a-930a-238c5faed50b",
"schedule": {
"pickup": "2018-12-04T15:51:20Z",
"delivery": "2018-12-04T16:01:07Z"
}
}
}
Field Name | Type | Description |
---|---|---|
tripId |
String (UUID) | Identifier for this trip. |
customerId |
String (UUID) | Identifier for the customer. |
schedule |
Object | Initial pickup and delivery schedule. |
TRIP_REJECTED
TRIP_REJECTED v1.0
{
"id": "5479e5eb-9c7c-46c4-a514-0b3ba2d716ee",
"timestamp": "2019-04-15T12:23:34Z",
"eventType": "TRIP_REJECTED",
"eventTypeVersion": "1.0",
"data": {
"tripId": "2b076baf-a253-4384-a743-fcc0662074eb",
"customerId": "d81705a2-ce44-4d2a-930a-238c5faed50b"
}
}
Field Name | Type | Description |
---|---|---|
tripId |
String (UUID) | Identifier for this trip. |
customerId |
String (UUID) | Identifier for the customer. |
PICKUP_STOP_FIXED and DELIVERY_STOP_FIXED
PICKUP_STOP_FIXED v1.0
{
"id": "5479e5eb-9c7c-46c4-a514-0b3ba2d716ee",
"timestamp": "2019-04-15T12:23:34Z",
"eventType": "PICKUP_STOP_FIXED",
"eventTypeVersion": "1.0",
"data": {
"tripId": "2b076baf-a253-4384-a743-fcc0662074eb",
"customerId": "d81705a2-ce44-4d2a-930a-238c5faed50b",
"stop": {
"name": {
"de": "Heidi-Kabel-Platz 2",
"en": "Heidi-Kabel-Platz 2"
},
"displayLocation": {
"lat": 53.554464874232266,
"lon": 10.007511187204898
},
"walkingDistance": 13.0,
"walkingDuration": "9.456s"
}
}
}
Field Name | Type | Description |
---|---|---|
tripId |
String (UUID) | Identifier for this trip. |
customerId |
String (UUID) | Identifier for the customer. |
stop |
Object | Stop name, location, walking duration and walking distance. |
stop.walkingDuration |
String | Walking duration to the stop from the origin. |
stop.walkingDistance |
Number | Walking distance to the stop from the origin in meters. |
DELIVERY_STOP_FIXED v1.0
{
"id": "5479e5eb-9c7c-46c4-a514-0b3ba2d716ee",
"timestamp": "2019-04-15T12:23:34Z",
"eventType": "DELIVERY_STOP_FIXED",
"eventTypeVersion": "1.0",
"data": {
"tripId": "2b076baf-a253-4384-a743-fcc0662074eb",
"customerId": "d81705a2-ce44-4d2a-930a-238c5faed50b",
"stop": {
"name": {
"de": "Heidi-Kabel-Platz 2",
"en": "Heidi-Kabel-Platz 2"
},
"displayLocation": {
"lat": 53.554464874232266,
"lon": 10.007511187204898
},
"walkingDistance": 13.0,
"walkingDuration": "9.456s"
}
}
}
Field Name | Type | Description |
---|---|---|
tripId |
String (UUID) | Identifier for this trip. |
customerId |
String (UUID) | Identifier for the customer. |
stop |
Object | Stop name, location, walking duration and walking distance. |
stop.walkingDuration |
String | Walking duration from the stop to the destination. |
stop.walkingDistance |
Number | Walking distance from the stop to the destination in meters. |
VEHICLE_FIXED
VEHICLE_FIXED v1.0
{
"id": "5479e5eb-9c7c-46c4-a514-0b3ba2d716ee",
"timestamp": "2019-04-15T12:23:34Z",
"eventType": "VEHICLE_FIXED",
"eventTypeVersion": "1.0",
"data": {
"tripId": "2b076baf-a253-4384-a743-fcc0662074eb",
"customerId": "d81705a2-ce44-4d2a-930a-238c5faed50b",
"vehicleInfo": {
"id": "vehicle-hamburg-12",
"label": "12"
}
}
}
Field Name | Type | Description |
---|---|---|
tripId |
String (UUID) | Identifier for this trip. |
customerId |
String (UUID) | Identifier for the customer. |
vehicleInfo |
Object | Vehicle identifier and human readable label. |
CUSTOMER_PICKED_UP and CUSTOMER_DELIVERED
CUSTOMER_PICKED_UP v1.0
{
"id": "5479e5eb-9c7c-46c4-a514-0b3ba2d716ee",
"timestamp": "2019-04-15T12:23:34Z",
"eventType": "CUSTOMER_PICKED_UP",
"eventTypeVersion": "1.0",
"data": {
"tripId": "2b076baf-a253-4384-a743-fcc0662074eb",
"customerId": "d81705a2-ce44-4d2a-930a-238c5faed50b"
}
}
CUSTOMER_DELIVERED v1.0
{
"id": "5479e5eb-9c7c-46c4-a514-0b3ba2d716ee",
"timestamp": "2019-04-15T12:23:34Z",
"eventType": "CUSTOMER_DELIVERED",
"eventTypeVersion": "1.0",
"data": {
"tripId": "2b076baf-a253-4384-a743-fcc0662074eb",
"customerId": "d81705a2-ce44-4d2a-930a-238c5faed50b"
}
}
Field Name | Type | Description |
---|---|---|
tripId |
String (UUID) | Identifier for this trip. |
customerId |
String (UUID) | Identifier for the customer. |
CUSTOMER_NOT_SHOWN
CUSTOMER_NOT_SHOWN v1.0
{
"id": "da133107-7611-457e-9c79-ab3ddf2180db",
"timestamp": "2019-04-15T12:24:31Z",
"eventType": "CUSTOMER_NOT_SHOWN",
"eventTypeVersion": "1.0",
"data": {
"tripId": "9f162a17-cecb-40bc-aee0-2663e1733933",
"customerId": "14984dcb-44bb-4d1b-be9c-059adcc70886"
}
}
Field Name | Type | Description |
---|---|---|
tripId |
String (UUID) | Identifier for this trip. |
customerId |
String (UUID) | Identifier for the customer. |
SERVICE_ABORTED
Note: This event is only sent in extremely rare cases when the vehicle has technical difficulties and the trip cannot be fulfilled in any way anymore.
SERVICE_ABORTED v1.0
{
"id": "5479e5eb-9c7c-46c4-a514-0b3ba2d716ee",
"timestamp": "2019-04-15T12:23:34Z",
"eventType": "SERVICE_ABORTED",
"eventTypeVersion": "1.0",
"data": {
"tripId": "2b076baf-a253-4384-a743-fcc0662074eb",
"customerId": "d81705a2-ce44-4d2a-930a-238c5faed50b"
}
}
Field Name | Type | Description |
---|---|---|
tripId |
String (UUID) | Identifier for this trip. |
customerId |
String (UUID) | Identifier for the customer. |
VEHICLE_LOCATION_UPDATED
VEHICLE_LOCATION_UPDATED v1.0
{
"id": "67b0d34b-b8b6-4a82-a98c-6f74be5e2cc6",
"timestamp": "2019-04-15T12:23:54Z",
"eventType": "VEHICLE_LOCATION_UPDATED",
"eventTypeVersion": "1.0",
"data": {
"tripId": "fa20e157-35cd-40f4-a3ef-93af2327ec75",
"customerId": "7ae77bad-8cc2-4bb4-96fe-4feeefc6ea1a",
"lat": 9.23763824,
"lon": 52.2348738
}
}
Field Name | Type | Description |
---|---|---|
tripId |
String (UUID) | Identifier for this trip. |
customerId |
String (UUID) | Identifier for the customer. |
lat |
Number | Last known latitude of the vehicle. |
lon |
Number | Last known longitude of the vehicle. |
TRIP_SCHEDULE_UPDATED
TRIP_SCHEDULE_UPDATED v1.0
{
"id": "576fdd4a-b13b-45a1-9cde-2148412fa991",
"timestamp": "2019-04-15T12:23:56Z",
"eventType": "TRIP_SCHEDULE_UPDATED",
"eventTypeVersion": "1.0",
"data": {
"tripId": "fa20e157-35cd-40f4-a3ef-93af2327ec75",
"customerId": "7ae77bad-8cc2-4bb4-96fe-4feeefc6ea1a",
"pickupTime": "2019-04-15T12:32:00Z",
"deliveryTime": "2019-04-15T12:43:11Z"
}
}
Field Name | Type | Description |
---|---|---|
tripId |
String (UUID) | Identifier for this trip. |
customerId |
String (UUID) | Identifier for the customer. |
pickupTime |
String (timestamp) | Currently estimated time for the pickup. Format: ISO 8601 |
deliveryTime |
String (timestamp) | Currently estimated time for the delivery. Format: ISO 8601 |
TRIP_PAYMENT_CHARGEABLE and TRIP_PAYMENT_REFUND_REQUESTED
Payment related events will be retried for up to 3 days in case they could not be delivered. The retry interval is at about every 10 minutes.
TRIP_PAYMENT_CHARGEABLE v1.0
{
"id": "8b903d63-d347-497b-a00b-15e4576ed1e4",
"timestamp": "2019-04-15T12:32:44Z",
"eventType": "TRIP_PAYMENT_CHARGEABLE",
"eventTypeVersion": "1.0",
"data": {
"tripId": "fa20e157-35cd-40f4-a3ef-93af2327ec75",
"customerId": "7ae77bad-8cc2-4bb4-96fe-4feeefc6ea1a",
"paymentReference": "A7BXY",
"charge": {
"grossAmount": "8.34",
"netAmount": "7.01",
"vatRate": "0.19",
"currency": "EUR"
}
}
}
TRIP_PAYMENT_REFUND_REQUESTED v1.0
{
"id": "8b903d63-d347-497b-a00b-15e4576ed1e4",
"timestamp": "2019-04-15T12:32:44Z",
"eventType": "TRIP_PAYMENT_REFUND_REQUESTED",
"eventTypeVersion": "1.0",
"data": {
"tripId": "fa20e157-35cd-40f4-a3ef-93af2327ec75",
"customerId": "7ae77bad-8cc2-4bb4-96fe-4feeefc6ea1a",
"paymentReference": "X5Q5NB",
"charge": {
"grossAmount": "8.34",
"netAmount": "7.01",
"vatRate": "0.19",
"currency": "EUR"
}
}
}
Field Name | Type | Description |
---|---|---|
tripId |
String (UUID) | Identifier for this trip. |
customerId |
String (UUID) | Identifier for the customer. |
paymentReference |
String (max length 8) | The book-keeping reference for this transaction. |
charge |
Object | The charge for this transaction. |
charge.grossAmount |
String | Charged gross amount. With the number of decimals that is standard for the currency (e.g. 2 decimals for EUR). |
charge.netAmount |
String | Charged net amount. With the number of decimals that is standard for the currency (e.g. 2 decimals for EUR). |
charge.vatRate |
String | Charged VAT rate. Number between 0 and 1 that has at least 2 decimals. |
charge.currency |
String | Currency as ISO 4217 code. |