Inline Booking Notification Webhook (article)

Susana Moleón Moya
Susana Moleón Moya
  • Updated

Notes

TourCMS Inline booking notification webhooks are a variant on our standard booking notification webhook with the following distinctions:

  • Allow you to provide TourCMS with extra information related to a booking
    Your response to the inline webhooks can return subsystem booking references/tickets information for use on vouchers, and also in some cases indicate how long you will hold seats/availability on a booking.
     
  • Run "inline" during TourCMS standard process, rather than being sent after the fact
    This allows TourCMS to collect the extra information, however, it also causes additional traffic and requires faster response times from your subsystem. If your subsystem is unavailable or throws an error booking will fail, causing a poor user experience.
     
    TourCMS standard webhooks can wait for longer, retry in case of error, and shield your subsystem from traffic load.
     
  • Supports bookings made via API and TourCMS booking engine
    The inline webhooks can be used for bookings made through the standard hosted TourCMS booking engine or the API and are not supported for back office bookings.

Flow

TourCMS API features a two-step booking process.

  1. Start New Booking - Creates the booking details in TourCMS, as a temporary booking, holding stock. A temporary booking is expected to always commit (see next step) but can just as easily be deleted by the implementer. During this step TourCMS will send you a "new_temporary_web" or "new_temporary_staff" webhook, you can then hold the stock in your subsystem and return any important references and if you have a limited hold period, the number of seconds you will hold for.
  2. Commit Booking - Turns the temporary booking created in the previous step into a fully committed booking, this step is not expected to fail. Once a booking is committed any confirmation emails are sent, vouchers can be viewed/printed etc. A committed booking can no longer be deleted, it can only be cancelled. During this step, if the booking is confirmed (i.e. made by a Trusted Travel Agent / OTA) TourCMS will send you a "new_confirmed_web" or "new_confirmed_staff" webhook, you can also return any important references and ticket ids for display on vouchers.

If a temporary booking is deleted prior to the expiration of the hold time, TourCMS will send you a "temporary_booking_deleted" webhook.

Triggers

One of the following events:

  • new_temporary_staff - A new "Temporary/Hold" booking, made by staff
  • new_temporary_web - A new "Temporary/Hold" booking created via API
  • new_confirmed_staff - A new "Confirmed" status booking, made by staff
  • new_confirmed_web - A new "Confirmed" status booking, made via the booking engine / API
  • deleted_temporary_booking - An API implementer deleted a booking prior to the hold time rather than committing it

Request

TourCMS appends the same query string parameters as the standard booking notification webhooks, however as the request is happening inline it will also post the XML output equivalent as if you had called our Show Booking API endpoint.

The XML is signed allowing you to verify that it is sent by TourCMS, see the Verifying the signature section below.

Response

Success/Failure

TourCMS looks for a 200 status code response to indicate a booking success, any other response will be taken as a booking failure.

While your endpoint may return a blank page, if any content is returned by your page it must be valid JSON. Additionally, it should be returned with an HTTP Content-type header of application/JSON.

Booking already committed? Booking already deleted?
These are both endpoints that can be retried in case of failure or indeterminate outcome. Please treat this as a success and return a 200 status, if you are returning a JSON response, consider including a "text" property with text to that effect. We may provide a more structured response for this in future.

Your references/ticket IDs

For each component* on a booking, you may return an array of tickets, these can be your own IDs or IDs from your supplier that you would like to be displayed on standard TourCMS vouchers or vouchers built by OTAs that support them.

You can also return a per-component operator_reference if you have one, for example, this could be the booking reference in your system (if this is different from the value returned in the array tickets). The reference does not need to be unique to a given component, for example, if you have booked all components on a TourCMS booking as a single booking in your system, all operator_reference would be identical.

You can return a barcode_symbology, by default if you omit this TourCMS will assume "QR_CODE" and while we strongly suggest the use of "QR_CODE" you can alternatively pass "CODE_128".

* Components in TourCMS are individual line items on a booking, for example, a booking for 2 Adults, 1 Child on Tour A would give 2 component in TourCMS: one for 2 Adults on Tour A, a second for 1 Child on Tour A. Bookings in TourCMS can contain multiple components from multiple different tours, however generally distributed (OTA) bookings are made for a single tour

Tickets and Operator references beginning with TOURCMS| are not allowed as they are reserved values in TourCMS.

Learn more about vouchers & barcodes in TourCMS

Booking hold time

TourCMS standard booking hold time is 45 minutes, this means that an API consumer making a successful call to the first step of our two-step booking process would expect that booking to be held for 45 minutes, and for a subsequent "Commit" call to be successful within that time.

TourCMS will send you the expected hold time in seconds as hold_time_seconds node during the first inline webhook, we would strongly recommend you match the requested hold time where possible as not doing so may limit which OTAs you can sell tours via. If you omit to return a hold_time_seconds TourCMS will assume the requested hold time. A hold_time_seconds less than 900 (15 minutes) will be ignored. A hold_time_seconds returned during step two ("Commit") will have no effect.

If your subsystem does not support temporary bookings, then please contact us by writing an email to support@palisis.com and we will activate a feature in TourCMS in order to send an instruction to the subsystem after the expiration time for the deletion of the booking.

