TourCMS, a leading online booking and channel management solution is operated by Palisis.

Contact Info

Palisis AG
Florastrasse 18A
8610 Uster
support@palisis.com
+41 44 533 40 40

Follow Us

home > support > API > webhooks > Inline Booking Notification

Inline Booking Notification Webhook


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 booking for.
     
  • 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 to and requires faster response times from your subsystem. If your subsystem is unavailable or throws an error bookings will fail, causing a poor user experience.
     
    TourCMS standard webhooks can wait for longer, retry in case of error, and shield your subsystem from load
     
  • Only support bookings made via the API
    The inline webhooks are not sent for bookings made by the standard hosted TourCMS booking engine or back office, only bookings made via API (Palisis website, OTA bookings, ) are supported.

Flow

TourCMS API features a two step booking process.

  1. Start New Booking - Creates the booking details in TourCMS, as a tempoary 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

Please note any events not listed here such as cancellations, redemptions, payments etc do not send as inline synchronous (POST) webhooks and will instead be sent via TourCMS standard asynchronous (GET) webhook.


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.

Request Id

TourCMS will include an X-Request-Id header in the request when sending you the webhook. The value of this header will be a random semi-unique value (currently a UUID4). If you are able to log this header it may help debugging or tracing specific requests.


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 to 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

Your voucher links

Generally we would strongly recommend that rather than returning your own voucher links that where possible you would return your desired barcode contents (i.e. ticket or booking references mentined above) and allw TourCMS or the OTAs and other API API consumers to generate their own voucher.

However, where that is not possible and where there are particular vouchers that customers must receive you may return an array of urls, either one per component or one per sale_quantity (i.e. per person). If the same URL applies to multiple components (i.e. if a booking for multiple rate types or multiple tours only has a single URL) just return that same URL against each component it relates to, the OTA / API consumer can de-dupe and display as they wish.

Each url must be of type "voucher", have a valid link and mime_type (currently only you may return an array of text/html and application/pdf are supported).

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 300 (5 minutes) will be ignored. A hold_time_seconds returned during step two ("Commit") will have no effect.

† 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 responses

A simple accept

Remember, to merely accept the inline webhook you may return a simple empty 200 HTTP response. However a JSON response showing the status can be useful for logging purposes:


{
	"hold_time_seconds": 2700,
	"text": "Booking accepted"
}

Returning your own subsystem refrences / tickets


{
	"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": "1235",
			"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.

Webhook 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 by passing <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 inbetween 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>
  ...
</response>


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

function validate_xml_hash($xml, $private_key) {

  // Get an array of XPath queries
  $fields = explode(" ", $xml->signed->hash_fields);

  // Loop through each query
  foreach($fields as $field) {

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

    // Loop through each result and build an array of node values
    foreach($xpath_result as $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>.


 
Changelog

This page details a work in progress specification, the following changes have been made:

  • 06 April 2022
    • Change min hold time for temporary bookings to 5 minutes.
  • 22 October 2019
    • Testing (force_inline_webhook)
  • 15 October 2019
    • Added this changelog
    • Document signed hash verification
    • Document "text" response property
    • Elaborated on "hold_time_seconds"
  • 02 October 2019
    • First version

More information