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.
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.
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.
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.
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.
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.
.. code-block:: xml
<html><head>
<script type="text/javascript">
window.location="http:\/\/google.co.uk\/";
</script></head>
<body></body></html>
The HTML page which is contained in this response is this:
.. code-block:: xml
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.
.. _purchase_reservation_part_one:
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.
Example input
~~~~~~~~~~~~~
.. code-block:: xml
demo
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
Mr
Peter
C
French
MIEE, MEng
Ingresso Group Ltd
The Metro Building, 1 Butterwick
Hammersmith
London
W6 8DL
gb
020 3137 7407
020 3137 7407
petefrench@ingresso.co.uk
4929123456788
1204
123
T1n7SQpAMgYAAAio978AAAAD
my.site.com
/some/path/t.T1n7SQpAMgYAAAio978AAAAD/
yes
somekindofkeyover20chars
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
.. _purchase_reservation_part_two:
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.
Example input
~~~~~~~~~~~~~
.. code-block:: xml
demo
demopass
somekindofkeyover20chars
T1n7SQpAMgYAAAio978AAAAD
T14I-QpAMgYAAAil914AAAAA
/some/path/t.T14I-QpAMgYAAAil914AAAAA/
https://some.debiting.site/
text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Mozilla/5.0 (X11; FreeBSD amd64; rv:7.0.1) Gecko/20100101 Firefox/7.0.1
Some data
Some more data
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