Integrating Voucher-Safe Payments

Into an e-commerce Website

15 July, 2011

Voucher-Safe.org



I. Overview

Voucher-Safe (VS) is a peer-to-peer (p2p) value transfer system built on top of XMPP/Jabber. It is quite possible to receive VS payments for orders on an e-commerce website, as described herein. However, due to the VS system's p2p nature, and because it is built on XMPP rather than HTTP, the integration procedure is somewhat different from the conventional integration techniques used with centralized web-based payment systems, such as PayPal or Pecunix. We will begin by elaborating upon these differences.

In a standard web payment system integration, the essential steps are these:

  1. Customer creates an order on the merchant's website.

  2. Merchant web server records customer's order in database.

  3. Customer reviews and approves order, and is redirected to secure payment system website. Order details are passed to payment system, typically via POST values.

  4. Customer completes payment.

  5. Payment site redirects customer back to merchant site, to either a success URL or a failure URL.

  6. On successful return, merchant web server verifies the payment. (This may also be performed following step 8.)

  7. After successful verification, the web server triggers whatever back-end processing is required to fulfill the customer's order.

  8. Depending upon the merchant's account settings at the payment system, there may be another parallel step where the payment system sends an out-of-band (OOB) notification directly to the merchant website announcing the payment.

In a Voucher-Safe payment integration, the functionally equivalent steps are as follows:

  1. Customer creates an order on the merchant's website.

  2. Merchant web server records customer's order in database.

  3. Customer reviews and approves order, starts their Voucher Safe Client (VSC), and tells the merchant website the Jabber ID (JID) at which their VSC is connected to the network.

  4. Merchant web server sends the order details to the customer's JID, encrypted with a unique security code, which is displayed to the customer.

  5. Customer enters the security code to decrypt the order details, which pre-populates their client's payment form with the merchant's information. Customer then completes payment.

  6. After completing the payment, customer returns to their browser and clicks a "Payment Completed" button to tell the merchant web server to go retrieve the incoming payment.

  7. Merchant web server invokes the Voucher-Safe command-line interface (CLI) client to retrieve only the specific payment just made by the customer.

  8. Based on whether the payment was indeed found, the merchant's web site redirects the customer to either the success URL or the failure URL.

  9. On success, merchant web server triggers whatever back-end processing is required to fulfill the customer's order.

It can be seen that two steps were added, and one step removed:

Using as a reference the sample PHP code provided in the SCI ZIP package, we will now examine the specific unique steps in detail.



II. System Requirements

To integrate Voucher-Safe payments as described below, you will need the following:

A voucher safe is essentially a digital wallet which contains vouchers. You can create one using the graphical client (VSC), available at voucher-safe.com. Be sure to pick a name prefix for your safe which resembles your website or service, so the customer will be reassured they are paying the right party.

A Jabber account is an instant messaging chat login, which can be created at any XMPP/Jabber server using any desired chat client (e.g. Spark, Pidgin). For improved notification speed and privacy however, you may wish to create your login directly on the Voucher-Safe system's gateway server, which is available at ofs.vm.to port 5233. The customers will not see your chat login name, so it is unimportant (unless you also use it for customer support or as contact info).

If you wish to integrate using a language other than PHP, such as Perl, Java, Python, or Lisp, you will need to provide functionality equivalent to the XMPPHP package (which allows PHP to send Jabber messages), and the class VoucherSCI (see VoucherSCI.php in the SCI demo package), which encrypts and formats customer order info messages according to the jabber:message:voucher-safe#web-vsc extension. This task is beyond the scope of this document.



III. Integration Steps

We shall not belabor the first two logical steps, involving the creation and storage of a customer order on the merchant's website. This should be performed in the usual manner; typically there is a unique database index such as an orderId or a customerId which suffices to look up the details of the customer's order.

A. Obtaining Customer JID

The first VS-specific step occurs at the point where the customer is vectored to the checkout page, and selects Voucher-Safe as their desired payment mechanism. At this point the user must be instructed to open their VSC program (which is a Java webapp), and input the Jabber Id (JID) at which they are connected. The user obtains this by opening the Advanced/Show JID popup window. The VSC connects via an anonymous login, so the JID will be different for each connection. This JID must be obtained by the web server so that the identifying order details (e.g. merchant payee, amount and units, and order identifier) can be sent to the customer's VSC. A simple example form which does this is found in demoForm.html in the SCI demo package, and can be seen online here. (In fact, the entire demo procedure is available online starting from this point, and can be used by anyone assuming that you have a voucher safe @voucher-safe.org which is funded with some test value; see Appendix.)



