[ic] Vend::HostedPayment proposal

Angus Rogerson arogerso at uwaterloo.ca
Tue Apr 1 13:07:06 UTC 2014

Hello list,

We have used beanstream's hosted payment service for credit cards on our 5.4.x interchange for a number of years. As we started upgrading to 5.8.0 we started looking at updating the interface to beanstream. Other users have talked on this list about using hosted payment aka transparent redirect with braintree. When it comes time to negotiate with payment processors, it would be to our advantage to have a standardized way of interfacing with hosted payment systems so it would be easy to switch providers. After some discussion with a few people, and some research on existing interchange payment modules, I have written a proposal for a hosted payment module. The proposal needs plenty of polishing still but I am spinning my wheels with too many unknowns and questions at the moment. I would appreciate any feedback about the general design (including terminology (processor vs gateway), names etc), and suggestions for improvement and places to look for existing code which could be used. Thanks -Angus


Interchange currently uses the module Vend::Payment as a base class for payment processing. The module provides a uniform interface between interchange and multiple payment processors. Specifics for each processor are handled in Vend::Payment::SomeProcessor. The Payment module implements a server-server model of transaction processing. Under this model, interchange collects all user and payment information. When the user submits the order, Vend::Payment assembles the information in a suitable format for the particular payment processor and sends it using an appropriate protocol to the processor's server and waits for a response. The response is processed by Vend::Payment, setting the appropriate interchange values and variables and the interchange transaction is completed or the user is informed of an error or decline.

Because interchange is collecting the user's credit card information the interchange server must be PCI compliant. (We could argue about 'must' - but there are various legal, contractual, ethical issues depending on the application, industry and jurisdiction which support it.)

Because interchange interfaces to Vend::Payment, it is at least theoretically possible to switch providers simply by specifying a different Vend::Payment processor module, and changing some variables.

A number of credit card processors offer an alternative model with various names: hosted, transparent redirect etc. Under this model, interchange collects whatever information it requires to fulfill a transaction (name, address, contact information etc) then directs the user's browser to the processor's secure (or hardened for the security geeks) website passing some type of transaction identifier, the amount to be charged and any customer information that is appropriate. The processor collects any information which has not already been provided by interchange from the user and collects the payment card information. The processor processes the payment card transaction and directs the user's browser back to an appropriate entry point in interchange where the interchange transaction is completed.

At no time does interchange see the credit card number. In fact, with some providers, interchange need not even see the name, address and contact information of the customer. This significantly reduces the PCI compliance needs. However, be sure to check with a competent security geek that this model meets your organization/industry/jurisdiction's requirements.

Under this model the user's browser must be redirected to another page during the transaction so the transaction flows differently than in the server-server model. This type of transaction has been implemented in some Vend::Payment modules, but always with the warning that it is not compatible on a call level with standard interchange payment modules. These modules require setting up additional pages and in some cases changes in etc/log_transaction and other code.

Many of the modules in Vend::Payment duplicate a lot of the translation code provided in Payment.pm and each other.

We plan to develop a new module Vend::HostedPayment, which used together with processor specific modules (Vend::HostedPayment::SomeProcessor), will provide a uniform interface between interchange and multiple hosted payment systems. (Alternatively, this might be implemented as Vend::Payment::HostedPayment, so that the existing code in Payment.pm does not need to be rewritten.) Most of the techniques and code would be adapted from the existing payment module and related processor modules, ideally Vend::HostedPayment would be backward compatible to Vend::Payment.

