[Warrior Payments] Warrior Payments IPN Integration

by 16 replies
Whenever a sale is made, refunded or reversed, Warrior Payments will send a FORM POST message to the IPN notification URL specified for your product. The message will contain the EXACT response we receive from the PayPal GetTransactionDetails API call. We will also send over extra Warrior Payments product related fields in the IPN message. The following table lists the extra fields sent in the current version (0.1).

In your script that handles IPN messages, you may use any of the fields available to process the sale. Your script can also return a response with greeting messages or special access keys/credentials for your product. This information will be displayed on the "WSO Secure Checkout" page. You can use simple/basic HTML tags such as paragraph breaks to format your message. For security reasons, we do not process JavaScript or iframes in the response.

WSO_SALE_ACTION
Description: Status of the sale (SALE, REFUNDED or REVERSED)

WSO_CUSTOMER_EMAIL
Description: The email address of the customer

WSO_CUSTOMER_NAME
Description: Full Name of the Customer

WSO_PRODUCT_NAME
Description: Warrior Payments Product Name

WSO_PRODUCT_ID
Description: Warrior Payments Product ID

WSO_SALE_ID
Description: Warrior Payments Sale ID

WSO_SALE_AMOUNT
Description: Sale Amount

WSO_SALE_CURRENCY
Description: Currency Code

WSO_TXN_ID
Description: Your PayPal Transaction ID for the sale

WSO_AFF_EMAIL
Description: The email address of the affiliate of this sale (if available)

WSO_AFF_AMOUNT
Description: Affiliate payout of this sale (if available)

WSO_SIGNATURE
Description: Signature of IPN post data using secret key

WSO_IPN_VERSION
Description: The api version

IPN Signature
A WSO_SIGNATURE field is added to the POST data if an IPN Secret is specified. By recalculating the signature in your IPN processing script you can verify that the IPN notification was sent from Warrior Payments untampered. See the following code samples for the actual algorithm that can be used to verify the signature.

Python

Code:
import urllib
import hashlib


def is_signature_valid(data, signKey):
    if 'WSO_SIGNATURE' not in data:
        return False

    expected_signature = data.pop('WSO_SIGNATURE')

    sorted_data = sorted(data.items(), key=lambda x: x[0])
    encoded_data = urllib.urlencode(sorted_data)
    signature = hashlib.sha1(encoded_data + signKey).hexdigest()

    return signature == expected_signature


data = {
    "AMT": "50.00",
    "COUNTRYCODE": "AU",
    "CURRENCYCODE": "USD",
    "EMAIL": "john.doe@email.com",
    "FEEAMT": "2.25",
    "FIRSTNAME": "John",
    "LASTNAME": "Doe",
    "ORDERTIME": "2014-11-27T01:57:40Z",
    "PAYERID": "FYPB3LQJWVV72",
    "PAYERSTATUS": "verified",
    "PAYMENTSTATUS": "Completed",
    "PAYMENTTYPE": "instant",
    "PENDINGREASON": "None",
    "PROTECTIONELIGIBILITY": "Ineligible",
    "PROTECTIONELIGIBILITYTYPE": "None",
    "REASONCODE": "None",
    "RECEIVERBUSINESS": "seller@email.com",
    "RECEIVEREMAIL": "seller@email.com",
    "RECEIVERID": "7KW652V29A9XJ",
    "SALESTAX": "0.00",
    "SHIPAMOUNT": "0.00",
    "SHIPHANDLEAMOUNT": "0.00",
    "TAXAMT": "0.00",
    "TIMESTAMP": "2014-11-27T02:53:45Z",
    "TRANSACTIONID": "2D351485ST427014X",
    "TRANSACTIONTYPE": "webaccept",
    "VERSION": "95",
    "WSO_AFF_AMOUNT": "0.00",
    "WSO_AFF_EMAIL": "",
    "WSO_CUSTOMER_EMAIL": "john.doe@email.com",
    "WSO_CUSTOMER_NAME": "John Doe",
    "WSO_IPN_VERSION": "1",
    "WSO_PRODUCT_ID": "wp_product_1",
    "WSO_PRODUCT_NAME": "ProductA",
    "WSO_SALE_ACTION": "SALE",
    "WSO_SALE_AMOUNT": "50.00",
    "WSO_SALE_ID": "wp_sale_1",
    "WSO_SALE_CURRENCY": "USD",
    "WSO_SIGNATURE": "0380a0fe6515f6552bab3f23c6b5c6c22f9f1f8e",
    "WSO_TXN_ID": "2D351485ST427014X",
    "payer_email": "john.doe@email.com",
    "saleid": "wp_sale_1"
}

