Download OpenAPI specification:Download
This document describes the standards used to establish connectivity between a supplier’s system (typically BMS / SRS platforms, Channel Managers) and Manawa.com.
To achieve this connectivity, the supplier must provide an API consisting of endpoints that allow Manawa to query the availability of products, place reservations and bookings, as well as cancel them. All of these supplier-side endpoints must be implemented for a successful integration.
Manawa will send requests to URLs described in the document, passing parameters and data as specified and expecting data to be returned as specified.
For example, when we need to retrieve availability for a given product, we will call
https://your-host.com/1/get-availabilities
. Your endpoint must return availability data in a format that complies with the spec. This data will then be used by Manawa to obtain product availabilites, pricing rules, and to display a booking interface to the users.
The workflow that we use is very simple:
When a Manawa customer wish to check availability for an activity, we send a /get-availabilities
request with date ranges, to your API. With the returned info, we can display a booking interface to the customer.
When the customer decides to add the activity to its shopping cart, we call /reserve
in order to secure the slots in the inventory for a limited time period.
When the customer confirms and pays, we call /book
to confirm the booking.
[Coming soon] If cancellation is necessary, we call /cancel-booking
.
Also note that:
The API does not cover static data such as product descriptions, policies or pictures. Static data is managed by the Manawa Sales & Integration team.
Mapping between your products and Manawa products is done by Manawa. We ask you to implement a few, simple endpoints to facilitate mapping.
Payment from customers and commission payouts to suppliers are handled by Manawa.
The API must be implemented as a set of regular HTTPS endpoints that handle data as JSON formatted payloads as per specifications. It is important that the HTTP Content-type header is set to application/json
for all responses.
Please note as well that we always expect a
200
HTTP status code, as long as the response contains an expected payload (this includes error codes). All non200
HTTP status codes are considered transport and/or server failures. See Error handling section for more info.
Please also note that we might add additional non-breaking fields to each data structure at our convenience; your JSON deserializer should be flexible enough to handle these new fields without breaking. API changes are described in the Changelog section.
Consider as well that Manawa is localized in several languages. It’s mandatory for your API to support UTF-8 character encoding both in requests and responses.
Requests will use GET
or POST
. Request data for GET requests will be passed as query string. Data for POST requests will be passed in the request body as JSON.
You can use any domain, subdomain, or subdirectory as base (https://your-host.com
, https://api.your-host.com
, https://your-host.com/api/
are all valid).
The API is versionned to ensure backwards compatibility. All endpoints must be prefixed with the API major version number (currently: /1/
). E.g: https://your-host.com/1/get-availabilities
.
Your endpoints must be secured using HTTP Basic Auth. We will pass an Authorization HTTP header in each request.
# [token] is the base64-encoding of `[username]:[password]`
Authorization: Basic [token]
Username and password are managed by the Supplier platform. Any string is accepted (email, username, API token...).
Please not that only Basic authentication is accepted. No other forms of authentication are allowed (e.g OAuth or Bearer token).
Our client is configured with a 30 seconds timeout limit. All responses taking longer will be ignored and the request will fail.
However, we strongly advise that responses should not take longer than 10s, in order to provide a satifying customer experience.
When an error occurs, it should be categorized into one of the types listed in the table below in order to facilitate automatic responses to errors, error handling and debugging.
Please note, the error structure must be present in the response only if the request is not successful. The API response will accept either the data
structure with the successful response or the errorCode
structure, not both. Inconsistency might lead to the API requests to fail.
Error Code | Explanation |
---|---|
AUTHORIZATION_FAILURE |
The provided credentials are not valid.
|
INVALID_PRODUCT |
The specified product does not exist or is broken for another reason (excluding availability issues).
|
VALIDATION_FAILURE |
The request object contains inconsistent or invalid data or is missing data, such as incorrect date range requested, timeslots are in the past, etc. Please provide as much detail as possible in the error message.
|
INTERNAL_SYSTEM_FAILURE |
An error occurred that is unexpected and/or doesn’t fit any of the types above, including timeouts, service not reachable, etc. Please provide as much detail as possible in the error message.
|
Error Code | Explanation |
---|---|
NO_AVAILABILITY |
Applicable endpoint: Reservation, Booking |
The reservation or booking call cannot be fulfilled because there is insufficient availability.
|
|
INVALID_TICKET_CATEGORY |
Applicable endpoint: Reservation, Booking |
The reservation or booking call specified a ticket category that is not configured for the requested product.
ticketCategory must match a ticket category supported. The value for this field should be the (or one of the) unexpected ticket categories that have been requested.
|
|
INVALID_PARTICIPANTS_CONFIGURATION |
Applicable endpoint: Reservation, Booking |
The reservation or booking call specified a ticket quantity that is not allowed for the requested product. This is based on the minimum or maximum number of participants per booking that have been configured for this product in your system. Individual Ticket Categories For Individual ticket categories, which consists of all ticket categories except Group , the expected response is:
In this example we might have made a request for two Adult tickets. This did not meet the product’s minimum participant number (four) in your system, so we received this error response.
Group Ticket Category
The |
|
INVALID_RESERVATION |
Applicable endpoint: Booking |
The booking call cannot be fulfilled because specified reservation does not exist or is not in a valid state.
|
|
INVALID_BOOKING |
Applicable endpoint: Booking Cancellation |
The booking cancellation call cannot be fulfilled because booking does not exist or is not in a valid state.
|
|
INVALID_SUPPLIER |
Applicable endpoint: Get Products List |
The request is not valid because the supplier does not exist or is not configured to sell on Manawa.
|
Points in time are expressed as strings using the ISO 8601
datetime format (e.g. 2020-12-05T14:00:00+02:00
). We always expect the local time with its timezone as UTC offset.
Example: Dog sledding tour in Montreal, 5th of December 2020 at 14:00 (local time):
Expected:
2020-12-05T14:00:00-05:00
Not expected:
2020-12-05T21:00:00+02:00
/2020-12-05T19:00:00+00:00
Please note that although the above examples express the same point in time, we consider only the first one valid as we always require the date and time in reference to the location of the activity.
Please find the list of the supported ticket categories below. All categories describe an individual with the exception of GROUP
.
Complete list of supported categories:
ADULT
CHILD
YOUTH
INFANT
GROUP
The GROUP
category should be used for products using a Group pricing strategy (typically when the base stock unit can accomodate several passengers).
Consider a supplier that provides Quad Biking tours. Each Quad bike can accomodate 1 or 2 passengers. We want to place an order for 2
ADULT
and 1YOUTH
.
If the supplier decides to apply individual pricing:
ADULT
and YOUTH
categoriesADULT
+ 1 YOUTH
.ADULT
and 1 of type YOUTH
.If the supplier decides to apply group pricing:
GROUP
categoryGROUP
tickets (to accomodate the 3 pax).GROUP
tickets.The ID of the requested product in the supplier’s system. Each product ID maps to one Activity Variant on Manawa. An Activity Variant can have multiple starting times, but a single product ID needs to respond to all of them. It can be up to 255 characters long.
Please refrain from using the character %
in your Product ID, as it is used as an escape character during URL encoding. The use of %
may lead to failed encoding of the product ID in the URL.
Please note that we will not map individual time slots, different languages and different ticket categories but you can encode all this information into the product ID (e.g. via a JSON structure) as long as you provide a string of maximum 255 characters long.
This endpoint must return availability and pricing information for a given product, during a date range specified in the request parameters.
The response must contain the availability for each time slot of the requested product that falls within the supplied time period. We may send requests asking for up to 31 days of availabilities, for dates up to 13 months in advance.
In order to get real-time availability, Manawa will call this endpoint whenever a Manawa customer requests availability for a connected activity. To avoid excessive load, availability responses are cached for 15 minutes.
If there is no availability for a timeslot that falls within the range, you must return an entry with 0 availability e.g. vacancies: 0
. Please do not return a NO_AVAILABILITY
error code.
If there is no availability at all in the given time range we expect an empty array.
NO_AVAILABILITY
must be used while handling a request for /book
only.
Please note, for GROUP products the vacancies
field should contain the total number of available groups, not the total number of individual vacancies.
For example, if you accept a maximum of 10 groups per timeslot you should return vacancies: 10
.
More details about group pricing here.
Time point products are activities that start at a precise time (eg, boat tours). People book for a specific date and time slot.
Time period products are activites with no pricise starting time, either because:
"availabilities": [
{
"dateTime": "2020-12-01T10:00:00+02:00",
// ...
},
{
"dateTime": "2020-12-01T15:00:00+02:00",
// ...
}
]
2020-12-05T00:00:00+04:00
.openingTimes
). Opening times spanning the full day can be expressed by setting fromTime
to 00:00
and toTime
to 23:59
. Any availability containing 24:00
in the opening times definition will be ignored by our system."availabilities": [
{
"dateTime": "2020-12-01T00:00:00+02:00",
// ...
"openingTimes": [
{
"fromTime": "09:00",
"toTime": "12:00"
}
],
},
{
"dateTime": "2020-12-02T00:00:00+02:00",
// ...
"openingTimes": [
{
"fromTime": "09:00",
"toTime": "18:00"
}
],
}
]
The optional field cutoffSeconds
is an integer representing the cut-off time in seconds. The cut-off needs to be sent on the starting time/opening hours level. If unspecified, we will use a default cut-off value defined by Manawa (72 hrs).
For example: An activity has two starting times on May 10th: 11:00 and 13:00. The cut-off may be sent for both timeslots or only for the starting time 11:00. In this scenario the 13:00 timeslot will use the default cut-off configured by Manawa.
Please note that the cut-off can not be negative.
All fields (currency
and pricesByCategory
) and nested subfields (retailPrices
- an array of objects containing category
and price
) are required.
The price
for each category
(Adult, Child, etc) must be present for each datetime received in your response. If a category
and relevant price
is absent, the response will be deemed invalid.
We make calls for availability upto 365 days in the future, so please ensure these are present in your system and your responses. If pricing data is absent, the response will be deemed invalid and the affected datetimes will become unbookable.
Similarly, price shared for GROUP category should apply to the whole group, regardless of its size.
If your system supports Tiered Prices, your can return the optional tieredPricesByCategory
field in your availability response.
If
tieredPricesByCategory
is provided, Manawa will consume the tiered prices and ignore values defined inpricesByCategory
. IftieredPricesByCategory
is not defined, Manawa will fallback to usingpricesByCategory
.
Adult | Child | |
---|---|---|
1-3 pax | EUR 50 | EUR 30 |
4-10 pax | EUR 45 | EUR 25 |
10+ pax | EUR 40 | EUR 20 |
In the example, a person booking for 4 adults and 2 children would have to pay 45 EUR per adult and 30 EUR per child (total EUR 240).
The corresponding tieredPricesByCategory
value would need to be:
{
"retailPrices": [
{
"category": "ADULT",
"tiers": [
{
"lowerBound": 1,
"upperBound": 3,
"price": 5000
},
{
"lowerBound": 4,
"upperBound": 10,
"price": 4500
},
{
"lowerBound": 11,
"upperBound": 200,
"price": 4000
}
]
},
{
"category": "CHILD",
"tiers": [
{
"lowerBound": 1,
"upperBound": 3,
"price": 3000
},
{
"lowerBound": 4,
"upperBound": 10,
"price": 2500
},
{
"lowerBound": 11,
"upperBound": 200,
"price": 2000
}
]
}
]
}
productId required | string Example: productId=prod123 The ID of the requested product in the supplier’s system. Please avoid using the character |
fromDateTime required | string Example: fromDateTime=2020-12-01T00:00:00+02:00 Marks the start (inclusive) of the requested time period (ISO 8601). |
toDateTime required | string Example: toDateTime=2020-12-01T23:59:59+02:00 Marks the end (inclusive) of the requested time period (ISO 8601). |
{- "data": {
- "availabilities": [
- {
- "dateTime": "2020-12-01T10:00:00+02:00",
- "productId": "prod123",
- "cutoffSeconds": 3600,
- "vacancies": 10,
- "currency": "EUR",
- "pricesByCategory": {
- "retailPrices": [
- {
- "category": "ADULT",
- "price": 1500
}, - {
- "category": "CHILD",
- "price": 1000
}
]
}
}, - {
- "dateTime": "2020-12-01T15:00:00+02:00",
- "productId": "prod123",
- "cutoffSeconds": 1800,
- "vacancies": 12,
- "currency": "EUR",
- "pricesByCategory": {
- "retailPrices": [
- {
- "category": "ADULT",
- "price": 1600
}, - {
- "category": "CHILD",
- "price": 1100
}
]
}
}
]
}
}
This call is made when customers add an activity to their cart. It represents the first step of the booking process. It must reserve the requested quantities in the supplier’s system for at least 1 hour in order to guarantee a successful booking within the following hour. Failure to do so will potentially result in unconfirmed bookings if the product is no longer available.
Please note that we allow customers to add a product to the cart through the reserve
endpoint until the time specified by the cut-off of the product (see Cutoff over API under the Availability Query).
This feature is not yet fully implemented by Manawa. At the moment,
/reserve
and/book
requests are chained together and sent when customers confirm their purchase. In other words, when a customer pays, we "reserve" the booking and send a "book" request immediately after.We will soon move the call to
/reserve
when adding to the cart, and use the proper reservation process explained above. So we strongly advice to support it right now in your API.
required | object |
{- "data": {
- "bookingItems": [
- {
- "category": "ADULT",
- "count": 2
}, - {
- "category": "CHILD",
- "count": 1
}
], - "dateTime": "2020-12-01T10:00:00+02:00",
- "productId": "prod123",
- "externalBookingReference": 1234567
}
}
{- "data": {
- "reservationReference": "res789",
- "reservationExpiration": "2020-12-01T07:35:53+00:00"
}
}
This call represents when either the customer removes the item from their shopping cart, or when it’s automatically removed by default after 1 hour. When called, Quantities reserved during the call to /reserve
should be released by the Suppliers' system.
This feature is not yet used by Manawa. At the moment,
/reserve
and/book
requests are chained and sent when customers confirm their purchase. In other words, when a customer pays, we "reserve" the booking and send a "book" request immediately after.This means that reservations are never cancelled by Manawa at the moment.
We will soon use the proper reservation process as described in the
/reserve
endpoint, so we strongly advice to support it right now in your API.
required | object |
{- "data": {
- "reservationReference": "res789",
- "externalBookingReference": 1234567
}
}
{- "data": { }
}
This call confirms a reservation that has been placed previously and provides additional information.
Whenever a call to this method previously failed, it will be retried up to 10 additional times. In case the booking was confirmed internally on the supplier’s side, this endpoint must return the expected response (repeat booking confirmation) without generating another booking nor an error.
object |
{- "data": {
- "bookingItems": [
- {
- "category": "ADULT",
- "count": 2,
- "retailPrice": 1560
}, - {
- "category": "CHILD",
- "count": 1,
- "retailPrice": 1300
}
], - "dateTime": "2020-12-01T10:00:00+02:00",
- "currency": "USD",
- "externalBookingReference": 1234567,
- "productId": "prod123",
- "reservationReference": "res789",
- "travelers": [
- {
- "email": "john@john-smith.com",
- "firstName": "John",
- "lastName": "Smith",
- "phoneNumber": "+33 123456789"
}
], - "comment": ""
}
}
{- "data": {
- "bookingReference": "bk456",
- "tickets": [
- {
- "category": "ADULT",
- "ticketCode": "code001",
- "ticketCodeType": "QR_CODE"
}, - {
- "category": "ADULT",
- "ticketCode": "code002",
- "ticketCodeType": "QR_CODE"
}, - {
- "category": "CHILD",
- "ticketCode": "code003",
- "ticketCodeType": "QR_CODE"
}
]
}
}
This call must cancel the booking in your system.
This feature is not yet used by Manawa, but will be implemented soon, so we strongly advise to support this endpoint right now.
In the meantime, cancellation notifications are sent by email to the supplier by Manawa Customer Services. Supplier is then responsible for manually cancelling the booking in its Booking Platform.
required | object |
{- "data": {
- "bookingReference": "bk456",
- "externalBookingReference": 1234567,
- "productId": "bk456"
}
}
{- "data": { }
}
The Supplier List endpoint allows Manawa to query a list of supplier available through the API. The generated list will enable mapping of products between the Connectivity Partner and Manawa.
The endpoint returns the entire list of suppliers as response.
{- "data": [
- {
- "supplierId": "supplier123",
- "supplierName": "Test Supplier"
}, - {
- "productId": "supplier456",
- "supplierName": "Another supplier"
}
]
}
The Product List endpoint allows Manawa to query a list of supplier products programmatically. The generated product list will enable mapping of products between the Connectivity Partner and Manawa.
The endpoint returns the entire list of products as response for a requested supplier ID.
supplierId required | string Example: Abc123 The ID of the supplier on the Connectivity partner's system. |
{- "data": {
- "supplierId": "supplier123",
- "supplierName": "Supplier Name",
- "products": [
- {
- "productId": "prod123",
- "productTitle": "Product Title"
}, - {
- "productId": "prod456",
- "productTitle": "Another product Title"
}
]
}
}
This endpoint returns a set of content and configurational settings for a product based on a requested product ID (ID of the product on the Connectivity partner's system)
productId required | string Example: PPYM1U Product identifier in the Connectivity partner's system |
{- "data": {
- "supplierId": "supplier123",
- "productTitle": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
- "configuration": {
- "participantsConfiguration": {
- "min": 1,
- "max": 10
}
}
}
}
The categories over API endpoint allows Manawa to import the price category data for a given product.
Only supported categories would be accepted and consumed. Any non supported category received via the endpoint would be rejected
productId required | string Example: prod123 The ID of the requested product in the supplier’s system. |
{- "data": {
- "pricingCategories": [
- {
- "category": "ADULT",
- "minTicketAmount": 1,
- "maxTicketAmount": 8,
- "groupSizeMin": 1,
- "groupSizeMax": 5,
- "ageFrom": 18,
- "ageTo": 99,
- "bookingCategory": "STANDARD",
- "price": [
- {
- "priceType": "RETAIL_PRICE",
- "price": 1000,
- "currency": "EUR"
}
]
}
]
}
}