If opportunities for more general abstraction present themselves, then we may develop Business::HostedPayment which would be to Vend::HostedPayment as Business::Payment is to Vend::Payment.


	• Pass information to arbitrary processor
		• arbitrary information to be entered in Interchange or on the processor's hosted site
			• ex: name and address may be entered in interchange, then credit card information entered on the processor's hosted site
		• supporting a variety of methods
			• from a form that the user fills out on your site
				• submit goes to the payment processor's site
				• the form is generated by interchange, but potentially sensitive payment data is only submitted to the processor's hosted site
			• or, as part of the standard Interchange charge procedures
		• requires
			• mapping field names from interchange (or possibly someone's custom ones) to field names expected by processor
				• possibly combining fields (ex: name = fname + lname or lname, fname)
			• flexibility for slightly different transaction sequences
				• use server-server to get a token before sending the user to the processor's site
				• use server-server to send a token confirming the transaction after the user returns to interchange			
			• specify additional information such as
				• the redirect url to get back to interchange
				• encrypted/hidden fields to send to braintree
	• Get information back from processor
		• at a page specified in the redirect url in the request
			• or possibly an action map
		• perform any necessary munging on the URL
			• Ex: beanstream returns myserver/cgi-bin/catalog/process.html?session_id?param=value&param=value - the extra ? confuses interchange
		• optionally update data modified while on the processor's site
			• Ex: customer changed address information while on processor's site
		• Perform additional processing required by some processors
			• ex: braintree confirm transaction by sending token
	• Complete the transaction and pass control back to interchange to display the receipt or tell the user about the problem and give them another chance


	• tools to define
		• mapping of
			• interchange field names to payment processor field names
			• payment processor results to interchange field names, database fields to save
			• pass/fail and error messages to user choices (option to retry or completely fail)
		• possibly to apply filters such as all caps, initial caps
		• combine fields in standard ways: year and month sent as yy/mm, fname, lname sent as fullname
	• usertags for a form whose action is to go to the processor, this is based on the model described by braintree  where the application has a form with the processor's field names - this would allow the user to make changes to values and proceed directly to the processor without validation by any interchange profiles, this is likely something that would be used by Business::HostedPayment rather than Vend::HostedPayment
		• HostedPaymentForm
			• generate the <form > tag for a form which will go to the paymentprocessor on submit (without any interchange validation)
		• HostedPaymentHiddens
			• generate the hidden fields required, this call may require server-server calls to generate some sort of transaction token
		• HostedPaymentFields
			• container tag which translates all input name= values from their interchange name to processor's field name
			• to convert applications which currently have an input form which requests all this information
		• HostedPaymentInput - generate an html <input /> tag with a value/evalue taken from interchange and a name suitable for the payment processor
	• mechanism to proceed from interchange to the provider, passing the necessary information
		• probably a &charge or [charge] with option=preCharge
		• allow interchange to detect that a call to Vend::HostedPayment is required as happens now with the current Vend::Payment
			• payment method selection, buttons and profiles to get from submit order to the paymentprocessor
		• HostedPaymentBounceToHost
			• generate a page which has a url to redirect the user's browser to an appropriate host
			• this may require server-server calls to generate some sort of transaction token
			• accept a parameter for type of transaction, sale, preauth, refund, etc
				• transaction types defined for each processor
				• if a transaction type is not defined for a processor then fails and logs an error
	• mechanism to return from payment processor
		• probably &charge or [charge] with option=postCharge
		• possibly an action map to handle anomalies in URL returned from the processor
			• for example: beanstream returns a query string consisting of the parameters we sent separated by a ? from the parameters it is returning
				• myhost/cgi-bin/icuser/mycatalog/process?mv_session_id=123&mv_order_profile=hosted ? trnApproved=0;trnId=1234 etc
			• defined
				• as separate file which goes in code/GlobalSub/hosted.globalsub and calls munge routine in Vend::HostedPayment
				• or maybe defined cleverly in the module (but outside the package)
			• used in return url instead of process, in the case of beanstream, munge the '?' into an '&' or ';'
			• continue on as though process had been called
		• page containing the appropriate charge tag
			• to accept and process results from processor
		• return url from processor will include mv_order_profile, that profile includes a line like
			• &charge=HostedPayment SomeProcessor
				• ??? or setcheck mv_success=[HostedPayment SomeProcessor]
	• mechanism for outbound intercept for testing
		• when in test mode, [HostedPaymentBounceToHost] (and possibly [HostedPaymentForm] and [HostedPaymentHiddens])
			• generates a URL to the intercept page, and
			• passes the URL that it would have sent.
			• The intercept page
				• generates a form which
					• displays the fields that would be sent to the processor and
					• allows the programmer to modify those values for testing and
				• has an action of the URL that would have been used
					• or possibly a loopback / short circuit page
				• is quick and dirty with no ITL interpolation
	• mechanism for inbound intercept for testing
		• when in test mode, [HostedPaymentBounceToHost] (and possibly [HostedPaymentForm] and [HostedPaymentHiddens])
			• changes the URL for returning from the processor
				• from process or munge
				• to the inbound intercept page
			• The intercept page
				• generates a form which
					• displays the fields that were returned by the processor and
					• allows the programmer to modify those values for testing and
				• has an action of the URL that would have been used
				• is quick and dirty with no ITL interpolation

Parameters and Datastructures

	• one or more map hashes will be needed for each processor to map field names and transaction types to and from interchange
		• possibly use regular expressions, perl s///, sprintf to allow more complex mapping (ex: mapping interchange's fname, lname to a processor's wholeName)
	• parameters related to the merchant or transaction defaults set in the usual interchange cascading way, with defaults set in Variables, possibly overridden in Routes, possibly further overriden in parameters passed to tags and functions
		• ex: [HostedPaymentBounceToHost beanstream] which uses merchant_id etc defined as variables (doing this would allow the use of multiple hosted payment processors perhaps for different tenders)
		• or [HostedPaymentBounceToHost] which uses processor=beanstream, merchant_id etc defined as variables (doing this allows a change of processor more easily)
	• parameters related to the payment processor defined in the Vend::HostedPayment::SomeProcessor module (ex: which fields to send, target URL for processor)
	• flag for test intercept, when set does inbound and outbound intercepts of transactions
	• flag for sandbox, when set uses sandbox settings defined for each payment processor

Structure of new modules

	• Vend::HostedPayment
		• sub charge which should perform the same as Vend::Payment sub charge, but consisting of
			• call to preCharge
			• call to processor specific preCharge
			• call to post_data
			• call to processor specific postCharge
			• call to postCharge
		• sub preCharge (first part of sub charge stolen from Vend::Payment), ending with call to processor specific preCharge and bounce to processor
		• sub postCharge (last part of sub charge stolen from Vend::Payment), begining with bounce from processor and call to processor specific postCharge
		• sub charge_param, map_actual, gen_order_id, post_data - stolen from Vend::Payment
			• plus possibly other helper functions
	• Vend::HostedPayment::Gateway
		• possibly implemented by setting Package Vend::HostedPayment, or maybe done the OO way
		• define maps which describe translation
			• from interchange to Gateway field names
			• from gateway to interchange results
		• to be used by
			• Vend::HostedPayment sub preCharge
			• Vend::HostedPayment sub postCharge
		• sub preGateway - processing required before bounce to the gateway
		• sub postGateway - processing required after bounce back from the gateway

Angus Rogerson, BMath, BScN, RN

Duct Tape Programmer
University of Waterloo | Retail Services | Information Systems

Visit Us Online & Right On Campus www.retailservices.uwaterloo.ca

More information about the interchange-users mailing list