print is_signature_valid(data, 'BIG_SECRET')
Ruby:

Code:
require 'open-uri'
require 'digest/sha1'

def is_signature_valid(data, signKey)
    return false unless data.include?('WSO_SIGNATURE')

    expected_signature = data.delete('WSO_SIGNATURE')
    data = data.sort_by { |key,value| key }
    encoded_data = URI.encode_www_form(data)
    signature = Digest::SHA1.hexdigest(encoded_data + signKey)

    return signature == expected_signature
end

data = {
    "AMT" =>"50.00",
    "COUNTRYCODE" =>"AU",
    "CURRENCYCODE" =>"USD",
    "EMAIL" =>"ivan.ivanovich@email.com",
    "FEEAMT" =>"2.25",
    "FIRSTNAME" =>"Ivan",
    "LASTNAME" =>"Ivanovich",
    "ORDERTIME" =>"2014-11-27T01:57:40Z",
    "PAYERID" =>"FYPB3LQJWVV72",
    "PAYERSTATUS" =>"verified",
    "PAYMENTSTATUS" =>"Completed",
    "PAYMENTTYPE" =>"instant",
    "PENDINGREASON" =>"None",
    "PROTECTIONELIGIBILITY" =>"Ineligible",
    "PROTECTIONELIGIBILITYTYPE" =>"None",
    "REASONCODE" =>"None",
    "RECEIVERBUSINESS" =>"seller@email.com",
    "RECEIVEREMAIL" =>"seller@email.com",
    "RECEIVERID" =>"7KW652V29A9XJ",
    "SALESTAX" =>"0.00",
    "SHIPAMOUNT" =>"0.00",
    "SHIPHANDLEAMOUNT" =>"0.00",
    "TAXAMT" =>"0.00",
    "TIMESTAMP" =>"2014-11-27T02:53:45Z",
    "TRANSACTIONID" =>"2D351485ST427014X",
    "TRANSACTIONTYPE" =>"webaccept",
    "VERSION" =>"95",
    "WSO_AFF_AMOUNT" =>"0.00",
    "WSO_AFF_EMAIL" =>"",
    "WSO_CUSTOMER_EMAIL" =>"ivan.ivanovich@email.com",
    "WSO_CUSTOMER_NAME" =>"Ivan Ivanovich",
    "WSO_IPN_VERSION" =>"1",
    "WSO_PRODUCT_ID" =>"wp_product_1",
    "WSO_PRODUCT_NAME" =>"ProductA",
    "WSO_SALE_ACTION" =>"SALE",
    "WSO_SALE_AMOUNT" =>"50.00",
    "WSO_SALE_ID" =>"wp_sale_1",
    "WSO_SALE_CURRENCY" =>"USD",
    "WSO_SIGNATURE" =>"78a0929ea59807ea3bcd5089b35ef5858a403f3f",
    "WSO_TXN_ID" =>"2D351485ST427014X",
    "payer_email" =>"ivan.ivanovich@email.com",
    "saleid" =>"wp_sale_1"
}

puts is_signature_valid(data, 'BIG_SECRET')
PHP:

Code:
<?php

function is_signature_valid($data, $signKey) {
    if (!array_key_exists('WSO_SIGNATURE', $data)) {
        return false;
    }

    $expected_signature = $data['WSO_SIGNATURE'];
    unset($data['WSO_SIGNATURE']);

    ksort($data);
    $encoded_data = http_build_query($data);
    $signature = sha1($encoded_data.$signKey);

    return $signature == $expected_signature;
}

