Blog archive


Payment Pages support has been added to the First Data/Payeezy plugin.  Payment Pages live on First Data's servers and are loaded on your store via an iframe.  The upside is that the customer's credit card information never touches your site so you aren't exposed to PCI concerns.  The only downside is you have a little less control over how the form looks.  The other caveat is that the customer's card is Authorized for the order amount when they enter their info and then Captured once they submit the order.  

If you select Hosted Payment Page as your Transaction Mode, you'll need to enter 3 additional fields:  Payment Page ID, Transaction Key, and Response Key.  The image below shows where to find those values in the Payeezy portal.


You can use the Customize Form and Appearance tabs within the Payeezy Portal to tailor the form to your tastes.  The billing address from Nop will be prepopulated on the payment form.  Keep in mind that the Hosted Payment Page option is a Store Setting which means each store in Nop can use a different payment page or you can mix which stores use Payment Pages and which collect credit card information directly.  

The Hosted Payment Page feature is available in NopCommerce versions 3.8, 3.9, and 4.0.  Use the contact form if you have any additional questions.

TransArmor Tokenization is a service provided by FirstData that allows you to store a credit card on FirstData's servers.  When a transaction is processed, FirstData will return a token representing the card.  The payment plugin can save this token and submit it instead of the card info on future transactions.  This enables two key features that have been added to the plugin:  card saving and recurring transactions.

If card saving is enabled in the plugin, any time a customer makes a purchase on your site, their info will be saved in the database along with the token instead of their card number.  On subsequent purchases, the customer will see their saved cards and have the option to use one instead of entering in new info.

Recurring billing can also be enabled.  The card info will be saved and the store owner can processes recurring transactions manually.  Automatic recurring transactions will still not be possible until FirstData adds them to the API.  Both options require TransArmor Tokenization to be enabled in the FirstData merchant account admin screen as seen below:

If you are using the demo version of First Data, you can make up any 4 digit token to test out the new features.  Your production account will require a specific 4 digit code that will be provided to you by First Data.

So you're ready to distribute license keys to customers that buy your plugins, but how do the plugins know that a license key is valid?  It's actually pretty easy.  The following code handles most of the work:

public bool IsLicensed(string host)
    var keys = GetAll();

    foreach (var key in keys)
            string decryptedKey = _encryptionService.DecryptText(key.LicenseKey, Constants.LicenseKeySeed);
            string licensedHost = decryptedKey.Substring(1);
            if (decryptedKey[0] == 'U')
                if (host == licensedHost || host == "www." + licensedHost)
                    return true;
            else if (decryptedKey[0] == 'D')
                if (host.EndsWith(licensedHost))
                    return true;
        catch { }

    return false;

The GetAll() function is just getting all of the license keys that the customer has purchased and saved within your plugin (I add a small CRUD table to my config page).  You want to allow them to store multiple keys because they could have multiple stores touching this plugin.  The host is passed into this function and is usually grabbed through HttpContext.Current.Request.Url.Host.

Constants.LicenseKeySeed is the same exact string as what you put into the ProductKey on your store.

License Key Plugin 01/09/2013

The License Key plugin is something I knew I had to write once I decided to start selling my First Data payment plugin.  The FirstData plugin uses a license key to verify if the store it is running on has paid for the full use.  It does this by decrypting the license key with a secret key.  The resulting string is then a letter to indicate if it's good for a single URL or the full domain followed by the URL it's enabled for.  An example for my website would be "" which means the license is good for any subdomain of

The hassle comes in when someone decides to purchase the plugin, they expect to be able to use it right away.  They don't want to wait for me to get home from my day job so that I can create their encrypted key.  The License Key plugin solves this by subscribing to the OrderPaidEvent in NopCommerce.  Once someone completes an order that has 1 or more products that require keys, the license plugin will take their info, generate the keys, and email them immediately.  It also places them in the order notes for future reference.

I'm releasing the full source code for this plugin to the entire NopCommerce community and will explain how it works here.  You can download the plugin from it's product page here.  The plugin has 3 major areas:  The encryption key for each product, the configuration page, and generating licenses when an order is paid.

Product Key

Each plugin you will sell needs its own unique Product Key that will be used in encryption/decryption.  If you didn't use a unique key, someone could purchase Plugin A and then use the same license for Plugin B without paying you.

