23. Purchase redirection changes

This document is intended for developers who have performed a complete XML core integration with the Ingresso TicketSwitch system, including the collection and passing of payment card details It describes the modifications necessary to move from the current implementation to one capable of supporting the redirection necessary for 3D secure and payment page handling.

23.1. The requirement for redirects

When the XML core was originally designed the debiting of a credit card was a relatively straightforward process. The card details were collected, along with the billing address, and these were passed through to an acquirer who responded with a success or a failure. No further interaction was required with the customer after the original data collection.

Since then, however, there have been two changes in the way cards are handled on the internet which means that this approach is no longer adequate. The first of these has been the introduction of 3D secure technology. This is known by a variety of names, such as “Verified By Visa” or “MasterCard SecureCode” to name the biggest two, but in essence the technology is the same for all implementations. 3D secure requires that a customer using a credit card online be redirected to a website owned by the card issuer, where they enter a password to verify that it is them using the card, the customer is then passed back to the original site to complete the purchase. This is starting to be mandated by certain card issuers for the taking of cards on the internet, and this is only set to become more prevalent.

The second change which has come across the industry is the rise of 3rd-party “pay pages”. This covers all kinds of services, such as Paypal and Worldpay, but what they all have in common is that the card details are no longer collected on the original website, but instead a separate site is used to handle the payment in its entirety. This removes the need for the ticketing system to handle any payment card data which is very attractive to a number of sites. It has hence lead to a number of ticketing systems who’s API’s no longer handle credit cards at all, in the expectation that any integration will use the pay page to take payment.

Because of both of the above factors, the current method of debiting cards through the XML core is no longer sufficient. To support both 3D secure and pay pages the XML core has been extended to provide a new purchase process that allows for redirection during the transaction. To ease the transition for existing customers this has been done in such a way as to preserve almost all of the current input and output data structures, in the hope that code can be re-used when migrating to the new process. This document gives the information necessary to perform the migration for people who already have a working integration.

23.2. Description of the new process

The new purchase scheme needs to allow for a space when a redirect can be returned to the client for them to pass the customer away to a 3D secure website or a payment page. Thus the original single purchase call has been split into two parts. The first part takes all the parameters necessary to make the purchase, but instead of completing will always return a redirect to the client. It is effectively a “start purchase process” call. The second call is used to handle the return from a redirect. It is called when a redirect returns to the client site and either completes the purchase, returning the end result, or passes back another redirect. There may be multiple redirects within a single purchase, and thus the part two call may be called multiple times.

One of the differences between the old purchase process and the new process is that under the old API, making a repeat of a call would result in an error being returned such as “already purchased”, whereas with the new process this is not true, as when redirects are being used there is a good chance that a URL may be refreshed, or double clicked, resulting in a repeated call. The new API is constructed such that such repeated requests are redirected off to the correct place under (almost) all circumstances. Hence the client does not need to worry about such things when coding. One caveat to that is, however, that the final results page may be produced multiple times if the customer refreshes the final redirect. If there is additional work which is done on completion of the purchase, then the client will need to track this using the transaction ID to make sure that they only perform the operation once. Sending a confirmation email is the kind of thing that would fall into this category, as would recording the transaction in a local database. Generating the final confirmation page, however, can simply be done from the returned data, as this will be reproduced exactly if the purchase is called multiple times.

24. Format of return URL

As part of the redirect process, the client is required to provide a return URL on their website, to which the customer will be sent when the redirect has completed its interaction. This URL then calls the part two purchase method, supplying any CGI variables given to it as either POST or GET, in order to transfer the result of the redirect through to the original system. To keep track of which return URL belongs to which redirect, the client must also generate a unique token when it supplies the return URL to the original request, and when the URL is called by the returning customer then this token needs to be passed back into the part two purchase method to identify which redirect the data is the return from.

The format of the token is entirely up to the client implementation, and should be whatever is easiest for them to use or generate. As an example the Apache UNIQUE_ID string makes a very good token as it is generated for every request, and is guaranteed unique. This is what is used internally by our own websites. The slight difficulty comes in the fact that the token needs to be encoded into the return URL, and cannot be passed as a CGI variable or held in a cookie. A CGI variable cannot be used as all of the CGI inputs are required by the return from the 3D secure process, and may be checksummed, which rules out any extras being supplied. It is also not necessarily the case that it will be the customers browser making the callback request, which is why the token cannot be held in a cookie.