B. Specifying the Amount and Selected Issuer

This sample form also asks for an amount, currency units for that amount, and the value of two sample baggage fields. In reality the amount is probably already fixed by the customer's order specifications by this time. The currency units supported by the VSC for specifying payment amounts are as follows:



Currency Name

Code

United States Dollars

USD

Argentine Pesos

ARS

Australian Dollars

AUD

Brazilian Reals

BRL

Canadian Dollars

CAD

Swiss Francs

CHF

Chinese Yuan Renminbi

CNY

Columbian Pesos

COP

Euros

EUR

Grams of Gold

GAU

UK Pounds Sterling

GBP

Gold Globals

GLO

Hong Kong Dollars

HKD

Indonesian Rupiahs

IDR

Indian Rupees

INR

Japanese Yen

JPY

Kuwaiti Dinars

KWD

Mexican Pesos

MXN

Malaysian Ringgits

MYR

New Zealand Dollars

NZD

Peruvian Nuevo Sols

PEN

Philippine Pesos

PHP

Russian Roubles

RUR

Swedish Krona

SEK

Singapore Dollars

SGD

Silver Isles

SIL

Turkish Lira

TRL

Vanuatu Vatus

VUV

Ounces of Silver

XAG

South African Rands

ZAR



In addition you must specify the voucher Issuer whose vouchers you wish to accept. Every Voucher Publisher (VP) supports one or more Issuers. The Issuer is the party who stores the actual assets represented by the vouchers, and typically handles the buying and selling of those assets at the wholesale level to/from retail currency exchangers. The demo form supports 3 Issuers: TESTGOLD, TESTUSD, and TESTEURO. As their names suggest, none of these represent any actual value. If the VP at which your merchant voucher safe was created supports multiple Issuers, you may wish to specify which types you are willing to accept. For example, as of this writing the VP network @vouchi.com presently supports these bona fide Issuers: VI-USV, VI-EUV, GSFS-AU, and GSFS-AG. The first two represent value measured in fiat currencies (USD and EUR respectively), while the latter two represent Gold Globals and Silver Isles minted by the Global Settlement Foundation. Others will be added in future.

Your acceptance of vouchers from particular Issuers will naturally depend on such factors as in and out exchange fees, liquidity, and reputation. If you have preferences, these can be specified so that customers can pay you only using vouchers from an approved Issuer. In the example, this is done by means of a simple options list. Note that if the customer does not have sufficient value from the selected Issuer in their voucher safe, they will of course not be able to pay you.



C. Sending the order details to the customer's client

Now that we have the customer's total payment amount, order identifier, and selected Issuer, we must communicate this information securely to their Voucher-Safe Client (VSC). To do this, we will create an object of class VoucherSCI. The PHP code below is extracted from scidemo.php in the demo ZIP:



require_once("VoucherSCI.php");

// CUSTOMIZE for your environment as needed below

// the Jabber server where your web bot has a login

$jabber = "ofs.vm.to";

// your merchant website

$website = "http://<your domain here>";

// your merchant VS# where you receive payments

$merchantVS = "mymerchantsafe-1234@vouchi.com";



// set up voucher SCI interface

$vouchSCI = new VoucherSCI($website,

$jabber, // <-- the Jabber server you use

5233, // <-- your Jabber server's listen port

"myuser", // <-- your web bot's username

"mypasswd", // <-- your web bot's password

null); // <-- JID/resource (ignored)

// set the VS where we wish to be paid

$vouchSCI->setSellerVS($merchantVS);

For the values of $jabber, the port, and the 'web bot' username/password, enter the details for the Jabber account you created using your favorite Jabber client. This login will be the sender for the message to the customer's client. (We suggest you do not use the generic values in scidemo.php, even though they presently work.)

Next, to secure the message while in transit from your web server to the customer's VSC, we need to generate an encryption code. This can be done like this:



// pick a secret (8 chars long in this example)

$secretLen = 8;

$secret = $vouchSCI->pickSecret($secretLen);

The pickSecret() method simply generates a random number, computes its MD5 hash, and takes the first N digits of it. The result is thus a random hexadecimal number of the given length. You may use 8-24 digits (>24 are ignored). You may also generate the secret by any other method you wish.

Next, we construct a Subject line for the message. This will be displayed in the customer's client, as the prompt above the text input for entry of the decryption code. Therefore, it's a good idea to identify both your website and the orderId number (or other order index which the customer can recognize).

The $baggage array can contain at most 3 name/value pairs. At minimum, it contains the customer's order identifier, $orderId as shown here. (This parameter will be used in step E as a search key to identify and retrieve the customer's incoming payment.)



// build the subject and baggage -- order Id in subject is a good idea

$subject = "Your order #" . $orderId . " from " . $website;

$baggage = array('orderId' => $orderId);

Now we simply request the SCI object to encrypt the message with the secret (using 3DES), log in to our Jabber account, and send the message to the customer, thus:



// send the order data

$vouchSCI->sendOrderInfo($buyerJID, $subject, $amount, $currency, $issuer, $baggage, $secret);

The $buyerJID is the customer's JID which was acquired in step A. The $amount, $currency, and $issuer were specified in step B. The value of $currency must be valid 3-letter international currency code, as listed in the second column of the table in step B. For example, for C$19.95 worth of USV these values would be: 19.95, "CAD", "VI-USV". The VSC will automatically perform unit conversions based on current relative market prices for fiat currencies and/or precious metals. Thus it is important to note that, while in this example you would be paid the value of $19.95 CAD in USD, using the correct exchange rate at the time the payment is made, when reviewing orders later you may discover that the value of the voucher you received has changed, and is now worth more or less than C$19.95. This will always be the case unless your currency value and the Issuer's asset units are identical.



D. Display decryption code and wait for customer to indicate payment was completed

We must now show the customer a confirmation that their order details were sent, and indicate the decryption code which they must use to access the message. The code may be shown in text form, or by using the method supplied, as a JPEG graphic (or both). If your website is not using https, then using a graphic is indicated in order to avoid sending the code over an unsecured web connection. We must then offer a button or other control which the customer can click to indicate that they've made their payment. The following XHTML example code does this (again, taken from scidemo.php):



// display results

?>

<html>

<head>

<title><?php echo($website . " order data sent"); ?></title>

</head>

<body bgcolor="cyan">

<br/><br/><br/>

<!-- your content here -->

<center>

<p>

Your order <?php echo($orderId . " "); ?>

information has been sent to: <?php echo($buyerJID); ?>

<br/>

</p>

<p>

<!-- You may use the displaySecret.php tool as below to show the decryption

secret graphically. This is essential if you are not using https.

You may also show the plaintext, to enable copy/paste.

-->

Your order decryption code is: <?php echo($secret);?><br/>

<img src="displaySecret.php?secret=<?php echo("$secret&digits=$secretLen");?>"

alt="<?php echo($secret);?>"/>

</p>

<br/><br/><br/>



<!--

The user must click this button once their Voucher-Safe payment has been completed. Doing so will trigger a payment pickup invocation. CUSTOMIZE the form action to go to your payment pickup processor.

-->

<form method="POST" action="scipickup.php">

<center>

Please make your Voucher-Safe payment to: <?php echo($merchantVS); ?>.<br/><br/>

To do this, in your Voucher-Safe client click on Payment and enter the

decryption code displayed above.<br/>

Your payment form will be pre-populated with the data from your website order.

<br/><br/>

When you have successfully made your payment, click on the Payment Completed

button below.<br/>

Processing can take a minute or two, so be patient.

<br/><br/><br/>

<input type="submit" name="pmtdone" value="Payment Completed"/>

</center>

<!-- you must tell the processor what baggage field to look for, plus its value -->

<input type="hidden" name="pmtKey" value="orderId"/>

<input type="hidden" name="keyVal" value="<?php echo($orderId);?>"/>

<!-- NB: you might also want to pass as hidden fields anything which will be

wanted by the success and failure URLs.

-->

</form>

</body>

</html>