† There are some variances, for example, Get Your Guide mandate a 1 hour hold time (3600 seconds).

Explanation text

If you provide a text property with your response TourCMS will return this alongside any error message, for example, if there is a problem creating a temporary booking you should output the reason why as a "text". Use of this field is strongly recommended.

Example response
{
"hold_time_seconds":2700,
"text":"",
"components":[{
"component_id":"1234",
"barcode_symbology":"QR_CODE",
"operator_reference":"1234567",
"tickets":[{
"label":"Adult entry",
"value":"1234568"
},
{
"label":"Adult entry",
"value":"1234569"
}
]
},
{
"component_id":"1234",
"barcode_symbology":"QR_CODE",
"operator_reference":"1234567",
"tickets":[{
"label":"Child entry",
"value":"1234570"
},
{
"label":"Child entry",
"value":"1234571"
}
]
}
]
}

Returning your own voucher links

{
	"hold_time_seconds": 2700,
	"text": "",
	"components": [{
			"component_id": "1234",
			"urls": [{
					"link": "http://www.example.com/1234568",
					"type": "voucher",
					"label": "Adult entry",
					"mime_type": "text/html",
				},
				{
					"link": "http://www.example.com/1234569",
					"type": "voucher",
					"label": "Adult entry",
					"mime_type": "text/html",
				}
			]
		},
		{
			"component_id": "1235",
			"urls": [{
					"link": "http://www.example.com/1234570",
					"type": "voucher",
					"label": "Child entry",
					"mime_type": "text/html",
				},
				{
					"link": "http://www.example.com/1234571",
					"type": "voucher",
					"label": "Child entry",
					"mime_type": "text/html",
				}
			]
		}
	]
}

Configuration

Enabling inline booking notification webhooks

Inline booking notifications are not provided as standard functionality in TourCMS, please contact us to discuss enabling the feature on your account. Once access has been enabled you can switch the webhooks on/off via the standard configuration page in Configuration & Setup > Webhooks.

URL

TourCMS will post to the same URL as configured for the standard booking notification webhooks in Configuration & Setup > Webhooks.

Filtering by channel/tour

The inline webhooks respect the same channel restrictions as the standard webhooks, configured via Configuration & Setup > Webhooks, additionally exclusive to the inline webhooks it is possible to whitelist/blacklist individual tours.

Skipping inline webhooks on a per booking basis

If you are placing a booking in your own TourCMS account for testing purposes, or to price up only you can skip the temporary inline booking webhook bypassing <skip_inline_webhook>1</skip_inline_webhook> in your call to "Start new booking".

Verifying the signature

TourCMS adds a signed hash the booking XML prior to posting it, you can verify the hash by concatenating the XML node values specified in the hash_fields with a pipe character in between each value, then hashing using the algorithm specified in the algorithm node using your TourCMS API key.

The following is an example of the signed XML node:

<response>
...
<booking>
...
</booking>
<signed>
<hash_fields>/response/booking/booking_id /response/booking/channel_id /response/booking/made_date_time /response/booking/components/component/component_id /response/booking/components/component/sale_quantity</hash_fields>
<algorithm>sha256</algorithm>
<hash>9a08bc4be09b94a66879820d51dd044d21c148cd45acace77ce6e47188d131da</hash>
</signed>

The following is a reference implementation in PHP, adapted from our PHP library:

functionvalidate_xml_hash($xml,$private_key){

// Get an array of XPath queries

$fields=explode(" ",$xml->signed->hash_fields);

// Loop through each query
foreach($fieldsas$field){

// Run the XPath query
$xpath_result=$xml->xpath($field);

// Loop through each result and build an array of node values
foreach($xpath_resultas$result){
$values[]=(string)$result[0];
}
}

// Generate the string to sign by concatenating the values with a pipe
$string_to_hash=implode("|",$values);

// Get the algorithm to use from the XML $algorithm=$xml->signed->algorithm;

// Generate the hash $hash=hash_hmac($algorithm,$string_to_hash,$private_key,FALSE);

// Compare the hash with the one provided in the XML return$hash==$xml->signed->hash;

}

Testing

If the functionality has been enabled for your account by Palisis staff you can test your integration without enabling the webhooks by passing <force_inline_webhook>1</force_inline_webhook> to Start new booking, Commit booking or Delete booking. This flag tells TourCMS to send the webhook regardless of whether you have turned inline webhooks on, regardless of whether the booking matches the whitelist/blacklist of tours and in the case of Commit booking regardless of whether the booking is about to go confirmed.

In addition to skipping the above checks, passing this parameter returns additional information regarding the response of your webhook endpoint which can help with debugging:

<webhook>
<webhook response>Any content received from your webhook endpoint</webhook_response>
<webhook_roundtrip>0.011</webhook_roundtrip>
<webhook_http_status>200</webhook_http_status>
<webhook_url>The URL TourCMS called</webhook_url>
<webhook_payload>The XML payload TourCMS sent</webhook_payload>
</webhook>

This extra information can also be returned without forcing the webhook by passing <webhook_info>1</webhook_info>.

 

More information