The only reasonable way to pass the token around is as a component of the path used as the return URL. If CGI scripts are being used then they tend to ignore any path components after the script, and there are a number of ways of accessing the path from within the script. For the unique ID “T1n7SQpAMgYAAAio978AAAAD” you could supply a return path of http://my.site.com/cgi-bin/return.exe/T1n7SQpAMgYAAAio978AAAAD for example. The exact implementation is, obviously, up to the client however.

25. Abandoned redirect handling

With the old monolithic purchase process there was no way that a purchase could be abandoned part way through. Once the call was made a success or failure message was guaranteed to be returned. With a redirecting buy process, however, it is perfectly possible that a customer may be redirected away and never return. If the 3D secure page is not filled in, or if a customer simply gets bored with redirecting in the situation that several redirects are necessary, then they may close their browser or navigate to another site. Under some circumstances this may leave a purchase in a state where some of the tickets have been purchased and some are left on reserve.

Rather than placing the onus for the detecting of abandoned attempts and the consequent tidy-up onto the client, we handle all of this internally. A redirect which has not returned to us after a significant time will be deemed to have timeout out, and our system will fake a returning customer by calling the return URL ourselves. This is one of the situations where the return URL will not be called by a customer (or even a web browser) and is part of the reason why cookies may not be used to hold the token. From the client’s point of view, nothing special should be done to handle timeouts. A confirmation email should be sent if necessary and a confirmation page generated. Thus from an implementation point of view, you can assume that a client will always return.

26. The redirect response from the core

All redirects for 3D secure, and most redirects for pay pages, need to be submitted as POST requests, and thus cannot be output using the HTTP “Location” header. Instead a page of HTML is produced by the system that contains a form and some javascript to immediately submit it on page load. For simplicity of client handling, those situations where a GET redirect is required are also handled using an HTML page and javascript, so that all the client has to do is to output the page verbatim.

When a request is made to either part one or part two purchase which results in a redirect being needed, the resulting XML will contain a single element called “redirect_html_page_data”. This contains the HTML page in its entirety as a single string, which can be output directly. As an example, the following XML contains a redirect to Google handled using a GET.

<purchase_reservation_part_one_result>
<redirect_html_page_data>&lt;html&gt;&lt;head&gt;
&lt;script type="text/javascript"&gt;
window.location="http:\/\/google.co.uk\/";
&lt;/script&gt;&lt;/head&gt;
&lt;body&gt;&lt;/body&gt;&lt;/html&gt;</redirect_html_page_data>
</purchase_reservation_part_one_result>

The HTML page which is contained in this response is this:

<html><head>
<script type="text/javascript">
window.location="http:\/\/google.co.uk\/";
</script></head>
<body></body></html>

27. Encryption of card data

As the card data may be passed to us in the initial request, we need to store it during any redirections that may occur. It is not acceptable for the card data to be stored in our database in plain text for reasons of PCI compliance and also common sense! The card data can be encrypted, but if the encryption key is also stored in the database then this is also insecure. For this reason we require that the client pass in a key to be used for encrypting the card data on each purchase request. This key must, obviously, remain constant through the entire process, but the client is free to use whatever they wish, as long as it is at least 20 characters long and is not whitespace.

A simple implementation would be for the key to be a constant known only to the client application, and thus be used for all transactions. The key is never stored at our end, and is only used within a request to decrypt the data. It is only required for the actual purchasing part of the process, however, and is not needed for timeout processing. Thus if a client wants a more sophisticated scheme of key generation and handling, they may store it in a cookie in the customers browser. If this approach is taken, however, the lack of the key in the cookie should not cause the return URL to fail - it should always make the part two purchase call, passing in the cookie if present.

27.1. The new purchase_reservation_part_one method

The part one method starts the multi-part purchase process as described in the previous section. It takes all of the same inputs that were required by the original “purchase_reservation” method, and thus existing code can be re-used to create this call. To support redirection, however, additional elements are required. The encryption key should be provided in an element named “encryption_key”, and the unique token to be used for a redirect return should be provided in “return_token”. Note that the token should be re-generated every time this call is made, so that even for repeated calls on the same transaction a new token should be generated each time.

A described earlier, it is necessary to provide a return URL to the system which encapsulates the return token in the path somehow. Rather than giving a single string, the return URL is provided as two parts, plus a flag. These parts are the domain to be returned to in “return_domain”, the path to be used in “return_path” and whether or not the return should use https as a flag “return_with_https”.