E. Pick up the customer's voucher payment

Once the customer has asserted that their payment was made, we must now examine our merchant voucher safe to see if the payment is there. In the sample demo, this is done in scipickup.php. You should read this file very carefully, and customize it appropriately for your site, or otherwise integrate it procedurally into your existing code.

Of particular note are the settings for $OFShost and $OFSport. These refer to the gateway XMPP server on the VS network. At present, this is at ofs.vm.to:5233, and this is also the default for the CLI if the -x and -p flags are not specified. However, note that more or different gateways can be specified in future. Any changes will be indicated in the JNLP file found at voucher-safe.org.

In order to avoid storing the login credentials of your merchant VS within the directory tree of the web server, the CLI will automatically read them from the file ~/.vouchers/.vshlogin. The format of this properties file must be as follows:



# this file contains merchant voucher safe login info -- keep it secure

vsnum=mymerchantsafe-1234@vouchi.com

pin=NNNN

longphrase=mylongphrase

passphrase=mypassphrase

Customize the .vshlogin file with the login credentials for your merchant VS, and then ensure that the file permissions are mod 400, owned by the system user that runs your web server.

Note: there is of course no obligation to utilize the convenience function http_redirect(). If you do use it, you may need to do a "pecl install pecl_http" on your system first. (See Appendix for procedure details.)

Most of the demo file scipickup.php is reproduced here:

// open log file

openlog("VS Web SCI", LOG_PID, LOG_USER);

// the path to the JAR file which contains the Voucher-Safe CLI executable

$execJAR = "/var/www/websci/java/voucher-cli.jar";

// the OFS gateway hostname

$OFShost = "ofs.vm.to";

// the OFS gateway port number

$OFSport = 5233;

// the location to which we direct the user on successful payment pickup

$successURL = "pmtSuccess.php";

// the location to which we direct the user on payment pickup failure

$failureURL = "pmtFailure.php";



// NB: the login details for the payment receiving safe must be stored

// separately in the file ~/.vouchers/.vshlogin (where ~ is the home

// directory of the user running the web server, e.g. www-data).



// invoke the CLI, telling it what to look for

// Notes: 'java' must be in the path. Also, if you have spaces in either the

// $pmtKey or $keyVal, you'll need to add enclosing double quotes.

$pmtKey = $_POST['pmtKey'];

$keyVal = $_POST['keyVal'];

$invoke = "java -jar $execJAR -x $OFShost -p $OFSport -w -b $pmtKey:$keyVal";



// invoke the CLI client

$result = exec($invoke);



/* The value of $result will be one of these:

* 1. "NOT FOUND" - if the payment could not be found

* 2. a JSON string - if the payment was received successfully

* 3. an error - otherwise

*/

$redirArgs = array();

$redirArgs[$pmtKey] = $keyVal;

if ($result === "NOT FOUND") {

syslog(LOG_ERR, "Payment not found for key $pmtKey:$keyVal");

http_redirect($failureURL, $redirArgs);

}

else {

$pmtDesc = json_decode($result, true);

if (is_null($pmtDesc) || !is_array($pmtDesc) || empty($pmtDesc)) {

// some other kind of error

syslog(LOG_ERR, "Error receiving payment for key $pmtKey:$keyVal : $result");

http_redirect($failureURL, $redirArgs);

}

else {

// Certain items are found in the JSON, which should be recorded or

// confirmed to match the order.

$baggage = array();

foreach ($pmtDesc as $field => $value) {

$redirArgs[$field] = $value;

switch ($field) {

case 'PAYER':

// the customer's VS# (record in case of a refund)

$payerVS = $value;

break;

case 'AMOUNT':

// echo of amount (should be confirmed)

$amount = $value;

break;

case 'UNITS':

// echo of amount units (should be confirmed)

$units = $value;

break;

case 'ASSET':

// voucher asset type (indicates asset supported by Issuer)

$asset = $value;

break;

case 'ISSUER':

// echo of asset Issuer (should be confirmed)

$issuer = $value;

break;

default:

// baggage field

if ($field != $pmtKey) {

$baggage[$field] = $value;

}

break;

}

}

syslog(LOG_NOTICE, "Payment received: from $payerVS, $amount $units of "

. "$asset at $issuer, $pmtKey = $keyVal, baggage: " . print_r($baggage, true));

http_redirect($successURL, $redirArgs);

}

}