$data = array(
    "AMT" =>"50.00",
    "COUNTRYCODE" =>"AU",
    "CURRENCYCODE" =>"USD",
    "EMAIL" =>"john.doe@email.com",
    "FEEAMT" =>"2.25",
    "FIRSTNAME" =>"John",
    "LASTNAME" =>"Doe",
    "ORDERTIME" =>"2014-11-27T01:57:40Z",
    "PAYERID" =>"FYPB3LQJWVV72",
    "PAYERSTATUS" =>"verified",
    "PAYMENTSTATUS" =>"Completed",
    "PAYMENTTYPE" =>"instant",
    "PENDINGREASON" =>"None",
    "PROTECTIONELIGIBILITY" =>"Ineligible",
    "PROTECTIONELIGIBILITYTYPE" =>"None",
    "REASONCODE" =>"None",
    "RECEIVERBUSINESS" =>"seller@email.com",
    "RECEIVEREMAIL" =>"seller@email.com",
    "RECEIVERID" =>"7KW652V29A9XJ",
    "SALESTAX" =>"0.00",
    "SHIPAMOUNT" =>"0.00",
    "SHIPHANDLEAMOUNT" =>"0.00",
    "TAXAMT" =>"0.00",
    "TIMESTAMP" =>"2014-11-27T02:53:45Z",
    "TRANSACTIONID" =>"2D351485ST427014X",
    "TRANSACTIONTYPE" =>"webaccept",
    "VERSION" =>"95",
    "WSO_AFF_AMOUNT" =>"0.00",
    "WSO_AFF_EMAIL" =>"",
    "WSO_CUSTOMER_EMAIL" =>"ivan.ivanovich@email.com",
    "WSO_CUSTOMER_NAME" =>"Ivan Ivanovich",
    "WSO_IPN_VERSION" =>"1",
    "WSO_PRODUCT_ID" =>"wp_product_1",
    "WSO_PRODUCT_NAME" =>"ProductA",
    "WSO_SALE_ACTION" =>"SALE",
    "WSO_SALE_AMOUNT" =>"50.00",
    "WSO_SALE_ID" =>"wp_sale_1",
    "WSO_SALE_CURRENCY" =>"USD",
    "WSO_SIGNATURE" =>"43122361d4ca2896548d0dc4f0ff02cb4a675441",
    "WSO_TXN_ID" =>"2D351485ST427014X",
    "payer_email" =>"johndoe@email.com",
    "saleid" =>"wp_sale_1"
);

echo is_signature_valid($data, 'BIG_SECRET');

***Update 27/07/2016***

Warrior Special Offers IPN Library

https://github.com/warriorforum/wso-ipn

This repository contains libraries for different web programming languages for handling WSO IPN (Instant Payment Notification) service.


WSO IPN Library for Java

This contains the class WsoIpn that accepts the http request's parameter names mapped to its value and/or the secret key and instantiates the WsoIpn. The class includes methods for signature validation and simple field getters.
This folder also includes unit tests for all the classes used in WsoIpn class.
An example on how to instantiate and use the WsoIpn class is shown in the servlet IPNListenerServlet.
The WsoIpn class can be extended to include functionalities (i.e., logging, persistence, etc.) necessary for other programs.
Note: The WsoIpn class was written to include very little to no dependency to third party libraries.


WSO IPN for Python

This contains the class WsoIpn that accepts the http request's dictionary of parameter and values. The class includes methods for signature validation and getter of necessary IPN data.
This also contains unit tests for signature validation and an example of a Listener that uses Flask.


WSO IPN for PHP

This contains the class WsoIpn that accepts the http request's dictionary of parameter and values. The class includes methods for signature validation and getter of necessary IPN data.
This also contains unit tests for signature validation and an example of a Listener.


Note:

The classes can be extended to include methods necessary for a program.
The provided code only serves as a guideline and example as to how to handle a WSO IPN. The way any of the code was structured should not be treated as standards.
The author is not liable for any errors caused by any WSO IPN library and shall not be responsible for any financial loss.
#warrior forum help #ipn #payments #processing #script #variables #warrior
Avatar of Unregistered

Trending Topics