We handle this by subscribing to the AdminTabStripCreated event which will let you know whenever someone loads up any admin page with a tab strip. 

public void HandleEvent(AdminTabStripCreated eventMessage)
    if (eventMessage.TabStripName == "product-edit")
        ProductKeyController controller = new ProductKeyController(_productService, _genericAttributeService, _permissionService);
        string html = controller.GetProductKey();

You have to make sure you check the TabStripName because you'll get called for all tabstrips in the entire admin site.  We're calling the ProductKeyController manually which means we need to pass in its constructor arguments ourself.  It's outside of the normal MVC lifecycle so we don't get the benefit of dependency injection here.  We get the HTML and add it to the tabstrip.

public string GetProductKey()
    if (ControllerContext == null)
        ControllerContext context = new ControllerContext(System.Web.HttpContext.Current.Request.RequestContext, this);
        ControllerContext = context;

    var model = new ProductKeyModel();

    int productId = Convert.ToInt32(ControllerContext.RequestContext.RouteData.Values["id"]);
    var product = _productService.GetProductById(productId);
    model.ProductKey = product.GetAttribute(Constants.LicenseKeyAttribute); return this.RenderPartialViewToString("BitShift.Plugin.Misc.Licenses.Views.EditProductKey", model); } 

Since the ControllerContext will most likely not be loaded, we need to nudge it along.  We'll also figure out what our product id is based on the RouteData in the URL.  After that it's just a matter of looking up what our existing product key is for this product and passing it to the View.  Since we are returning the View as a string instead of ActionResult, we use the RenderPartialViewToString method.

@model BitShift.Plugin.Misc.Licenses.Models.ProductKeyModel

<table class="adminContent">
        <td class="adminTitle">
            @Html.NopLabelFor(model => model.ProductKey):
        <td class="adminData">
            @Html.EditorFor(model => model.ProductKey)
            <span id="licensekey-save" class="t-button">@T("Admin.Common.Save")</span>
            <span id="licensekey-message" style="color:#009900"></span>

<script type="text/javascript">
    $(document).ready(function () {
        $("#licensekey-save").click(function () {
            var model = {id: $("#Id").val(), productKey: $("#ProductKey").val() };
            $.post("@(Url.RouteUrl("Plugin.Misc.Licenses.SaveKey"))", model, function() {

The View is pretty simple.  It's just a single field for our ProductKey and then a jQuery function to post it back to our ProductKeyController when we want to save it. 

public void SaveKey(int id, string productKey)
    if (!_permissionService.Authorize(StandardPermissionProvider.ManageProducts))

    var product = _productService.GetProductById(id);
    _genericAttributeService.SaveAttribute(product, Constants.LicenseKeyAttribute, productKey); } 

The SaveKey function just takes in the new key and adds it to the products Attributes.


To configure the plugin, you just need to determine what Product Attributes will designate your URL mode and Domain mode.  This is how the plugin will recognize what products should get a license key when they are ordered. 

This page also has a tool to create a license key manually.  You can use this for occassions where the customer makes a typo and you need to create a new key.

Generating Licenses

The meat of the plugin happens when a customer orders an item that needs a license.  The LicenseService will loop through all of the OrderItems and determine if any use our Url or Domain attributes.  If they do, it will pull the value the customer entered and the ProductKey for that product and encrypt them together to create the license key.  If there is at least 1 license key generated, they will be added to the OrderNotes and also email directly to the customer using a MessageTemplate that was created when the LicenseKey plugin was installed.

A future blog post will detail how your other plugins should decrypt the license key and verify that is valid for where they are installed.

First Data requires 4 distinct pieces of info to accept transactions from your store: Gateway ID, Password, Key ID, and HMAC.

If you are testing out the plugin, the first step is to register for a demo account with First Data here

Once you are in, click Administration at the top right, then Terminals.  Select the Terminal with ECOMM in the name.


In the middle of this form, you will see Password.  You might have to click Generate to get one.  This is the password field for the plugin and the Gateway ID is here, too. It's important to note that the Password is separate from the username/password you used to log in.

Click on the API Access tab and generate a new HMAC Key.  The Key ID is on this page, also.  Click Update at the bottom to save the HMAC.

You'll have to do it again if you are using the Production version.  The demo info will only work in Sandbox mode and the Production info will only work if Sandbox is turned off.

If you have any other questions don't hesitate to use the contact form.