closelog();



F. Display success or failure to customer; process order

In this example, this is done in pmtSuccess.php and pmtFailure.php. These handlers are not very interesting, merely emitting some plaintext recapitulating the arguments passed to them. In actual use, you would direct the customer to the appropriate return page, just as you would customers who paid by any other method.

Back-end processing, e.g. initiating an order shipment or activating a user subscription, would be triggered either by the 'success' URL, or in the payment pickup processor once you are satisfied that the payment was received and agrees with the expected values. Note that the VSC does not allow the user to alter payment fields received via a decoded website message. However, since the VSC is a published-source utility, it is conceivable that a user might be running an altered client which has been modified to permit this. It is therefore advisable to validate the amount, units, and other fields returned in the JSON string. An example of the JSON string returned following successful payment pickup is as follows:

{ "PAYER":"joecustomer-2345@vouchi.com", "AMOUNT":21.24, "UNITS":"USV", "ASSET":"USV", "ISSUER":"VI-USV", "orderId":3456 }

This indicates that a customer whose VS# is joecustomer-2345@vouchi.com paid a voucher in the amount of US$21.24 (equivalent, on this date, to C$19.95) representing value stored with VI-USV, to fulfill orderId 3456. (Observe that the value of 1 USV is fixed at 1 USD.)

Signed receipts are automatically generated by the CLI and sent back to the customer. It is therefore technically redundant to do this by other means such as email, but still may be desirable. Receipt copies are also stored in your merchant safe, and can be reviewed by logging into it manually. Doing so periodically, and pruning receipts which are no longer needed is a good idea, especially if you experience a lot of sales, because it can become unwieldy to deal with a very large number of stored receipts (mainly because they all need to be decrypted before they can be viewed).

To prevent overlapping access to your merchant VS, separate copies of the CLI running in parallel are synchronized by means of a system-wide login semaphore. It is therefore not necessary to serialize processing in the web server. Do be aware that pickup processing can take some time, depending on many variables. It is therefore recommended that you set max_execution_time = 60 (or longer) in your system's php.ini file. A customer's pickup request which is unable to begin running for more than 30 seconds due to a semaphore block will time out, and must be retried if this occurs.

Lastly, be aware that your merchant safe login credentials are stored on your web server. This means that someone who hacked, root-kitted, or otherwise gained access to your server could theoretically find that file and use it to steal your accumulated value. Since voucher safes cost nothing to create, and one can have as many of them as one wishes, it is therefore recommended that you periodically log into your merchant safe and "sweep" voucher value into another VS whose login credentials are completely private. This is analogous to the procedure commonly used with PayPal for example, where sales revenues are periodically flushed to a bank account or debit card, for similar reasons.



APPENDIX

Notes on installing the pecl_http utility

If you wish to use http_redirect, as in the example code, you will need to install the pecl_http package. This is a package which is built from source; therefore you may need some prerequisite packages as well in order to get the include files and libraries which are needed. On a Debian or Ubuntu system, you can do this as follows:

It is quite likely that the apt-get commands, especially for php5-dev, will also pull in a significant number of dependencies. The pecl command performs the actual compilation of the package.



Sandbox Testing

It is customary to debug a web payment integration in a sandbox environment using play money. Happily, this is also possible with Voucher-Safe. To do this, use the VSC to create at least two safes on the @voucher-safe.org network. This VP is for test and demo purposes only, and will never have any real Issuers. You may then request any amount of test funding for your safe(s), in TESTUSD, TESTEURO, or TESTGOLD, by making a post in the forums on either voucher-safe.com or voucher-safe.org. In your post, indicate the VS# you want funded and the kind(s) of vouchers you want.

Once you have a VS with some test value in it, you can try out the demo SCI online.

The @vouchi.com VP also has a single test Issuer called TESTING (which is gold-based), but to avoid any possible confusion with any real-money vouchers which safes on that network may contain, we suggest that you use test merchant and customer safes on the @voucher-safe.org network only.



This concludes the documentation on the Voucher-Safe web SCI. If you have questions, comments, or improvements, please join the voucher-safe.org community and post in the forums.