The vOffice-API is devided into three main sections:
section | description |
---|---|
Data-Export | Export data from vOffice. It is typically used to import all relavant data to an external database. It is NOT intended for a live query / high frequency calls |
Live-Query | Query search-results, quotes etc. This section is especially usefull, if you are devoloping a custom homepage (not using the vOffice CMS). |
Booking | Save an online-booking / option and query existing bookings |
To access the interface, you need to have an api-key. If you do not have one yet, please create it in the options of vOffice / request it from our customer. Depending on the implementation type (direct or CM+), you will either get a api-key for each customer or one for all customer which have activated your connection on our side.
If you set up an interface to vOffice, please tell us about it, so we can inform our customers about the possibilities and assist you with questions about the implementation etc.: info@v-labs.eu
Our documentation provides a small web test section, where you can test out basic requests against some of our endpoints. (Please keep in mind, that you still need the api-key and you are not able to set custom parameters in this test) You can see it in action here: API Test
The api is available under following base address:
An API request via HTTP GET must be of the following form, since some parameters are always required:
Parameters that are always required:
parameter name | value |
---|---|
key | your vOffice api key |
actionName | action to perform (equivalent of an api endpoint) |
Parameters that are always required for live-queries and bookings:
parameter name | value |
---|---|
data | json encoded data (see corresponding actions for details) |
lang | ISO 639-1 language code to return the specific language (if possible) |
Depending on the action there might be more required parameters.
Alternatively you can do a HTTP-POST with the body beeing the data parameter as json, however this is not recommended as it disables the cache and therefor increases the costs.
All responses are UTF-8 json files.
This api is charged by the number of api calls. Please refer to the vOffice prices for detailed information.
In order to improve performance and avoid uncessary costs you should adhere to these best practices:
Respect Cache-Control in results:
In the result headers you will find a Cache-Control entry (max-age in seconds). Results should be cached accordingly client-side and server-side.
Max-age depends on the type of data: Availabilities are updated much faster than description texts for example.
HTTP GET instead of POST:
Results are also cached by vOffice, however that is only true for GET requests, not POST requests.
Rendered pages should be cached:
If this API is integrated for a website, pages should be cached - both: client side in the browser AND server-side (ideally on a CDN).
Always use updatedSince:
If you are using Data-Export-APIs, always specify the updatedSince-parameter, so you don't have to download the complete result list every time.
Do NOT call the API for every search-result-entry:
The search API is quite powerful, if you are missing some details, it can usually be accomplished by adding a parameter.
Do NOT call for example "getUnit" or "quotePrices" after a search on every single search-result-entry!
How often should you import data:
Please reach out to us, so that we can discuss the implementation process (info@v-office.com or partner@v-office.com if previously in contact).
At first, things may need to be clarified on the business side, before starting with the technical parts.
If beneficial, we can set up meetings, to get things started. There we can clarify any questions, which occured after reading the api, the test process and everything else.
The onboarding process will be done by our support team, depending on the connection type, the new units will then be available under the existing api key (if CM+ / bul connection) or you will need to add a new api key (if direct connection) which will contain the new units.
The details of the process may differ from partner to partner, so make sure to clarify it with us in advance, to avoid misunderstandings later on.
If not agreed on otherwise, units that are no longer being exposed over the api, should be removed / set offline (or marked as unavailable till no open booking is present anymore) automatically.
Make sure to elaborate the thematic and add all the available information.
For example: member id, unit id, detailed description of the issue (not "price is wrong" but rather "we have noticed that the calculated vtax value we are getting from the QuotePrices action is to low, 200 instead of 300, when we book for 2 persons a 7 nights"), timestamps etc.
If you have general issues/questions: please contact info@v-office.com
If you have api related issues/questions: please contact partner@v-office.com
4.2.2021 | added parameters to search (groupFacilities, fuzzy, alternatives) |
9.2.2021 | added list of error codes |
27.2.2021 | added best practices |
30.4.2021 | added publish + reachableByLink to unit export |
29.7.2021 | added externalNumber to online booking |
18.09.2021 | added includeServiceLimits to quote prices and getBooking |
21.09.2021 | added nights_min and nights_max to search |
28.9.2021 | added petsCount to quotePrices |
5.10.2021 | added Analytics API |
28.11.2021 | updated depositLocation values on getUnits |
29.12.2021 | added "Understanding flexible / fuzzy / alternative search" in search |
15.1.2022 | extended Analytics API: - added id, unitid, region, country, city, postalcode to BOOKINGS - added booking with status 'FREEZE' and field 'freeze_reason' - added sections 'UNITS' + 'DAYS' |
08.08.2023 | Replaced api endpoint api.v-office.com with api2.v-office.com, which provides better caching behavior. |
If there is any important news regarding the api, it will be mentioned here.
For example: planned changes which would require action on the implementation side in the future.
- No important notice at the moment -
parameter | description | value | type |
---|---|---|---|
prices | include prices | true | B |
offers | include offers | true | B |
restrictions | include booking-restrictions | true | B |
facilities | include facilities or list only facilities | true = include OR exclusive | B |
ratings | average ratings (1-5) | true | B |
feedbacks | list of text feedbacks | true | B |
profiles | include property manager / contact profiles | true | B |
groups | include unitgroups | true | B |
facilitiesimages | add images from facilility in images | true | B |
updatedSince | show only entries, that have been updated since this date | e.g. 2015-06-05T09:53:43Z | DT |
max | optional parameter to limit the results to a number smaller than 128 | between 1 and 127 | I |
{units: [ { _id: 23423, info: {...}, member: 1234 prices: {...}, offers: {...}, restrictions: {...}, currency: 'EUR' }, { _id: 23424, ...., } ]}
The member ID which is returned for every unit, is the internal customer ID.
If you use a direct connection, every api key should only feature on member.
If you use the CM+ (bulk) connection, a key will feature all available aka multiple members, so you can use the member ID to identify which units belong to which member if necesssary.
In our system, the customer has the possiblity to create unit groups. These groups have a unique ID and the customer may assign multiple units to it.
Groups will be included in the response (as groups, which will be a array), if the request parameter group (see above) is set to true.
You can filter for all units of a specific unit group by using the unitgroupid parameter and set the ID of the unit group you want to select with the filter.
Which units may be included in the specific unit groups and what these groups mean, should be clarified with the customer / agency, if you need to know it / want to use this feature.
field | description | type |
---|---|---|
facility | facility id (Facilities combine units located in one house or at one site. For example a holiday apartment house is one facility.) |
I |
isfacility | whether this entry is a facility or a unit | B |
code | internal code/name of the unit | S |
type |
one of HOUSE, FLAT, ROOM, PRIVAT, MOBILEHOME, YACHT in case of a unit |
S |
deposit | Value of the deposit | C |
depositLocation | one of WITH_PREPAYMENT, WITH_FINALPAYMENT, ON_ARRIVAL, ON_SITE | S |
bookable | one of DIRECTLY, REVERSED, REVERSED_OPT, INQUIRY_CAL, INQUIRY_NO_CAL DEPRECATED: if you are an OTA, please ignore this field, units should always be directly bookable |
S |
bookingLeadTime | number of days the booking needs to take place before arrival | I |
region | the id of the region and the index | SET |
regionName | the name of the region (may be available in multiple languages) | ML |
loc | Geo location (longitude and latitude only) | GeoJSON |
fullName | unit name including facility name (in the language of the customer) | S |
name | name/title of the unit (may be available in multiple languages) | ML |
facilityName | name/title of the facility (may be available in multiple languages) | ML |
address | Contains the address information (excludes longitude and latitude) | SET |
url | direct link to the unit on the vOffice Homepage | ML |
picsOrder | one of FAC_PICS_FIRST, FAC_PICS_LAST, NO_FAC_PICS (order being facility pictures first, last, not present) | S |
images | A list of the units images (see below for details) | LIST |
roomDetails | list of rooms including list of beds | LIST |
cancellationPolicy | Conditions and costs for cancellations (see below for details) | OBJECT |
publish | if false, unit should not be included in search-results | B |
reachableByLink | if publish is false and reachableByLink is true, it should still be reachable by (private) link | B |
licenseNumber |
Contains the properties license code (if set) Attention: Units in italy may contain multiple ids in this field if the unit has 2 (CIR, CIN, CITRA), they will be transmitted in following format "CIR: {id1}, CIN: {id2}" like "CIR: 343481389, CIN: 347378" Please make sure to filter them out, to import both necessary Ids |
S |
licenseType | Contains the properties license type (if set) | S |
NOTE: In addition to these fields, all descriptions and properties can be exported (need to be activated in the api-key by our support).
You can get a list of all possible properties here: https://api2.v-office.com/export/properties
This will show a list of all properties that are valid for all customers
You can get a list of all properties that are possible for customers, exposed via the specified api key here (replace [key] with the api key): https://api2.v-office.com/export/properties?key=[key]
This will show a list of all properties (global and user-defined), that are actually beeing exported for the given api-key. If you want to see the complete list of possible properties add &all=true
You can also fetch properties, using the getProperties action, which will enable you to fetch properties on a customer aka member level (if CM+ is in use, you may want to specify the member ID, if it is a direct connection, this is not needed, since the api key will only contain one member):
parameter | description | type | required |
---|---|---|---|
member | Internal identifier for our customers (called members) | I | false |
A list of the units images.
Field |
Description |
type | possible values |
id |
image id | I | |
width | image width in pixel | I | |
height | image height in pixel | I | |
tag | image tag aka category | S |
A string which can have one of the following values (seperated by ,): birdsEye,buildingMain,facade_entrance,floorplan,activities,beach,mountains,scenery,neighbourhood,bbqarea,fitness,lobby,play,restaurant,sauna, wellness,whirlpool,pool,garden,livingroom,bedroom,bathroom,guestwc,balcony,terrace,kitchen,seaview,gardenview,poolview,landmarkview, bbq,bed,decorativeDetail,fireside,tv_multimedia |
titles | a list with the titles per language | LIST | |
titles-de | the image title in german | S | |
titles-en | the image title in english | S | |
titles-... | the image title can be available in multiple languages accessible via the 2 digit code within the titles list | S |
Example (of one image entry):
{ id: 123456, width: 1440, height: 961 tag: "fireside", titles: { de: "Kamin-/Ofen", en: "Fireplace" } },
Image download:
You can find and download the images under the following url:
https://dyn.v-office.com/image/[size]/[imageId].jpg
Possible sizes: tn, tnfx, tnx, tnxfx, s,sfx, m, mx, xl, xxl (sizes ending with fx will scale/stretch to fit exactly the size)
For example - medium size (600x400): m
A list of rooms with additional details, including beds.
Field |
Description |
type | possible values |
type |
type of this room | S | 'BEDROOM','LIVINGROOM','GALLERY'/*Empore*/,'OTHER' |
hasPrivateBathroom | does the room has a private / directly accessible bathroom | B | |
roomDarkeningOption | does the room has darkening like window shutters | B | |
wardrobe | does the room have a wardrobe | B | |
maxGuests | maximum number of guests this room is fitted for | I | |
beds | list of beds contained in this room | LIST |
kind:'SINGLE','SMALLDOUBLE','DOUBLE','KINGSIZE',BUNK', 'BUNK4THREE' type:'ORDINARY','BOXSPRING','SOFA','LOFT','FOLDAWAY_CLOSET','FOLDAWAY','WATER','FUTON','HAMMOCK','FLOOR_MATTRESS','AIR_MATTRESS' |
Example:
{ type: "BEDROOM", hasPrivateBathroom: false, roomDarkeningOption: true, wardrobe: true, maxGuests: 2, beds: [{ kind: "KINGSIZE", type: "ORDINARY", raisedBeds: false, openFootsection: true, extraLongBeds: false, childrenOnly: false, amount: 1 }] },
Contains Address related information all in the STRING data type.
Example:
address: { street: "Straßenname", housenumber: "7", postalcode: "28217", city: "Stadt", country: "DE" },
Contains longitude and latitude values
Example:
{ type: "Point", coordinates: [ 15.96399973376475, 28.14786475479639 ] },
Field |
Description |
type |
service |
service id (reference to the service) | I |
value |
price in cents |
C |
ask |
used to sort the price table (ascending / order from lower to higher), response should already return the prices in this order |
C |
calculation | one of "FLAT","NIGHT","DAY","WEEK","MONTH" (30 nights - will not be calculated partly, only applied every full 30 days),"PERC", |
S |
type |
one of RENT, FINALCLEANING, LINEN, HANDTOWELS, PET, CRIB, HIGHCHAIR, BABYBED, TRANSFER, VTAX, CITYTAX, HEATING, GAS, WATER, ELECTRICITY, INSURANCE, CANCELLATION |
S |
season |
name of the season |
S |
condition |
price is only valid if condition is met DEPRICATED! use guestRange and nightRange instead |
Object |
guestRange |
if present price applies only to this number of persons (OBP pricing), contains the parameters "min": INT, "max": INT |
Object |
nightRange |
if present price applies only if lenght of stay is in this range (LOS pricing) contains the parameters "min": INT, "max": INT |
Object |
surcharge |
if the serviceline is a person surcharge price (example: if guestrange is 3-4, arriving guests are 4 and the price is flat per person, the value will be applied twice, starting from the "min" of 3 days up to the number of guests. Basically(guests-("min"-1)) aka (4-(3-1)) = 2 | B |
fromdate |
Date as string (yyyy-MM-dd), from which the prices will be valid. |
D |
tilldate |
Date as string (yyyy-MM-dd), till which the prices will be valid. |
D |
NOTE: Prices with the calculation PERC, will not be included in the response but will be returned in the QuotePrices request, where the percentage value is already calculated into an total value
NOTE: FINALCLEANING should only every be applied once, if multiple are returned, the first applicable FINALCLEANING in the order should be applied, other types usually add up if multiple apply
Example:
"prices": [ { "service": 123332, "value": 15788, "ask": 32.0, "sourceId": 2331221, "calculation": "NIGHT", "type": "RENT", "fromdate": "2022-01-01", "tilldate": "2026-06-08", "nightRange": { "min": 1, "max": 2 }, "condition": { "minDays": 1, "maxDays": 2, "minPersons": 0, "maxPersons": 999999 "sourceId": true } }, ...]
Note: EarlyBird and Lastminute offers will only be applied, if the validfrom and validtill dates are within the stay period, the offer will not be applied if only the arrival day is within the valid dates.
Field |
Description |
type |
name |
name of the offer | ML |
validfrom |
Date as string (yyyy-MM-dd), the arrival may not be before this day |
D |
validtill |
Date as string (yyyy-MM-dd), the departure may not be after this day |
D |
minStay |
special offer is only valid if the customer stays at least this long (number in days) |
I |
type |
|
S |
timeSpan |
if type=’EARLYBIRD’: the arrival has to be at least this many days ahead if type=’LASTMINUTE’: the arrival may not be more than this many days ahead |
I |
discountType |
'XY','PERCENT','FLAT' |
S |
value |
if discountType=’XY’: Stay at least X days, pay for Y days + the days exceeding X days. The value of Y will be contained in the value field. The value of X will be the minStay value of the offer. In other words, if your stay fullfills the minStay, than the difference between the minstay(X) and value(Y), determines how many days are free of charge. Cannot apply multiple times, if X fits multiple times within the stay period (like X is 5 and the stay is 10, in this case the value of the free days still only apply once, even though minstay fits twice into the stay) For example: If minStay is 7 and value is 6, then you will have to pay 6 out of these 7 days. If you stay 10 days, you will have to pay 9 (minStay is fullfilled), if you stay 6 days you will have to pay 6 (minstay is not fullfilled) and if you stay 21 days you will have to pay 20 (minStay is fullfilled). if discountType=’Percent’:discount in percent (1000 = 10%) if discountType=’Percent’:discount in a fix value of the currency (1000 = 10€) The value needs to be devided by 100 to get the day / percentage / fix value. |
I / P |
services | ids of the services this discount is applied to (mainly used for the Percent discount type), can be missing / empty in which case the offer is applied to servicelines of the typ RENT. | LIST |
voucherCode | voucher code for "protected" special offers | S |
Example:
"offers": [ { "id": 123, "minStay": 2, "type": "PERCENT", "timeSpan": 180, "discountType": "XY", "value": 3400, "visible4interfaces": true, "name": {}, "services": [123, 1456] }, ...]
Field |
Description |
types |
fromdate |
Date as string (yyyy-MM-dd), from which the restriction will be valid. |
D |
tilldate |
Date as string (yyyy-MM-dd), till which the restriction will be valid. |
D |
minimumStay |
during the specified period, a booking has to be at least this many days long |
I |
minimumGap |
in order to prevent gaps that are too small to be booked, it is possible to specify a minimum gap (in days) between the arrival and the departure of the preceding guest. Applies only if the arrival is not on the same day as the preceding departure (meaning seamless bookings are still possible). |
I |
fillGaps |
if specified, these restrictions (minimumStay and minimumGap) are ignored if an existing gap can be closed. Bookings need to completely close a gap in order to be possible (like: the standard minimumStay is ignored, but the indirect minimumStay will be the length of the gap that should be filled instead). |
B |
fillGapsMinDays | The gap which can be filled needs to be at least that many days long, smaller gaps may not be filled | I |
ignoreArrivalDaysOnFillGap | If true, the standard arrivalDays can be ignored for the fill gap process | B |
ignoreDepartureDaysOnFillGap | If true, the standard departureDays can be ignored for the fill gap process | B |
arrivalDays |
if specified the arrival has to be on these days Contains fields from monday to sunday, which feature a bool value (true = arrival on that day possible, false = not possible) Exception: The arrival is on an existing departure or the departure is on an existing arrival respectively (may occur if there is a manually entered booking) |
OBJECT |
departureDays |
if specified the departure has to be on these days Contains fields from monday to sunday, which feature a bool value (true = departure on that day possible, false = not possible) Exception: The arrival is on an existing departure or the departure is on an existing arrival respectively (may occur if there is a manually entered booking) |
OBJECT |
Example:
restrictions: [{ rid: 12345, minimumStay: 5, minimumGap: 5, fillGapsMinDays: 5, fillGaps: true, lastMinuteLead: 7, ignoreArrivalDaysOnLastMinute: false, ignoreDepartureDaysOnLastMinute: false, ignoreArrivalDaysOnFillGap: false, ignoreDepartureDaysOnFillGap: false, minimumStayLastMinute: 4, minimumGapLastMinute: 0, fixWrongDay: false, arrivalDays: {7 items}, departureDays: {7 items}, fromdate: "2023-05-13T00:00:00Z", tilldate: "2023-06-24T00:00:00Z" },...]
Example:
"cancellationPolicy": { "gracePeriod": 3, "gracePeriodArrivalInMaxDays": 180, "defaultPenalty": 3000, "cancellationFlatFee": 5000, "byDaysTillArrival": [ { "daysBeforeArrival": 14, "penaltyInPercent": 9500 }, { "daysBeforeArrival": 30, "penaltyInPercent": 9000 }, { "daysBeforeArrival": 90, "penaltyInPercent": 4000 } ] }
Field | Description | type |
gracePeriod | Days after booking where no fee is due | I |
gracePeriodArrivalInMaxDays | gracePeriod is only valid if this condition is met (the arrival needs to be at least that many days in the future) | I |
defaultPenalty | Default penalty (cancellation fee in percent, based on the booking price) which will apply if no byDaysTillArrival-condition is met and the grace period is over. The default penalty can be 0. | P |
cancellationFlatFee |
Flat fee for each cancellation (in cents), if set (greater than 0), this fee will always apply even, if the cancellation itself may be free at that time | C |
byDaysTillArrival | List of specified extra conditions, each condition contains: daysBeforeArrival (the arrival needs to be equal or less days in the future for this penalty to apply) and penaltyInPercent (cancellation fee in percent, based on the booking price) | LIST |
fb_ + a specific number are the internal rating categories, please ignore these and use the avg value instead.
Example:
{ ...
arrival: "2024-09-08T00:00:00Z",
departure: "2024-09-15T00:00:00Z",
onDate: "2024-09-30T00:00:00Z",
forename: "Max",
surname: "M.",
lang: "de",
fb_28: 5,
comment: "Dies ist ein Beispiel Text einer Bewertung.",
avgRating: 4.5
... },
Field | Description | type |
arrival | Date of arrival | DT |
departure | Date of departure | DT |
onDate | Date where the feedback was created | DT |
forename | First name of the guest | S |
surname |
First digit of the last name of the guest with a dot after it. Example: Mustermann would be returned as M. |
S |
lang | 2 digit Language code of the feedback, like "de" | S |
comment | The comment, the guest left with the feedback | S |
avgRating | Average rating based on the category ratings | Number |
fb_ + a specific number are the internal rating categories, please ignore these and use the avg value instead.
Example:
ratings: {...
fb_count: 124,
fb_28: 4.702479362487793,
fb_avg: 4.514904975891113,
...}
Field | Description | type |
fb_count | Total number of feedbacks for this unit | I |
fb_avg | Average rating score for this unit | Number |
parameter | description | value |
---|---|---|
changeOver | include possible changeover days | true |
minStay | include minimum stay information | true |
facilitid | include facility-id (may be empty, if unit does not belong to a facility) | true |
updatedSince | show only availabilities, that have been updated since this date | e.g. 2015-06-05T09:53:43Z |
{units: [
{
_id: 23423,
availability: [NNNYYYYNNN...],
changeOver: [XXXXIIIIOOOCCC....],
minStay: [3333377777777333...],
availabilityUpdate: "2015-06-05T09:53:43Z"
},
{
_id: 23424,
....,
}
]}
Each section consists of an array of days. The first day is the value of "availabilityUpdate". Max size is 1095.
N = not available
Y = available
Q = on request
The arrivalday is marked as not available, the departureday is marked as available.
The array will not be larger than the last booking, the last item in the array stands for the rest of the period. So if there are no bookings yet, you will only get [Y].
X=no action possible, C=check-in/out, O=check-out only, I=check-in only
A booking has to be at least this long.
{ "services": [ { "_id": 446, "calculation": "NIGHT", "constrain": true, "mandatory": true, "type": "RENT", "charge": "CUSTOMER", "ask": 1000, "provider": "OWNER", "name": { "en": "Rent", "de": "Miete" } }, { "_id": 449, "calculation": "FLAT", "mandatory": true, "type": "FINALCLEANING", "charge": "CUSTOMER", "ask": 2000, "provider": "SELF", "name": { "en": "Finalcleaning", "de": "Endreinigung" } }, ...]}
field | description | type |
---|---|---|
name | name of the service (in multiple languages, if given) | ML |
summary |
one of "ADD_NO_SHOW","SHOW","EXCLUDE" Defines if the service should be added or/and listed in the inclusive price or separately Examples: rent SHOW, surcharge ADD_NO_SHOW, bedlinen EXCLUDE - in this case the shown inclusive price should include rent and surcharge but only display that it includes rent, while additionaly displaying beldinen as separate cost point (the total booking cost needs to include all mandatory costs, of course) |
|
calculation | one of "FLAT","NIGHT","DAY","WEEK","MONTH","PERC","USAGE" | S |
constrain | if true this service has to be charged the whole stay (if mandatory and the guest stay exceeds the service application period, it won't be bookable) | B |
perAdult |
if true, prices are multiplied by the number of adults (if the service is not mandatory (meaning it is a optional service), the prices should only be multiplied by the number selected (additionally booked) by the guest) |
B |
perChild |
if true, prices are multiplied by the number of children (if the service is not mandatory (meaning it is a optional service), the prices should only be multiplied by the number selected (additionally booked) by the guest) |
B |
perBaby | This should currently have no effect, since we do not calculate costs per baby, meaning, that you can ignore this, even if it is set to true | B |
minChildAge | if perChild is true, prices are multiplied by the number of children that are at least this old | I |
maxChildAge | if perChild is true, prices are multiplied by the number of children that are not older than this | I |
mandatory | if true, customers have to pay for this service | B |
type | Appendix B | S |
surcharge | if true, prices are multiplied if the number of persons is equal or greater than the minimum number of persons specified in the price-condition (guestRange-min see unit-prices), for example "min"=3 means, that if 3 guests stay, the surcharge will be applied once, twice if it is 4 etc. | B |
serviceLimits | A list of service limits, the same you can request via quotePrices (only included in the response, if the request contains includeServiceLimits=true) |
parameter | description | value | type |
---|---|---|---|
description | include descriptions | true | B |
{"regions":[ { _id:3, name:{ "de":"Alle Orte" "en":"All regions" }, path:{ "de":"Alle-Orte", "en":"All-regions" } }, { _id:608, leveltype:"REGION", name:{ "de":"Ostsee" }, path:{ "de":"Ostsee", "en":"Ostsee" }, descriptions:{ "de":"Die Ostsee ist ...", "en":"The Baltic Sea is...." }, parent:3 }, { _id: 23424, ...., } ]}
field | description | type |
---|---|---|
name | ML | |
description | ML | |
path | path on the vOffice CMS homepage | ML |
leveltype | one of: 'COUNTRY','REGION','AREA','CITY','DISTRICT' or empty if other | S |
parent | id of the parent region | I |
parameter | description |
---|---|
lastid | include the id of the last message received in order to get the next page |
The content of the messages and attachements are provided by encrypted urls which are valid for three days.
List / search for units. Useful for homepages, NOT intended for interfaces to OTAs / channelmanager.
Action name: searchUnits
name | description | format | required |
---|---|---|---|
fields | requested unit properties for the search result, see below | Object | true |
filter | filter for the search result | List | true |
warnings | wether to check for warnings, only aplicable when from and till is set in the filter | B | |
sorting | can be a unit property or one of: 'price', 'random', 'rating', 'stars' | S | |
ids | unit ids (will disable search, used for subsequent calls (pagination)) | List | |
max | maximal number of results, default is 18, max is 128 | I | |
groupFacilities | limit the number of searchResults for a single facility | I | |
fuzzy | do a fuzzy search (only relevant for flexible search, see below "Understanding flexible / fuzzy / alternative search") | B | |
alternatives | show alternative matches, see below "Understanding flexible / fuzzy / alternative search" | B |
NOTE: Live search is only allowed with pagination in place. If you've got more than 64 units, subsequent results may only be fetched on user interaction (e.g. pagination or infinite scroll).
On first call, you will get a list of all unit-ids in the result-set and the first page of data. To get other pages, you need to add a sublist of these ids to the request.
Requested fields can be all unit properties (global and custom ones). See unit export for possible values. In addition these special fields can be requested:
name | description |
---|---|
calc.total | total price for the selected period |
calc.oTotal | |
calc.discountName | |
idxImage | index image path |
A field is specified as {'u.fieldname':{filter:projection}}, see projection for details.
You can filter for all unit properties (global and custom ones). See unit export for possible values.
Append '_min' or '_max' to the fieldname for integer values, like 'beds_min'.
In addition these special values can be used:
name | description | type |
---|---|---|
from | yyyy-MM-dd | D |
till | yyyy-MM-dd | D |
region | region path, like "France/Provence/Cote.d-Azur/Vence" | S |
regionid | I | |
unitgroupid | unit group id | I |
facilityid | facility id | I |
adults | I | |
children | I | |
childrenAges | required if prices depend on age of children (example: "10,12" - the ages of the children as string, seperated by a ,) | S |
babys | I | |
name | (first letters of) unit name OR unit id | S |
offers | all units with an offer | B |
offerid | id from the special offer | I |
price_min | I | |
price_max | I | |
bedrooms_min | I | |
bedrooms_max | I | |
bathrooms_min | I | |
bathrooms_max | I | |
nights_min | search for a possible booking in the selected period with at least this many nights, see below "Understanding flexible / fuzzy / alternative search" | I |
nights_max | search for a possible booking in the selected period with max this many nights, see below "Understanding flexible / fuzzy / alternative search" | I |
If "nights_min" / "nights_max" is less then the number of nights between "from" and "till" it will result in a so called "flexible search".
In total you have these options to offer more results:
Option | flexible search | alternatives | fuzzy | result |
---|---|---|---|---|
A | false | false | is ignored (always false) | only exact matches will show up (not recommended because it leads to lower conversion-rate) |
B | false | true | is ignored (always true) | show alternatives if no exact match can be found, includes expanded search period* |
C | true | false | is ignored (always false) | search for possible bookings in the selected period, all returned periods will respect nights_min and nights_max |
D | true | true | false | search for possible bookings in the selected period, returned periods are prioritized when matching nights_min and nights_max |
E | true | true | true | like D but with expanded search period* |
* "fuzzy" will expand the search for free periods that end 7 days before "from" latest or start 7 days after "till" earliest.
During a flexible search you can use "splitAlternatives" to get exact matches in a separate result field called "matchingPeriods" instead of in "alternatives", see below. However, this is not needed, as you can distinguish between the two by inspecting "foundExactMatch".
When using one of these options, you will see these extra fields in the result:
field | description |
---|---|
foundExactMatch | this will be true only if one or more periods have been found that match exactly the search criteria |
alternatives |
Option B: these will include alternatives if no exact match is found
|
matchingPeriods | only when using "splitAlternatives": periods that exactly match the search criteria |
{
"fields": {
"u.name": {"filter": "vautolang"},
"u.loc.coordinates": {},
"u.path": {"filter": "vlang"},
"u.idxImage": {},
"u.calc.total": {"filter": "vcurrency"},
},"filter": {
"adults": "4",
"children": "1",
"babys": "0"
},
"sorting": "random"
}
NOTE: Sorting or filtering by price is more expensive and will cost more credits.
{
ids: [2344,2342343,3423423,...],
units: [
{name: 'App. 04', type: 'Ferienwohnung'},
{name: 'App. 05', type: 'Ferienwohnung'},
....
],
ok: true
}
Note: On first call, you will get a list of all unit-ids in the result-set and the first page of data. To get other pages, you need to add a sublist of these ids to the request.
Get unit data for a single view. Useful for homepages, NOT intended for interfaces to OTAs / channelmanager.
Action name: getUnit
name | description | format | required |
---|---|---|---|
fields | requested unit properties for the search result, see below | Object | true |
id | unit id | I | true unless code is give |
code | unit code | S | false |
pricetable | additionally request a pricetable (pricelist optimized for presentation) | B | false |
Requested fields can be all unit properties (global and custom ones). See unit export for possible values.
A field is specified as {'u.fieldname':{filter:projection}}, see projection for details and search for example.
Get the availability, possible arrival/departure days and minimum stays for one unit. Intended for a single unit view.
Useful for homepages, NOT intended for interfaces to OTAs / channelmanager.
Action name: getCal
name | description | format | required |
---|---|---|---|
unit | unit id | I | true |
{ "availability": ["N", "N", "Y",... ], "changeOver": ["X", "X", "X", "X",... ], "availabilityUpdate": "2015-07-18T01:00:03Z", "minStay": [7, 7, 7, 7, 5, 5, ....] }
name | description | type |
---|---|---|
availability | availability: N=not available, Y=available, Q=on request; Arrival = N; Departure = Y | List |
minStay | minimum stay in nights (the highest minStay during the stay period needs to be fullfilled, if not disabled via another configuration like fillGaps or special offers) | List |
changeOver | X=no action possible, C=check-in/out, O=check-out only, I=check-in only | List |
availabilityUpdate | timestamp the calendar was updated, first entries of each section is this day | DT |
This query greatly reduces the complexity of building your own booking process on an external website. It calculates for a given time period the prices, taking into account things like special offers, booking restrictions, price conditions etc.
See Booking -> "quote prices" for details.
Search for a contact history by phonenumber.
Action name: searchPhoneNumber
name | description | format | required |
---|---|---|---|
nr | phonenumber | E164 (e.g. +41446681800) | true |
{ "trackingId": "i-0dd64dd37218bccef|c34e17f4-f384-45ec-864b-3d96385dfdbb", "intNr": "+49 40 99999XXX", "nr": "040 99999XXX", "description": "Hamburg", "id": 462723, "label": "Mustermann, Max", "image": "https://....", "unitcount": 1, "units": [ { "id": 2133, "code": "Grüntal I App.05" } ], "bookingcount": 16, "bookings": [ { "id": 3528776, "label": "Grüntal I App.05: 20.11.20 - 22.11.20" }, { "id": 3198718, "label": "Grüntal I App.05: 04.11.20 - 06.11.20" }, { "id": 3244487, "label": "Grüntal I App.05: 31.10.20 - 02.11.20" } ], "ok": true }
name | description |
---|---|
id | contact-id |
unitcount | number of units in case this contact is an owner |
units | units this contact is owner of |
bookings | lastest bookings made by this contact |
Check if a coupon code is valid and cashable online.
Action name: checkCoupon
name | description | format | required |
---|---|---|---|
code | coupon code | true |
{
"trackingId": "i-0dd64dd37218bccef|1a0901da-f074-4a33-9213-b4ccb1cf2693",
"ok": true,
"amount": 10000,
"available": 10000
}
name | description | format |
---|---|---|
ok | If true, the coupon is applicable / valid | B |
amount | The total credit amount, the coupon had, when it was created | C |
available | The credit amount, which is currently left on the coupon | C |
You can use the validateVoucher action to check if the vouchers are valid, you should do that, before using the voucher codes in other actions.
Request example (Json payload):
{ "code": "[VOUCHER-CODE]" }
Response example (for an valid voucher):
{ ... "voucher": { "name": "Name des Vouchers, wie im Backend angegeben" }, ... }
Our suggested approach would be to store the voucherCode (temporarily) once it was successfully validated and submit it with all the following requests if it is needed (like price and booking requests).
Because the voucherCodes can be restricted to certain Units/UnitGroups you should try to get the reduced price first by calling quotePrices with the code added on the root of the JSON Payload
{ ... "voucherCode": "[VoucherCode]", ... }
While executing the final book request, the voucherCode has also to be submitted:
{ ... "voucherCode": "[VoucherCode]", ... }
This query greatly reduces the complexity of building your own booking process on an external website. It calculates for a given time period the prices, taking into account things like special offers, booking restrictions, price conditions etc.
Action name: quotePrices
name | description | format | required |
---|---|---|---|
unit | vOffice unit id | I | true |
fromdate | arrival date | D | true |
tilldate | departure date | D | true |
adults | number of adults | I | |
children | number of children | I | |
babys | number of babys that do not require a full-sized bed | I | |
childrenAges | required if prices depend on age of children (example: "10,12" - a string containing the children ages, separated by a ,), if not specified while a children count is being send, the age specific prices may all be returned and need to be handled actively | S | |
includeServiceLimits | include service limits (maxPerBooking, maxDaysAfterBooking, minDaysBeforeArrival, blockedByDate) in result | B | |
petsCount | number of pets | I | |
checkTravelInsuranceIsSetup | when set to true, it will check the members configuration for travelinsurances | B |
{"mandatory": [{ "service": { "constrain": true, "mandatory": true, "type": "RENT", "id": 446, "name": "Miete" }, "price": 5500, "calculation": "NIGHT", "charge": "CUSTOMER", "season": "Saison C", "fromdate": "2015-09-20", "tilldate": "2015-09-25", "timespan": 5, "total": 27500, "timeLabel": "Nächte" "discountName": "Name of the discount", // only present if a special offer applies to this service "specialOffer": 1234, // only present if a special offer applies to this service "oPrice": 6000, // only present if a special offer applies to this service "oTotal": 30000 // only present if a special offer applies to this service }, { "service": { "mandatory": true, "type": "FINALCLEANING", "id": 449, "name": "Endreinigung" }, "price": 4500, "calculation": "FLAT", "charge": "CUSTOMER", "total": 4500 }.... }, omandatory": [{ ..... }], "optional": [{ ..... }], "onsite": [], "onsiteOptional": [], "usage": [], "errors": {}, "warnings": {}, "paymentSchedule": { "prepayment": { "date": "2015-07-31", "amount": 8300, "percent": 2500 }, "rest": { "date": "2015-08-30", "amount": 24950, "percent": 7500 } }, "optionValidFor": 3, "travelInsuranceIsSetup": false, "deposit": { "amount": 25000, "location": "WITH_FINALPAYMENT" }, "serviceLimits": [{ "449": { "maxPerBooking": null, "maxDaysAfterBooking": null, "minDaysBeforeArrival": 7, "blockedByDate": true } }], "currency": "EUR" }
name | description | type |
---|---|---|
mandatory | services that need to be paid for, for example rent | List |
omandatory | original price of services that need to be paid for, for example rent (useful if mandatory is a reduced price, but you still need/want the original service price) | List |
optional | services that can be booked optionally, for example bed linen | List |
onsite | services that need to be paid on site, they will not be invoiced by vOffice | List |
onsiteOptional | services that need to be paid on site, but can be booked optional | List |
usage | services that need to be paid by usage, for example electricity, gas etc. | List |
errors | errors that are blocking the booking process, for example the unit is already occupied in the selected period | Object |
warnings | warnings that are not blocking the booking process | Object |
paymentSchedule |
contains payment schedule types and their details: prepayment, rest (payment), total (full payment) and onsite (payment) with date (when to pay), amount (in cents), percentage (of total payment) and includesDeposit (cent value if deposit has to be paid with this payment schedule) fields deposit can have its own schedule, if the regular payments have other schedules, in this case, the percent field will be missing, since the deposit is not a part of the total payment You may not consider the deposit price for your displayed total price and rather substract it. If includesDeposit is in a schedule without percent, that means, do not add it to the total, if it is within a schedule with precent, substract the deposit amount from the total, to get the total price without deposit (as displaying the price with deposit would show a inflated price. |
Object |
optionValidFor | if making an option is possible in addition to a booking, these are the days the option will be valid for | I |
travelInsuranceIsSetup | if true, member has support for booking a travelinsurance | B |
deposit | deposit information with the amount and location (location = where/when the deposit has to be paid) | List |
serviceLimits |
A list of service limits with the service id being the key of the list and the limit of this service id being the value. The value includes maxPerBooking, maxDaysAfterBooking, minDaysBeforeArrival, blockedByDate (blocked by date is a bool, which tells you if the currently requested time period does alredy block the service application due to maxDaysAfterBooking or minDaysBeforeArrival not being fullfilled) Service limits are not mandatory fields for our customer, therefore it can be empty / missing if the customer did not specify any limits, in this case there is no limit, but you may want to add an artifical one for your frontend, if you do not want to allow guests to select a huge amount (for example if no limit, limit = guests * nights of stay etc. depending on the service type or/and your own preference) |
List |
currency | the currency of the returned prices as iso currency code | CC |
name | description |
---|---|
notavailable |
the unit is not available for the given search parameters |
nopetsallowed | the unit does not allow pets |
maxbedsblock | too many persons, booking is not possible (guest count exceeds total bed count) |
maxbeds | too many persons, should request bunkbeds (guest count exceeds standard bed count) |
minpersons | not enough persons |
maybeavailable | no prices found for the rental |
badday | not a valied arrival / departure day (allowed days can be found in the details) |
mingap | if arrival is not on a previous departure (aka a seamless booking), there needs to be a minimum gap, which is not fullfilled |
minstay | the minstay criteria is not fullfilled |
minstayfill | minimum stay unless a gap is filled |
Changelog
2022-02-08
- new optional parameter checkTravelInsuranceIsSetup
Make an online booking or option.
Action name: book
name | description | format | required |
---|---|---|---|
reservation.customer | customer information, see below | Object | true |
bookings | List of booking information, currently only one booking possible per request, see below | List | true |
action |
|
S | true |
commission | commission charged by partner in cents | C | false |
extraCommission | Info about additional third party commission | Object | false |
couponCode | Coupon-Code, needs to be checked before using here | S | false |
reservation.externalNumber | external booking ID if applicable | S | false |
travelInsurancePlan | insurance planid like 'RR06' | S | false |
travelInsuranceAmount | insurance plan amount (in cents) | I | false |
name | description |
---|---|
title | |
forename | |
surname | |
company | |
mainAddress.street | |
mainAddress.housenumber | |
mainAddress.postalcode | |
mainAddress.city | |
mainAddress.country | |
phone | |
telcom | office phone |
fax | |
mobile | |
currency | |
preferredLanguage | SO 639-1 |
message | additional message from guest, will be shown in the inbox |
name | description |
---|---|
unit | unit id |
adults | |
children | |
babys | |
fromdate | yyyy-MM-dd |
tilldate | yyyy-MM-dd |
servicelines | list of servicelines, see below (required to ensure the booking is created with the same price) |
childrenAges | required if prices depend on age of children (example: "10,12") |
name | description |
---|---|
service.id | |
amount | as Float |
price | in cents |
discountName | |
description | |
season | |
fromdate | yyyy-MM-dd |
tilldate | yyyy-MM-dd |
specialOffer | |
timespan |
|
timeLabel |
|
total | |
... |
The total will be calculated as: PRICE * AMOUNT * TIME (e.g. nights). Amount should be empty if not applicable, for example for rent.
name | description |
---|---|
amount | in cents |
description | who is charging this commission |
{"reservation": { "customer": { "mainAddress": { "country": "DE", "street": "Karpendiek 23", "postalcode": "23730", "city": "Neustadt" }, "title": "Herr", "forename": "Jens", "surname": "Hoff", "email": "knoffhoff@gmx.de", "mobile": "56465" } }, "action": "booking", "bookings": [{ "unit": 2351, "adults": "2", "children": "1", "babys": "0", "fromdate": "2015-10-02", "tilldate":"2015-10-07", "servicelines ":[{ "service ":{ "id": 4465 //rent }, "price": 9000, "season": "Saison C", "fromdate": "2015-10-03", "tilldate": "2015-10-08", }, { "service":{ "id ":4495 //final cleaning }, "price ":6500 }] }], "travelInsurancePlan": "RR06", "travelInsuranceAmount": 5000 }
As result you will get the reservation id (unique for all voffice customers) and number (unique only per customer), customer id and number and booking id. The booking id is necessary to be able to assign changes later via getUpdatedBookings.
{ reservation: { "id": 612349, "nr": "19204", "token": "sdfksdfj...", "guestToken": "sdfksdfj...", "customer": { "id": 757456, "nr": "26243" }, "bookings": [{ "id": 596995 }], "paymentSchedule": { .... }, }, "paymentMethods": { ... }, ok: true }
See Online-Payment for details on fields "paymentMethods" and "paymentSchedule"
After booking you should show a confirmation page and a button for the guest to get to his guest-app:
<a href="https://guests.v-office.com/#/login/token/{{result.guestToken}}" class="btn btn-primary btn-lg active" role="button" > Your Booking in your guest-app </a>
The account must first be activated to book insurance. When booking, the insurance can then optionally be booked by transmitting the parameters travelInsurancePlan and travelInsuranceAmount.
See Booking -> "getTravelInsurancePlans" for details.
parameter | description | value |
---|---|---|
updatedSince | required, max 7 days in the past | e.g. 2015-06-05T09:53:43Z |
channelPrices | optional, boolean, show channel Prices | true or false (default: false) |
{ "trackingId": "i-0dd64dd37218bccef|eba14461-5e6a-463c-8fe0-c19736f21e71", "bookings": [ { "id": 3198434, "fromdate": "2021-02-13", "status": "CONFIRMED", "tilldate": "2021-02-21", "lines": [ { "type": "RENT", "total": 44000, "fromdate": "2021-02-13", "price": 5500, "tilldate": "2021-02-21" } ] }, [...] ], "ok": true }
List one specific Booking made by the supplied key.
parameter | description | value |
---|---|---|
bookingId | required, id of the booking entry | integer |
channelPrices | optional, boolean, show channel Prices | true or false (default: false) |
{ "trackingId": "i-0dd64dd37218bccef|eba14461-5e6a-463c-8fe0-c19736f21e71", "booking": { "id": 3198434, "fromdate": "2021-02-13", "status": "CONFIRMED", "tilldate": "2021-02-21", "lines": [ { "type": "RENT", "total": 44000, "fromdate": "2021-02-13", "price": 5500, "tilldate": "2021-02-21" } ], }, "ok": true }
In order to manage bookings (get, update, add payments etc.), you will need a second token.
vOffice will generate a link for each booking with a custom token that will look like:
yourdomain/[language-code/]manage?token=sdfk23sdf...
This token is needed to get or update a booking. The link can be placed in any document intended for the guest / customer.
The token is also part of the returned value of each new booking made.
The booking endpoints may return a number of different status codes, the ones following are the important ones, there can be others, but these can be ignored / should not occour in the normal process.
Get a booking or option. It is intended to offer guests a possibility to update their booking. Please use "getUpdatedBookings" to look for changes in your bookings.
Action name: getBooking
This action is only usable for direct connections, CM+ connections do not support this action at the moment.
name | description | format | required |
---|---|---|---|
token | booking token generated by vOffice | S | true |
includeServiceLimits | include service limits (maxPerBooking, maxDaysAfterBooking, minDaysBeforeArrival) in result |
Update a online booking or option.
Right now, you can only add services and update Guests. Once you update a booking or option, the status will automatically become "CONFIRMED".
Action name: updateBooking
name | description | format | required |
---|---|---|---|
token | booking token generated by vOffice | S | true |
bookings | updated bookings, this set consists of the booking ids as the keys and the updates as the value, see below | SET | true |
noStatusChange | leave the booking-status unchanged | B |
name | description | format | required |
---|---|---|---|
addedServicelines | see online booking for details | LIST | false |
addedGuests | LIST | false | |
changedGuests | you can only update the birthdate! | LIST | false |
removedGuests | LIST | false |
{"bookings":{ "710560":{ "addedServicelines":[ { "service":{ "id":480 }, "price":1000, "amount":1, "total":1000 } ] } }, "token":"eyJhbGciOiJ..." }
As result you will get the reservation status:
{ "reservation":{ "nr":"20599", "paid":0, "outstanding":49600, "total":50600, "id":726544, "paymentSchedule":{ "total":{ "date":"2015-11-14", "amount":37200 } } }, "ok":true }
{"bookings":{ "710560":{ addedGuests:[ { // enter a known contact as guest: id: 34343 }, { // or create a new contact: surname: 'Doe', forename: 'John', birthdate: '1984-01-01' } ], removedGuests: [ { guestId: 234234 } ], changedGuests: [ { guestId: 234235, "changes": { "contactId": 5678910, "birthdate": "1980-04-03" } } ] } }, "token":"eyJhbGciOiJ..." }
DEPRICATED! Do not use any more. Get a specified document (for example 'terms and conditions').
Action Name: getDoc
Fields in the json-encoded "data" parameter:
name | description | format | required |
---|---|---|---|
lang | S | true | |
type | specifiy required document, currently only 'gtc' supported | S | true |
In the response of "book" and "getBooking" you will find a section called "paymentMethods" which will list all possible payment methods for this booking. The returned list may vary depending on parameters like arrival date, booked property etc.
In addition you will find "paymentSchedule" which tells you what amount is due when.
{ "reservation": { "id": 17203234280, "nr": "716313", ...., "paymentSchedule": { "prepayment": { "date": "2021-01-22", "amount": 42200 }, "rest": { "date": "2022-04-12", "amount": 98680 } } }, "paymentMethods": { "PAYPAL": { "id": 1012, "type": "PAYPAL", "paymentTest": false, "button": { "cmd": "_xclick", "business": null, ... }, "paymenturl": "https://www.paypal.com/cgi-bin/webscr" }, "STRIPE": { "id": 4437, "type": "STRIPE", "paymentTest": false }, "BANKACCOUNT": { "id": 99974, "type": "BANKACCOUNT", "paymentTest": false, "bankaccount": { "iban": "DE65 2307 0700 5838 7607 00", "swift": "DEUTDEDB285", "institution": "Deutsche Bank AG" } } }
The Stripe payment uses our key/account and not the key of the customer.
The customers have to connect their stripe accounts via "Stripe Connect" to our key/account.
They can do that, by adding Stripe as payment method in our interface and then pressing the link Account button in that same ui section.
They will have to redo the linking process in order to apply the de/activation of the test mode, which they can de/activate via checkbox in the same ui section.
1. include Stripe.js on your site:
<script src="https://js.stripe.com/v3/"></script>
2. include a Button to pay with Stripe.
3. once the Button is clicked you call action "checkoutPayment" and redirect to stripe.
Sample code:
var req = { id: r.id, // id of reservation nr: r.nr, // nr of reservation amount: amount, //amount in cents to be paid paymentMethodId: 4437, // id of payment-method rootUrl: 'my.site.com' // after payment success or failure will be redirected here }; doPost('checkoutPayment', req) .then(res => { // since the customers are connected to our account/key via Stripe connect // you have to use these public keys for test / live mode in order for the request to work var stripe = Stripe(pm.paymentTest ? 'pk_test_62sy8HrukNuTd7ko6lZcyJcv00CtNmm5oo' : 'pk_live_lHTr8iFxjPqtC0aYmkQYZuzZ00qtUAATYP', { stripeAccount: res.accountId }); stripe.redirectToCheckout({ sessionId: res.sessionId }).then(function (result) { if (result.error) { this.error = { reasonText: result.error.message }; } }); }).catch(e => { ...error handling });
Todo after payment return:
The redirect urls will be setup like this:
success_url: "${req.rootUrl}payment?result=success&token=>oken=$guestToken",
cancel_url: "${req.rootUrl}payment?result=canceled&token=>oken=$guestToken",
You will need to setup a page which shows the payment result. In addition you should show a button to get to the guest-app:
<a href="https://guests.v-office.com/#/login/token/{{parameters.gtoken}}" class="btn btn-primary btn-lg active" role="button" > Your Booking in your guest-app </a>
Subscribe to newsletter via double opt-in
Action name: subscribe
name | description | format | required |
---|---|---|---|
setup.listId | id of the mailjet list to subscribe to | I | true |
setup.newsletterName | title of newsletter shown to contact | S | false |
setup.templateId | id of the email template to send as confirmation email | S | false |
setup.registrationEmailSubject | subject of confirmation email | S | false |
form.email | email address to subscribe | S | true |
form.[addition-var] | you can add custom defined variables, but they need to be added to mailjet prior to usage | S | false |
{ "setup":{ listId: 23324, }, "form":{ email: 'test@test.de', }, }
Common values for all GuestApp-Requests:
Parameter | Description | Type |
---|---|---|
lang | Language Code (ISO-639-1) | S |
key | Guest App Token | S |
Used to send the GuestApp-Url with token via E-Mail to the current customer (does not need to be a guest) that booked the unit.
{
"locationToken":"eyJhbGciOiJIUzI1NiJ9.eyJ1bml0IjoxMDg2NDh9.Hetpzh2d_u0pNJgnImXq20rvKSW2Tx61IARSiVNon44"
}
{
"ok":true
}
Get all information about the given reservation and bookings. The reservation is set by the key/token
{}
{
"trackingId":"...",
"bookings":[
{
"id":22554865,
"availableLanguages":[
"de",
"en"
],
"currency":{
"code":"CHF",
"symbol":"CHF",
"symbolPosition":"TRAILING_SPACE"
},
"preferredLanguage":"de",
"reservationNumber":"00001",
"reservationDate":"2022-01-20",
"bookingId":9319655,
"customer":{
"id":6351986,
"title":"Herr",
"forename":"Christian",
"surname":"Mustermann",
"street":"Dünenweg",
"housenumber":"1h",
"city":"Neustadt in Holstein",
"postalcode":"23730",
"country":"DE",
"email":"cm@gmail.de",
"mobile":null
},
"status":"CONFIRMED",
"arrivalStatus":null,
"from":"2022-03-30",
"till":"2022-04-08",
"arrivalTime":null,
"departureTime":null,
"totalDays":9,
"totalPersons":2,
"personCountDetails":{
"adults":2,
"children":0,
"babys":0
},
"unit":{
"id":12345,
"title":"App. 01",
"image":{
"urlThumb":"//www.v-office.com/dyn/image/p.tnx/2721181.jpg",
"url":"//www.v-office.com/dyn/image/p.m/2721181.jpg"
},
"city":"Westerland",
"url":"http://hp.v-office-cms.com/de/Schleswig.Holstein/Nordsee/Sylt/Deich.01"
},
"bookedServices":[
{
"id":null,
"serviceId":null,
"name":"Inklusivpreis",
"info":"Miete",
"price":108000,
"total":108000,
"amount":null,
"timespan":null,
"from":null,
"till":null,
"calculation":null,
"perAdult":null,
"perBaby":null,
"perChild":null
},
...
],
"availableExtras":[
{
"id":22571,
"name":"Handtücher",
"price":1000,
"calculation":"DAY",
"limits":{
"maxPerBooking":1,
"maxDaysAfterBooking":null,
"minDaysBeforeArrival":null
}
},
...
],
"guests":[
],
"guestSuggestions":[
{
"GuestId":null,
"Tilldate":null,
"Fromdate":null,
"ContactId":123456,
"Birthdate":null,
"RegistrationPersonGroup":null,
"City":"Neustadt in Holstein",
"Country":"DE",
"Forename":"Christian",
"Gender":null,
"Housenumber":"1h",
"IdExpiry":null,
"Iddate":null,
"KnownIdType":null,
"Nationality":null,
"Personalid":null,
"Postalcode":"23730",
"Street":"Dünenweg",
"Surname":"Mustermann",
"Surname2":null,
"Title":"Herr"
}
],
"payments":[
],
"paymentSchedule":{
"prepayment":{
"date":"2022-02-03",
"amount":21100,
"includesDeposit":false
},
"rest":{
"date":"2022-03-16",
"amount":84400,
"includesDeposit":false
}
},
"registrationForm":[
{
"id":364,
"provider":"DEMO",
"useGuestNationality":"VISIBLE",
"useGuestGender":"VISIBLE",
"useGuestRegistrationPersonGroup":"VISIBLE",
"useGuestForename":"REQUIRED",
"useGuestSurname":"REQUIRED",
"useGuestSurname2":"REQUIRED",
"useGuestBirthdate":"REQUIRED",
"useGuestStreet":"VISIBLE",
"useGuestHousenumber":"VISIBLE",
"useGuestPostalcode":"VISIBLE",
"useGuestCity":"VISIBLE",
"useGuestCountry":"VISIBLE",
"useGuestKnownIdType":"VISIBLE",
"useGuestPersonalid":"VISIBLE",
"useGuestIddate":"VISIBLE",
"useGuestFromdate":"VISIBLE",
"useGuestTilldate":"VISIBLE",
"personGroups":[
{
"code":"Erwachsener",
"label":"Erwachsener"
},
{
"code":"Kind",
"label":"Kind"
},
...
]
}
],
"options":{
"countries":[
...
{
"id":"DE",
"text":"Deutschland",
"used":true
},
...
],
"titles":[
"Frau",
"Herr",
"Familie",
"Eheleute"
]
},
"setup":{
"askForEstimatedArrival":true,
"askForEstimatedDeparture":true,
"checkinFrom":"08:00:00.000",
"checkinTill":"20:00:00.000",
"checkoutFrom":"08:00:00.000",
"checkoutTill":"20:00:00.000",
"colorBackground":null,
"colorForeground":null,
"colorPrimary":null,
"colorSecondary":null,
"fontFamily":null,
"logoImageId":null,
"showCheckin":true,
"showCheckout":true,
"showFeedback":true,
"showGuides":true,
"showLocations":true,
"showTravelinfo":true
"showPayments":true
"showAddServicelines":true
}
}
],
"ok":true
}
Get all reservations belonging to the customer of the current reservation. Useful for displaying the past or upcoming reservations.
{}
"trackingId":"...",
"reservations":[
[
{
"token":"eyJhbGciOiJIUzI1NiJ9.eyJyZXNlcnZhdGlvbiI6MjI1NTQ4NjR9.P4ZhFbDwkcbpt06fXUBW5n3KX92TYZZA1ZHwpotzg2o",
"reservationNumber":"00093",
"from":"2022-01-27",
"till":"2022-02-02",
"totalDays":6,
"totalPersons":2,
"personCountDetails":{
"adults":2,
"children":0,
"babys":0
},
"unit":{
"title":"App. 01",
"image":{
"urlThumb":"//www.v-office.com/dyn/image/p.tnx/2721181.jpg",
"url":"//www.v-office.com/dyn/image/p.m/2721181.jpg"
},
"city":"Westerland"
}
}
],
[
{
"token":"eyJhbGciOiJIUzI1NiJ9.eyJyZXNlcnZhdGlvbiI6MjI1NTQ4NjV9.icKtkL08Cb7VlDahMmCRMpPP2mmi5CFbhnPxegcm7wE",
"reservationNumber":"00094",
"from":"2022-03-30",
"till":"2022-04-08",
"totalDays":9,
"totalPersons":2,
"personCountDetails":{
"adults":2,
"children":0,
"babys":0
},
"unit":{
"title":"App. 01",
"image":{
"urlThumb":"//www.v-office.com/dyn/image/p.tnx/2721181.jpg",
"url":"//www.v-office.com/dyn/image/p.m/2721181.jpg"
},
"city":"Westerland"
}
}
]
],
"ok":true
}
Providing the editorial content managed inside of vOffice.
{}
{
"locations":[
{
"id":2861,
"section":"locations",
"vellcomeCategory":15,
"title":"Zur goldenen Möwe",
"filetype":"LOC",
"latitude":null,
"longitude":null,
"highlight":false,
"changed":"2021-01-14T10:39:05Z",
"locationType":null,
"fileUploaded":false,
"previewImageUrl":"//www.v-office.com/dyn/image/p.m/3957684.jpg",
"contacts":[
{
"id":1422,
"type":"WEB",
"value":"http://www.location-domain.de",
"number":"http://www.location-domain.de"
}
]
},
...
],
"guides":[
{
"id":2695,
"section":"guides",
"vellcomeCategory":null,
"title":"Bedienunsanleitung Waschmaschine",
"filetype":"HTML",
"latitude":null,
"longitude":null,
"highlight":false,
"changed":"2021-03-08T14:55:29Z",
"locationType":null,
"fileUploaded":false,
"previewImageUrl":"//tim.v-office.com/dyn/image/p.m/4225544.jpg",
"contacts":[
],
"contentId":3906,
"content":""
},
{
"id":2528,
"section":"guides",
"vellcomeCategory":null,
"title":"WLAN Zugang",
"filetype":"LOC",
"latitude":null,
"longitude":null,
"highlight":false,
"changed":"2020-12-18T16:44:30Z",
"locationType":null,
"fileUploaded":false,
"contacts":[
]
}
],
"locationCategories":[
{
"id":15,
"label":"Bars & Restaurants"
},
{
"id":16,
"label":"Sehenswürdigkeiten"
},
{
"id":17,
"label":"Einkaufstipps"
}
],
"ok":true
}
Getting information on how to display a feedback-form for the customer, providing the configured labels, fields and field types. Possible Field Types:
Type | Description | Value |
---|---|---|
STARS | 5 Star Rating, (0 means “not rated”) | Int 0 - 5 |
TEXT | Free Text Input | S |
{
"bookingId":9319654
}
{
"feedbackForm":[
{
"id":603,
"name":"Sauberkeit",
"type":"STARS"
},
{
"id":604,
"name":"W-Lan Geschwindigkeit",
"type":"STARS"
},
{
"id":605,
"name":"Essen",
"type":"STARS"
},
{
"id":606,
"name":"Personal Freundlichkeit",
"type":"TEXT"
}
],
"feedbackData":[
{
"id":603,
"value":3
},
{
"id":604,
"value":2
},
{
"id":605,
"value":4
},
{
"id":606,
"value":"Super Toll"
}
],
"hasGivenFeedback":true,
"ok":true
}
Just submitting the customer feedback based on the feedback form.
Please note: for the type:"TEXT", the value may not contain characters that require 4 bytes unicode sequences (i.e. emojis). vOffice will remove any invalid characters without further notice.
{
"bookingId":9319654,
"formData":[
{
"id":603,
"name":"Sauberkeit",
"type":"STARS",
"value":3
},
{
"id":604,
"name":"W-Lan+Geschwindigkeit",
"type":"STARS",
"value":2
},
{
"id":605,
"name":"Essen",
"type":"STARS",
"value":4
},
{
"id":606,
"name":"Personal+Freundlichkeit",
"type":"TEXT",
"value":"Super+Toll"
}
]
}
{
"ok":true
}
Save the missing information about the customer, not the guest! The customer is always the one who has created the contract. In most cases the customer will also be a guest, but he has not to be a guest, e.g. someone gives a trip as a gift to a friend.
{
"customer":{
"id":6351987,
"title":"Herr",
"forename":"Christian",
"surname":"Mustermann",
"street":"Dorfstra.",
"housenumber":"15",
"city":"Hochhausen",
"postalcode":"12345",
"country":"DE",
"email":"cm@mail.com",
"mobile":"0170111222333"
},
"bookingId":9319656
}
{
"ok":true,
"customer":{
"id":6351987,
"title":"Herr",
"forename":"Christian",
"surname":"Mustermann",
"street":"Dorfstra",
"housenumber":"15",
"city":"Hochhausen",
"postalcode":"12345",
"country":"DE",
"email":"cm@mail.com",
"mobile":"0170111222333"
}
}
The gust can tell vOffice when he has arrived at the location.
{
"bookingId":9319654
}
{
"ok":true,
"arrivalStatus":"CHECKED_IN"
}
The guest can tell vOffice when he has left the location.
{
"bookingId":9319654
}
{
"ok":true,
"arrivalStatus":"CHECKED_OUT"
}
Changing the status of the given reservation. Valid status are:
{
"status":"CONFIRMED",
"bookingId":9319656
}
{
"ok":true,
"newStatus":"CONFIRMED"
}
Tell vOffice the estimated arrival time.
{
"arrivalTime":"12:00",
"bookingId":9319654,
}
{
"ok": true,
"arrivalTime": "12:00:00.000"
}
Tell vOffice the estimated departure time.
{
"departureTime":"12:00",
"bookingId":9319654
}
{
"ok":true,
"departureTime":"12:00:00.000"
}
Action name: getDocument
Retrieving given documents that are managed in vOffice. Possible documents are
Documents can only be fetched after a booking and therefore requires the booking token.
Fields in the json-encoded "data" parameter (request body):
parameter name | value | format | required |
type |
“gtc” or “privacy” | S | true |
token | booking token generated by vOffice | S | true |
{
"type":"gtc"
}
{
"ok":true,
"document":{
"subject":"AGB",
"content":"<p>HTML content...<\u002fp>"
}
}
Getting the configured Payments Methods
{
"bookingId":9319654
}
{
"BANKACCOUNT":{
"id":12344,
"type":"BANKACCOUNT",
"paymentTest":false,
"creditCardAccepted":false,
"sofortAccepted":false,
"giropayAccepted":false,
"bankaccount":{
"iban":"DE02200505501015871393",
"swift":"HASPDEHH",
"institution":"Sparkasse"
}
},
"PAYPAL":{
"id":12346,
"type":"PAYPAL",
"email":"paypal.mail@address.com",
"paymentTest":true,
"creditCardAccepted":false,
"sofortAccepted":false,
"giropayAccepted":false,
"fields":{
"cmd":"_xclick",
"business":"paypal.mail@address.com",
"item_name":"Reservierung: 00093",
"cancel_return":"payment?result=canceled",
"no_shipping":1,
"return":"payment?result=accepted",
"currency_code":"EUR",
"notify_url":"https://api2.v-office.com/api/paypalcallback?ref_id=eyJhbGciOiJIUzI1NiJ9.eyJwYXltZW50TWV0aG9kSWQiOjEyMzQ2LCJyZXNlcnZhdGlvbklkIjoyMjU1NDg2NH0.pQTooGgDRK-7Tz9pY1RJmuG2HucY8zHTxbRrmx2XUPI",
"lc":"de"
},
"url":"https://www.paypal.com/cgi-bin/webscr"
},
"STRIPE":{
"id":12345,
"type":"STRIPE",
"paymentTest":false,
"creditCardAccepted":true,
"sofortAccepted":true,
"giropayAccepted":true
},
"ok":true
}
Initialize a Stripe payment. Returned data can be used with Stripe SDK. The “id” in this request has to be the reservationId.
{
"id":22346841,
"nr":"00091",
"amount":75000,
"paymentMethodId":12345,
"rootUrl":"https://custom-guest-app.com/",
"successUrlBase":"https://custom-guest-app.com/payment-success",
"cancelUrlBase":"https://custom-guest-app.com/payment-cancelled"
}
{
"ok":true,
"sessionId":"ab_cdef_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"accountId":"acct_xxxxxxxxxxxxxxxx"
}
Submitting coupons, not vouchers. Coupons do represent a fixed amount of money (e.g. as a present) instead of vouchers that mostly represent a percentual discount for e.g. marketing purposes. Returning Coupon types are “VALUE” and “DISCOUNT”
{
"couponCode":"XXXX-XXXX-XXXX-XXXX",
"bookingId":9111522,
"amount":75000
}
{
"ok":true,
"coupon":{
"amount":10000,
"type":"VALUE"
}
}
The analytics api helps you understand your data. It provides a condensed view. Results should be cached at least 24 hours.
It uses a different API key, which can be setup in vOffice: Einstellungen->Team-Zugang->Analytics (Setup->Team-Access -> Analytics).
name | description | format | required |
---|---|---|---|
key | see above | S | true |
section | one of "BOOKINGS", 'UNITS' OR 'DAYS' | S | |
schema | if provided, result will show the schema | B | |
omitDataNode |
{ "data": { "fromdate": { "type": "DIMENSION", "datatype": "YEAR_MONTH_DAY", "label": "Von" }, "tilldate": { "type": "DIMENSION", "datatype": "YEAR_MONTH_DAY", "label": "Bis" }, "status": { "type": "DIMENSION", "datatype": "TEXT", "label": "Status" }, "booking_total": { "type": "METRIC", "datatype": "CENT", "currency": "EUR", "label": "Gesamt VK" }, .... }
name | description | format |
---|---|---|
type | either DIMENSION or METRIC | S |
datatype | one of YEAR_MONTH_DAY, TEXT, CENT, NUMBER | S |
{ "data": [ { "fromdate": "2021-01-21", "tilldate": "2021-01-24", "status": "CONFIRMED", "booking_total": 54000, "purchase_total": 26068, "days": 3, "adults": 2, "children": 0, "babys": 0, "booked": "2020-10-01", "channel": "Booking.com", "client": null, "unit": "Deich Hs. 37", "rooms": 3, "beds": 4, "margin": 8142, "sale_PET": 9000, "sale_RENT": 32100, "sale_LINEN": 3000, "sale_offer": null, "purchase_PET": 9000, "purchase_RENT": 32100, "purchase_offer": null, "sale_ownerTotal": 41100, "sale_BOOKING_FEE": 1900, "sale_FINALCLEANING": 8000, "purchase_COMMISSION": -8142, "purchase_COMM_THIRD": -6890, "purchase_ownerTotal": 41100 }, { "fromdate": "2021-03-08", "tilldate": "2021-03-10", "status": "CONFIRMED", "booking_total": 31300, "purchase_total": 19206, "days": 2, "adults": 2, "children": 0, "babys": 0, "booked": "2020-05-12", "channel": "Homepage", "client": null, "unit": "Königsstr. 04", "rooms": 3, "beds": 4, "margin": 2594, "sale_RENT": 21800, "sale_LINEN": 2000, "sale_offer": null, "purchase_RENT": 21800, "purchase_offer": null, "sale_ownerTotal": 21800, "sale_FINALCLEANING": 7500, "purchase_COMMISSION": -2594, "purchase_ownerTotal": 21800 }, ... }
name | description |
---|---|
[sale|purchase]_ownerTotal | sum of all services provides by owner |
margin | = (sale_ownerTotal-purchase_ownerTotal) + commission |
type / format | description | json data type |
---|---|---|
S | Text / String value | STRING |
D | Date as String (yyyy-MM-dd) | STRING |
DT | Date time as string (e.g. 2015-06-05T09:53:43Z) | STRING |
E164 | A phonenumber (e.g. +41446681800) | STRING |
CC | ISO 4217 currency codes like "eur" | STRING |
ML | multilanguage set, the key describes the language code (ISO 639-1) | OBJECT |
Object | Contains sub fields | OBJECT |
GeoJSON | The geometry part of the GeoJSON format (containing the point type with longitude and latitude) | OBJECT |
SET | A set of data / sub fields | OBJECT |
List | A list / array that can contain multiple entries with sub fields | ARRAY |
C | Currency value (value stating the amount cents) | NUMBER |
I | A numeric value (like INTEGER) | NUMBER |
P | Percentage value (*100, so please deduct 00 from the result, for example 3000 is 30%) | NUMBER |
B | Boolean value (true or false) | BOOL |
type | description |
---|---|
RENT |
|
FINALCLEANING |
|
LINEN |
|
HANDTOWELS |
|
PET |
|
CRIB |
|
HIGHCHAIR |
|
BABYBED |
|
TRANSFER |
e.g. Airport Transfer |
VTAX |
Visitor’s tax also known as tourist tax |
CITYTAX | Tax imposed by the city |
GAS |
|
WATER |
|
ELECTRICITY |
|
INSURANCE |
|
CANCELLATION |
cancellation fee |
COMMISSION |
own booking commission |
COMM_THIRD |
booking commission to third parties |
AGIO |
payment agio |
BOOKING_FEE |
|
DISCOUNT | should contain a negative value if discounts/offers are applied |
INTERNET | |
PARKING |
The result of searches and unit request can be projected for easier handling, performance and result size.
name | description |
---|---|
vcurrency | format as currency |
vsoption | translate an option value into the translated string |
vlang | select requested language only for a multilanguage text |
vautolang | select best available language for a multilanguage text (slower) |
code | description |
---|---|
notavailable | this unit is not available |
petsnotallowed | this unit does not allow pets |
petsOnRequest | pets are not directly allowed, but need to be requested |
maxPets | the max number of pets is exceeded |
childrennotallowed | this unit does not allow children |
maxbedsblock | not enough beds for the specified number of persons |
maxbeds | warning: you need foldable beds for the specified number of persons |
minpersons | minimum number of persons is not met |
maybeavailable | e.a. rent prices have not yet been specified by agency |
leadtimeundercut | booking restrictions require specified number of lead time |
badArrivalDay | booking restrictions do not allow this arrival day |
badDepartureDay | booking restrictions do not allow this departure day |
restPeriodArrival | booking restrictions require a rest time (free days between departure and subsequent arrival) |
restPeriodDeparture | booking restrictions require a rest time (free days between departure and subsequent arrival) |
mingap | booking restrictions require a min gap after departure if you are not booking an arrival on departure day |
minstay | minimum number of nights |
minstayfill | minimum number of nights if not filling a gap |
Coupons are pre paid, the guest can pay money for a coupon, which will then contain the credit according to the paid amount. If the coupon code is added to a payment process, the credited value will be substracted from the amount (does not go past 0) the guest would have to pay otherwise. The coupon will be gone, as soon as the credit is used up.
You can check for valid coupon codes using checkCoupon action
You can apply a coupon code by adding it to the booking request
You can submit coupons using the submitCoupon action
Vouchers are for restricted special offers, these restricted special offers may function like normal special offers, except for the application condition, since the restricted special offers require the specific voucher code to be sent in the request, otherwise they will not be applied.
The customer can add the voucher code requirement to any regular special offer and therefore turn it into a restricted one, these special offers will be returned in the regular offers list and will contain the voucherCode field, with the value being the voucher code itself.
You can check for valid voucher codes using validateVoucher action
You can apply a voucher code by adding it to the qoutePrices and booking requests
Note: Only the special offer, which will lead to the lowest price will be applied. Since these voucher restricted special offers, follow the same logic, they may not be applied if another special offer would result in a lower price.
Service costs may be calculated per person (excluding babies), if specified.
Total bed count might be divided in beds suitable for adults and beds suitable for children only.
Persons above 18.
Adults count towards the person limit and require additional beds which are suitable for adults (beds4Adults or the difference between beds and beds4kids).
Service costs may be calculated per adult, if specified.
A person may be transmitted as child, if the age is between 2 and 18.
You should always send the ages of the children, if the requested actions allow to set them, this is needed to calculate service prices, where the customer has specified children ages as one of the application conditions.
A child counts towards the person limit and does require an additional bed (every bed can be used as children bed, although beds4kids might be more suitable).
Service costs may be calculated per children, if specified.
A person may be transmitted as baby, if the age is between 0 and 2.
Babies do not count towards the person limits and do not require an additional bed.
Service costs may not be calculated per baby, even if specified.
Die Buchungsstrecke kann um eine optionale Reiserücktrittskostenversicherung erweitert werden:
Zunächst wird über einen zusätzlichen Parameter in der API Funktion quotePrices abgefragt, ob die Agentur eine Versicherungsleistung anbieten will/kann.
Ist die Unterstützung der Reiserücktrittversicherung konfiguriert, kann unmittelbar ein zweiter API Request mit der Funktion getTravelInsurancePlans abgesetzt werden. Dieser Request baut eine Verbindung von vOffice zu dem Server der Versicherung auf, um die möglichen Versicherungspläne abzufragen.
Achtung: dieser Request kann etwas dauern. Daher ist zu überlegen, ob der Request asynchron erfolgt.
Das Rückgabeergebnis von getTravelInsurancePlans enthält verschiedene Pläne (in der Regel zwei), die jeweils einen Tarifcode und weitere Angaben enthalten.
Der Gast kann nur einen Plan aus der Auswahl buchen- oder eben auch gar keinen Plan.
Wir empfehlen eine separate Box mit folgenden Optionen:
Kein Versicherungsschutz (voreingestellt)
Reiserücktrittsversicherung
Reiserücktrittsversicherung inkl. Reise-Abbruch-Versicherung
Die Angebote müssen folgende Angaben enthalten:
Wenn eine der Versicherungen ausgewählt wird, müssen vor Bestätigung der Buchung durch den Gast die rechtlich vorgegebenen Dokumente abgerufen worden sein, d.h. erst danach darf die Schaltfläche “Buchen” nutzbar sein. Dies kann beispielsweise durch das Öffnen des Dokuments in einem separaten Tab geschehen oder die Option, das Dokument herunterzuladen. Die Umsetzung sollte so erfolgen, dass die Conversion möglichst wenig beeinträchtigt wird.
Vor Anfrage der Versicherung unbedingt prüfen, ob sich die Reisesumme durch Ergänzung oder Reduktion optionaler Leistungen verändert hat, sonst kann es zu Fehlern kommen, weil der angefragte Tarif nicht mehr zur Buchungssumme passt.
Wir empfehlen, sich von vOffice ein paar aktuelle Referenz-Seiten nennen zu lassen um sich einen Eindruck von der Umsetzung machen zu können.
Um den Abschluss der eigentlichen Buchung nicht zu gefährden, wird im Anschluss an den API Aufruf book die Versicherung gebucht. Dieser Buchungsvorgang ist mehrstufig.
Im ersten Schritt wird die Buchung der Versicherung "angekündigt". Die Versicherung antwortet mit einer PolicyId und einer URL, die der Gast zum Bezahlen aufrufen muss. Bezahlt werden kann per Kreditkarte und Lastschrift. Die Versicherung wird erst gültig, wenn die Bezahlung erfolgt ist.
Nach erfolgter Buchung der Reise sollte dem Gast eine Buchungsbestätigung angezeigt werden. Darüber hinaus sollte darauf verwiesen werden, dass der Versicherungsschutz erst mit Bezahlung der Prämie gesichert ist. Hierzu wird in x Sekunden auf die Bezahlseite der URV weitergeleitet.
Sollte die Bezahlung scheitern, kann sie unter Wahrung gewisser Fristen unter demselben Link nachgeholt werden.
Die URL, die zur Bezahlseite der Versicherung führt, kann nicht in einem iframe aufgerufen werden!
Erst wenn der Gast die Versicherung bezahlt hat, ist sie gültig. Nach der Bezahlung der Versicherung erhält der Gast von der URV eine Bestätigungsmail, in der nochmal alle Details aufgeführt sind, im Anhang sind u.a. die Versicherungsbedingungen.
Es hat keinen Sinn, bei einer Anfrage oder der unverbindlichen Reservierung einer Option eine Versicherung zu buchen. Denn dann hätte der Gast schon eine Versicherung gebucht, ohne überhaupt eine Reise gebucht zu haben.
Daher sollte bei Anfragen oder Optionen keine Versicherung in der Buchungsstrecke mit angeboten werden. Die Versicherung kann immer noch im Nachgang bei fester Buchung dazugebucht werden (z.B. über die Gäste-App).
Ausnahme: Wenn für Buchungen innerhalb einer bestimmten Frist vor Anreise die Zahlung per Online-Payment vorgesehen ist, werden solche Buchungen zunächst als Belegung mit Status “Angebot” in vOffice angelegt. Erst nach Bestätigung des Zahlungseingangs durch Stripe kann der Status in “Bestätigt” gewandelt werden. (Dies kann automatisiert oder manuell erfolgen). In diesen Fällen darf eine Versicherung mit angeboten werden, da ja eine unmittelbare Buchungsabsicht besteht.
Gemäß § 2 Abs. 1 der Allgemeinen Bedingungen kann nur Versicherungsnehmer “sein, wer seinen ständigen Wohnsitz in der Bundesrepublik Deutschland hat.”
Daher darf die Versicherung nur angeboten werden, wenn in der Maske der Adressdaten des Gastes kein anderes Land als Deutschland eingetragen wurde.
this query retrieves an array of travelinsurance plans. Fire this request imediatly after the quotePrices request.
Action name: getTravelInsurancePlans
Fields in the json-encoded "data" parameter:
name | description | format | required | |
---|---|---|---|---|
target | test or production | S | ||
debug | when true, you will get additional infos | B | ||
totalBookingAmount | total amount | I | true | |
fromdate | D | true | ||
tilldate | D | true | ||
adults | I | true | ||
children | I | true | ||
babys | babies that do not require a full-sized bed | I | true |
Attention: parameter target overrides the configuration of the member.
{
"target": "test", // test or production, when emtpy, the default value for this member is used
"debug": 1,
"totalBookingAmount": 31500,
"fromdate": "2022-12-07",
"tilldate": "2022-12-21",
"adults": 2,
"children": 1,
"babys": 0,
"forceTravelInsuranceMode": "test"
}
{
"trackingId": "i-013809d7349d5c6d9|40d4afd1-a4dc-4fe9-be4e-d587889ef8d2",
"ok": true,
"errors": {},
"rq": "set debug=1",
"status": 200,
"text": null,
"xml": null,
"sent": null,
"response": null,
"plans": [
{
"planid": "RR02",
"name": "Reise-Rücktrittskosten-Versicherung ohne Selbstbehalt",
"expireDate": "2022-02-08",
"effectiveDate": "2022-02-08",
"featured": "false",
"quoteDetailUrl": "https://www.unionreiseversicherung.de/IPID/DRRV_oSB_oRAB_0218.pdf",
"bookingDetailUrl": "https://www.unionreiseversicherung.de/IPID/AVB_DTour_0218.pdf",
"planCost": {
"currencyCode": "EUR",
"amount": 2200.0
},
"termsConditionsUrl": "https://www.unionreiseversicherung.de/IPID/AVB_DTour_0218.pdf",
"commonProductInformationsUrl": "https://www.unionreiseversicherung.de/IPID/DRRV_oSB_oRAB_0218.pdf",
"logoUnderwriterUrl": "https://urvibe.it-auf-abruf.de/images/urv/URV_Logo_HKS43_100x100.png",
"features": {
"1": {
"name": "Reiserücktritt",
"id": "1"
},
"4": {
"name": "Rückreisekostenschutz",
"id": "4"
},
"110": {
"name": "Versicherung ohne Selbstbehalt",
"id": "110"
}
}
},
{
"planid": "RR19",
"name": "Reise-Rücktrittskosten-Versicherung ohne Selbstbehalt inkl. Reise-Abbruch",
"expireDate": "2022-02-08",
"effectiveDate": "2022-02-08",
"featured": "false",
"quoteDetailUrl": "https://www.unionreiseversicherung.de/IPID/DRRV_oSB_mRAB_0218.pdf",
"bookingDetailUrl": "https://www.unionreiseversicherung.de/IPID/AVB_DTour_0218.pdf",
"planCost": {
"currencyCode": "EUR",
"amount": 2600.0
},
"termsConditionsUrl": "https://www.unionreiseversicherung.de/IPID/AVB_DTour_0218.pdf",
"commonProductInformationsUrl": "https://www.unionreiseversicherung.de/IPID/DRRV_oSB_mRAB_0218.pdf",
"logoUnderwriterUrl": "https://urvibe.it-auf-abruf.de/images/urv/URV_Logo_HKS43_100x100.png",
"features": {
"1": {
"name": "Reiserücktritt",
"id": "1"
},
"4": {
"name": "Rückreisekostenschutz",
"id": "4"
},
"10": {
"name": "Reiseabbruchversicherung",
"id": "10"
},
"110": {
"name": "Versicherung ohne Selbstbehalt",
"id": "110"
}
}
}
]
}
name | description | usage |
---|---|---|
trackingId | internal id | for debugging |
target | test or production | just for information |
ok | true if succeeded | |
errors | contains information about errors occured | |
status | HTTP status code | for debugging |
rq | XML Request, only set, wenn parameter debug is true | for debugging |
response | XML Response, only set, wenn parameter debug is true | for debugging |
plans | Array | |
plans.planid | tariff code | display: optional |
plans.name | name of the tariff | display: yes |
plans.quoteDetailUrl | URL, display as link | display: optional |
plans.bookingDetailUrl | URL: display as link | display: optional |
plans.termsConditionsUrl | URL: terms of condition display as link | display: yes |
plans.planCost | amount and currency | display: yes |
plans.features | array: details of covered options | display: optional |
Normally there a two plans, identified by the planid
Only one plan can by booked, so you have to display the plans as a choice.
Die Reiserücktritts-Versicherung kann auch im Anschluss an die eigentliche Buchung oder später gebucht werden, z.B. im Rahmen einer Gästeapp.
Die Versicherung kann bis 30 Tage vor Anreise gebucht werden, oder wenn die Reise weniger als 30 Tage vor der Anreise gebucht wird, innerhalb von zwei Werktagen nach Buchung der Reise. Diese Bedingungen werden von der Versicherungsagentur (URV) vorgegeben.
Die Buchung der Versicherung wird erst mit der Bezahlung der Versicherung gültig. Bezahlt werden kann die Versicherung über den Link, der in paymentUrl zurückgegeben wird, oder über die vOffice Gästeapp.
Action name: bookTravelInsurancePlan
name | description | format | required |
---|---|---|---|
debug | request for debuging informations | B | no |
bookingId | 1234567 | I | yes |
plan | Contain planid and amount | Object | yes |
plan.planid | URV Plan Id like 'RR03' | S | yes |
plan.amount | Amount of plan in cents | I | yes |
forceTravelInsuranceTarget |
test or production | S | no |
forceTravelInsuranceBookingMode |
test or production | S | no |
Das Feld forceTravelInsuranceTarget kann auf 'test' gesetzt werden, auch wenn die Agentur schon im Live Betrieb ist. In diesem Falle wird gegen das Testsystem der URV gebucht.
Das Feld forceTravelInsuranceBookingMode kann auf 'test' gesetzt werden, auch wenn die Agentur schon im Live Betrieb ist. In diesem Falle wird gegen das Produktiv System der URV gebucht, die Buchung aber als Textbuchung markiert.
{
"debug": 1,
"bookingId": {{bookingId}},
"plan": {
"planid": "{{planId}}", // muss zum Reisepreis passen
"amount": {{planAmount}}
},
"forceTravelInsuranceTarget": "{{forceTravelInsuranceTarget}}", // force test or production
"forceTravelInsuranceBookingMode": "{{forceTravelInsuranceBookingMode}}"
}
name | description | format |
---|---|---|
trackingId | S | |
ok | 'true' or 'false' | B |
travelInsurance | Object | |
travelInsurance.id | numeric id | I |
travelInsurance.policyid | S | |
travelInsurance.planid | tarifcode like 'RR03' | S |
travelInsurance.amount | amount of insurance in cents | I |
travelInsurance.booked | timestamp of booking | D |
travelInsurance.changed | timestamp of last changed | D |
travelInsurance.target | 'test' or 'production' | S |
travelInsurance.mode | 'test' or 'production' | S |
travelInsurance.paymentUrl | Link for payment, does not work in iframe | S |
travelInsurance.tarifLimit | versicherter Reisepreis | I |
travelInsurance.status | BOOKED if OK | S |
travelInsurance.status_payment | BOOKED if paid | S |
travelInsurance.errortext | result text form URV in case of error | S |
text | result xml form URV in case of error | S |
reasonText | Fehlerbeschreibung | S |
{
"trackingId": "i-0703ff64e73c6165a|3adab145-db39-437f-9cf9-fc0d5aab18ca",
"ok": true,
"travelInsurance": {
"id": 299,
"policyid": "109003990",
"target": "test",
"mode": "test",
"paymentUrl": "https://urvibetest.it-auf-abruf.de/public/paymentLink.do?token=pPudIDsHLx5iTkEBHOt3p8oDzMWk2kDXenLu62b0fxorIa6ElKQmKjKOURLHQrlp",
"planid": "RR03",
"amount": 2700,
"booked": "2022-08-27T15:07:13Z",
"changed": "2022-08-27T15:07:14Z",
"status": "BOOKED",
"status_payment": "UNKNOWN",
"errortext": "OK",
"bookingTotal": 49400,
"tarifLimit": 50000
},
"status": 200,
"transactionIdentifier": "voffice-2515-11024329-2022-08-27 15:07:13.818"
}
{
"trackingId": "i-0703ff64e73c6165a|13f8c6d3-6b66-4a58-970e-65f932c91702",
"ok": false,
"travelInsurance": {
"id": 291,
"target": "test",
"mode": "test",
"planid": "RR03",
"amount": 2700,
"booked": "2022-08-27T11:52:25Z",
"status": "BOOKEDERROR",
"status_payment": "UNKNOWN",
"errortext": "[0:[code:1, type:1, text:Das gewählte Produkt passt nicht zu den von Ihnen angegebenen Reiseinformationen!]]"
},
"status": 200,
"text": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<OTA_InsuranceBookRS Version=\"1.0\" TransactionIdentifier=\"voffice-2515-9470258-2022-08-27 11:52:25.019\" TimeStamp=\"2022-08-27T13:52:25.287+02:00\" Target=\"Test\">\n <Warnings>\n <Warning Type=\"1\" ShortText=\"Das gewählte Produkt passt nicht zu den von Ihnen angegebenen Reiseinformationen!\" Code=\"1\"/>\n </Warnings>\n</OTA_InsuranceBookRS>\n<!-- 200 [0:[code:1, type:1, text:Das gewählte Produkt passt nicht zu den von Ihnen angegebenen Reiseinformationen!]] -->",
"rq": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<OTA_InsuranceBookRQ PrimaryLangID=\"de\" Target=\"Test\" TimeStamp=\"2022-08-27T11:52:25\" TransactionIdentifier=\"voffice-2515-9470258-2022-08-27 11:52:25.019\" Version=\"1.0\">\n <POS>\n <Source AgentDutyCode=\"464\" ISOCountry=\"DE\" ISOCurrency=\"EUR\">\n <RequestorID ID=\"50000082\" ID_Context=\"KID\" MessagePassword=\"2-gh5jHABSpf\" Type=\"13\" URL=\"\">\n <CompanyName CompanyShortName=\"vOffice\" TravelSector=\"6\">vOffice GmbH</CompanyName>\n </RequestorID>\n </Source>\n </POS>\n <PlanForBookRQ Name=\"\" PlanID=\"RR03\">\n <CoveredTravelers>\n <CoveredTraveler>\n <CoveredPerson Age=\"42\" BirthDate=\"1900-01-01\">\n <NamePrefix>Herr</NamePrefix>\n <GivenName>Test</GivenName>\n <Surname>vOffice</Surname>\n </CoveredPerson>\n <IndCoverageReqs>\n <IndTripCost Amount=\"0\" CurrencyCode=\"EUR\" />\n </IndCoverageReqs>\n </CoveredTraveler>\n <CoveredTraveler>\n <CoveredPerson Age=\"42\" BirthDate=\"1900-01-01\">\n <NamePrefix>Familie</NamePrefix>\n <GivenName>2.</GivenName>\n <Surname>Reiseteilnehmer</Surname>\n </CoveredPerson>\n <IndCoverageReqs>\n <IndTripCost Amount=\"0\" CurrencyCode=\"EUR\" />\n </IndCoverageReqs>\n </CoveredTraveler>\n <CoveredTraveler>\n <CoveredPerson Age=\"12\" BirthDate=\"1900-01-01\">\n <NamePrefix>Familie</NamePrefix>\n <GivenName>3.</GivenName>\n <Surname>Reiseteilnehmer</Surname>\n </CoveredPerson>\n <IndCoverageReqs>\n <IndTripCost Amount=\"0\" CurrencyCode=\"EUR\" />\n </IndCoverageReqs>\n </CoveredTraveler>\n </CoveredTravelers>\n <InsCoverageDetail EffectiveDate=\"2023-01-30\" ExpireDate=\"2023-02-04\">\n <CoverageRequirements>\n <CoverageRequirement CoverageType=\"4\" EffectiveDate=\"2023-01-30\" ExpireDate=\"2023-02-04\" />\n </CoverageRequirements>\n <TotalTripQuantity Quantity=\"1\" />\n <TotalTripCost Amount=\"0\" CurrencyCode=\"EUR\" />\n <CoveredTrips>\n <CoveredTrip End=\"2023-02-04\" Start=\"2023-01-30\">\n <Destinations>\n <Destination ArrivalDate=\"2023-01-30\" DepartureDate=\"2023-02-04\" Type=\"4\">\n <CountryName Code=\"DE\">Germany</CountryName>\n </Destination>\n </Destinations>\n <Operators>\n <Operator CompanyShortName=\"ABC\" TravelSector=\"6\">ABC GmbH</Operator>\n </Operators>\n </CoveredTrip>\n </CoveredTrips>\n </InsCoverageDetail>\n <InsuranceCustomer Gender=\"\" ID=\"5259900\">\n <PersonName>\n <NamePrefix>Herr</NamePrefix>\n <GivenName>Test</GivenName>\n <Surname>vOffice</Surname>\n </PersonName>\n <Telephone CountryAccessCode=\"49\" PhoneLocationType=\"6\" PhoneNumber=\"+49192277363535356\" />\n <Email>info@v-office.com</Email>\n <Address>\n <StreetNmbr PO_Box=\"\">Am Holm 25</StreetNmbr>\n <BldgRoom />\n <CityName>Neustadt in Holstein</CityName>\n <PostalCode>23730</PostalCode>\n <CountryName Code=\"DE\">DE</CountryName>\n </Address>\n <PaymentForm>\n <PaymentLink>\n <NotifyUrl>https://juergen.v-office.com/if/travelInsurancePaymentCallback?id=291&bid=9470258</NotifyUrl>\n </PaymentLink>\n </PaymentForm>\n </InsuranceCustomer>\n <PlanCost Amount=\"32\" CurrencyCode=\"\" />\n </PlanForBookRQ>\n</OTA_InsuranceBookRQ>",
"rs": {},
"transactionIdentifier": "voffice-2515-9470258-2022-08-27 11:52:25.019"
}
Datenstruktur travelInsurance
name | description | format | example |
possible values
|
---|---|---|---|---|
id | internal vOffice id | I | 283 | |
policyid | URV policyid | S | 109003989 | |
target | booked on URV platform: test or production | S | test | test, production |
mode | test or production | S | test | test, production |
paymentUrl | link for URV payment platform | S | ||
planid | URV tarifcode | S | RR03 | |
amount | URV tarif amount in cents | C | 2700 | |
booked | insurance booked timestamp | D | 2022-08-27T10:46:44Z | |
changed | last changed | D | 2022-08-27T10:46:44Z | |
status | status of insurance | S | BOOKED | REQUEST', BOOKED, BOOKEDERROR, CANCELREQUEST, CANCELED, CANCELEDERROR |
status_payment | status if payment | S | UNKNOWN | UNKNOWN, BOOKED, ERROR, ABORTED, PAYMENT_DEADLINE_EXPIRED |
errortext | S | success | ||
bookingTotal | current amount of booking in cents | C | 49400 | |
tarifLimit |
insured travel price in cents |
C | 50000 | |
fromdate | arrival
at the time of booking |
D | 2022-11-01 | |
tilldate | departure
at the time of booking |
D | 2022-11-07 | |
cancellable | S | true, false onrequest | ||
tarifLimitExceeded | true if current bookingTotal is greater than tarifLimit | B | true, false |
Eine Versicherung kann im Rahmen des 14 tägigen Widerrufsrechtes storniert werden, wenn die Buchung der Versicherung nicht länger als 14 Tage zurückliegt.
Action name: cancelTravelInsurance
name | description | format | example | required |
---|---|---|---|---|
debug | optional for debuuging information | B | 0 | no |
bookingId | vOffice bookingId | I | 1234567 |
yes
|
cancelReasonId | I | 5 | yes | |
forceTravelInsuranceTarget | overides settings | S | test | no |
1 - Reise vom Veranstalter abgesagt
2 - Reiseumbuchung - deshalb neuer Vertrag bei URV
3 - Reise bereits vorher anderweitig versichert
4 - Storno Reiserücktritt wg. Umwandlung in Paket inkl. Reiserücktritt (neuer Vertrag)
5 - Kunde widerruft innerhalb Frist von 14 Tagen
{
"debug": 0,
"bookingId": 12456789,
"cancelReasonId": 5, // 5: cancellation within 14 days after booking
"forceTravelInsuranceTarget": "test"
}