Part one purchase will always return a redirect, either to an external debitor, or directly to the return URL. If your implementation is designed to work on credit, never needing a redirect, and cannot redirect the customers browser as a result, then please contact us directly.

Include an empty “send_confirmation_email” element when calling “purchase_reservation_part_two” to request a confirmation email to be sent to the customer.

27.1.1. Example input

<purchase_reservation_part_one>
<user_id>demo</user_id>
<crypto_block>s2--AgBUIdqCoM8BTmPgRUz8Zep1a9SB4hvttQdoT5qxan96T
ogehZ-l_SI4rqn2uJJQHH-tH-v20N4yZEA3jWCBzK-3dqQsjfa_MYufnw-bCaZT
b-NaqraAOBBwCymw2pojKN-8BRagvzW_cf3Gd9s-XiCz8I74B6A1XSMNmkqN6Ml
CgAZFw8JHYra2Qp9PXw0h95Y__8_pPVRsJTNLlv4HoBcj-sf4d7C1A-7auwfB52
gC9jfi16cXSkDhfI5dgZmRHVs6H8Y95N9QQYuXfXuD9eDsEqEqZKNBn5-RTfwfu
yzWQGOPfI1xjsXhEaRejKQcKPVLrAB0RbaIEr437itxWg2LhSzbSd8LfcWrJ9Uw
-Q_EfsKtVcFhF453ewreN1aeqvRkCGJ8x8DWlwzeg7sCCeRAB1NctLs6Z
</crypto_block>

<customer_data>
<title>Mr</title>
<first_name>Peter</first_name>
<initials>C</initials>
<last_name>French</last_name>
<suffix>MIEE, MEng</suffix>
<address_line_one>Ingresso Group Ltd</address_line_one>
<address_line_two>The Metro Building, 1 Butterwick</address_line_two>
<town>Hammersmith</town>
<county>London</county>
<postcode>W6 8DL</postcode>
<country_code>gb</country_code>
<work_phone>020 3137 7407</work_phone>
<home_phone>020 3137 7407</home_phone>
<email_address>petefrench@ingresso.co.uk</email_address>
<supplier_can_use_data/>
</customer_data>

<card_data>
<card_number>4929123456788</card_number>
<expiry_date>1204</expiry_date>
<cv_two>123</cv_two>
</card_data>
</purchase_reservation_part_one>

<return_token>T1n7SQpAMgYAAAio978AAAAD</return_token>
<return_domain>my.site.com</return_domain>
<return_path>/some/path/t.T1n7SQpAMgYAAAio978AAAAD/</return_path>
<return_with_https>yes</return_with_https>
<encryption_key>somekindofkeyover20chars</encryption_key>

28. Potential failure codes

The following failure codes are to be treated as any other codes in the system would be, and appear inside “fail_code” and “fail_desc” elements as usual. They follow the same general pattern as the 1100 error codes, and thus code can be easily migrated. Some 1100-type codes are never returned here, however, and some new ones have been added.

  • 1 - the supplied crypto block was not generated by “make_reservation”
  • 2 - the requested “mime_text_type” was not a supported value
  • 1301 - the reservation has expired
  • 1302 - no “customer_data” element has been supplied
  • 1303 - no “card_data” element has been supplied when required
  • 1304 - a “card_data” element has been supplied when not required
  • 1305 - no “country_code” element was present in the customer data
  • 1306 - the chosen despatch method does not allow the given country code in the customer data
  • 1307 - the supplied email address fails RFC822 syntax checking
  • 1308 - the customer details supplied are incomplete
  • 1309 - no “card_number” element was present in the payment card data
  • 1310 - the payment card type is not known from the supplied card number
  • 1311 - the payment card type is not one of those accepted for this transaction
  • 1312 - the card number given is not valid for cards of that type
  • 1313 - no “expiry_date” element was present in the payment card data
  • 1314 - the expiry date given is not valid
  • 1315 - no “cv_two” element was present in the payment card data
  • 1316 - the CV2 value given is not valid
  • 1317 - no “issue_number” element has been supplied when required
  • 1319 - the issue number given is not valid
  • 1320 - alternate card billing address supplied when not supported
  • 1321 - the alternate card billing address details supplied are incomplete
  • 1322 - no “start_date” element has been supplied when required
  • 1323 - the start date given is not valid
  • 1324 - the users prefill data is not editable, and does not match the customer data supplied
  • 1325 - a “card_data” element has been supplied over a non-encrypted connection
  • 1326 - a bad “return_token” element has been supplied
  • 1327 - a bad “return_domain” element has been supplied
  • 1328 - a bad “return_path” element has been supplied
  • 1329 - a bad “return_with_https” element has been supplied
  • 1330 - a bad “encryption_key” element has been supplied
  • 1331 - the supplied “return_token” element has already been used

28.1. The new purchase_reservation_part_two method

The part two purchase method is called whenever a callback occurs back to the client site. It’s purpose is to complete any previously generated redirect, and to issue a new one if necessary. Thus there are two possible returns from this method - a new redirect, or the final purchase result data. The purchase result data has been designed to match that returned by the original “purchase_reservation” method, with the caveat that multiple calls to this method will return the same data, rather than failing with “already purchased” after the initial call.

For simplicity of client implementation, this method does not require a “crypto_block” to be passed to it, and can take the “user_passwd” directly, in the same way as the “start_session” method does. If a “crypto_block” is preferred, however, then the one from “start_session” may be used. The same encryption key used in the part one purchase also needs to be provided, inside an “encryption_key” element.

This method is only ever called as the return from a previous redirect, with the token identifying the redirect passed in the path as previously described. The token from the path must be passed into the method in the “returning_token” element, and then three elements are passed containing three HTTP headers. These are “http_referer”, “http_accept” and “http_user_agent”, and contain the data from the associated HTTP header. These fields are used by certain debitors, and are thus mandatory. Finally the actual returned CGI variables are passed, contained as individual elements with an element called “callback_data”. This should contain all the POST or GET variables, plus any variables from the query string, even in the case of POST. Whilst we realise this is not standard (a POST request should not have a querystring) we have encountered some systems which do this, and thus this behaviour is, regrettably, necessary. Each returned CGI variable is passed in an element of its name, with the contents of the element being the string data passed in the variable.

Finally, as the method may return a new redirect, a set of elements are passed to contain a new token and associated return URL. As with the part one method, the return token should be generated fresh every time, even if the method is being called repeatedly, which is more likely in this case as the return URL may be refreshed by the customer’s browser. The new return token and path are specified in the elements “new_return_token” and “new_return_path”. The domain and https flag are taken to be the same as those provided in part one.

28.1.1. Example input

<purchase_reservation_part_two>
<user_id>demo</user_id>
<user_passwd>demopass</user_passwd>
<encryption_key>somekindofkeyover20chars</encryption_key>
<returning_token>T1n7SQpAMgYAAAio978AAAAD</returning_token>
<new_return_token>T14I-QpAMgYAAAil914AAAAA</new_return_token>
<new_return_path>/some/path/t.T14I-QpAMgYAAAil914AAAAA/</new_return_path>

<http_referer>https://some.debiting.site/</http_referer>
<http_accept>text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8</http_accept>
<http_user_agent>Mozilla/5.0 (X11; FreeBSD amd64; rv:7.0.1) Gecko/20100101 Firefox/7.0.1</http_user_agent>

<callback_data>
<data1>Some data</data1>
<data2>Some more data</data2>
</callback_data>

</purchase_reservation_part_two>

29. Potential failure codes

As all of the input data for a purchase has been checked in the part one method, the failure codes which can come from here are limited to checking the callback variables, and they are listed below. Additionally, however, the call may generate the same failure codes for the purchase which are handled as special cases in the original “purchase_reservation” method, as it will produce the same output data on completion. Thus the same code should be used to handle the complete purchase return as was used in the non-redirecting implementation.

  • 1401 - a bad “returning_token” element has been supplied
  • 1402 - the “returning_token” is unknown
  • 1403 - the trolley was already purchased, but we cannot reproduce the results page (very unlikely)
  • 1404 - the reservation has expired
  • 1405 - a bad “new_return_token” element has been supplied
  • 1406 - a bad “new_return_path” element has been supplied
  • 1407 - a bad “encryption_key” element has been supplied
  • 1408 - the “sub_id” has changed since part one purchase
  • 1409 - one of the http header elements is missing
  • 1410 - the “callback_data” element is missing
  • 1411 - the supplied “new_return_token” element has already been used