Click here to Skip to main content
14,975,416 members
Articles / Web Development / ASP.NET / ASP.NET Core
Article
Posted 3 Feb 2021

Stats

4.2K views
17 bookmarked

Capturing Payments Using Mastercard MIGS Service and ASP.NET Core

Rate me:
Please Sign up or sign in to vote.
5.00/5 (5 votes)
3 Feb 2021CPOL11 min read
Mastercard MIGS payment service and how to capture payments from clients
In this article, we will explore Mastercard MIGS payment service and learn how to capture payments from your clients through the provided API using C# and ASP.NET Core.

Overview

Image 1Good day everyone! Today, we will explore Mastercard MIGS payment service and learn how to capture payments from your clients through the provided API using C# and ASP.NET Core.

It is worth mentioning that the payment component we are going to create can be used from any project (not just ASP.NET core projects.) Moreover, it is very easy to port our test code to MVC, WebForms or even console/desktop apps.

Full Source Code

Full code and its testing web application are available at the following link. The code is fully documented and easy to follow:

The package is also available on Nuget at:

Introduction

Mastercard provides a service called MIGS (Mastercard Internet Gateway Service) that merchants can use to capture and collect funds from their clients as well as to issue refunds and monitor reports. This service exposes its functionality through an API called VPC (Virtual Payment Client) that can be easily accessed using some sort of credentials that merchants receive from their acquiring bank.

In other words, the VPC (Virtual Payment Client) acts as an interface that provides a secure method of communication between your online store and the Mastercard payment server, which facilitates the processing of payments.

Image 2

For this to work, as a merchant, you must register for the e-payment service through your bank which will give you two sets of credentials that can be used to communicate with VPC, the testing and the production credentials.

Secure Credentials

Each secure credential (testing/production) that you will receive form the bank consists of five pieces:

  • Merchant ID: which you can think of as the username.
  • Access Code: which you can think of as the password.
  • Secure Hash Secret: which can be used for integrity validation (which we will cover later.) This code must be kept in a safe place.
  • The AMA user: will be covered later in the transaction queries.
  • The AMA password: will be covered later in the transaction queries.

Integration Models

To collect and capture your funds from clients, you need to use one of two models:

  • Server-Hosted Model
  • Merchant-Hosted Model

Server-Hosted Model / 3-Party

Server-Hosted Model, also called bank-hosted and 3-party, is where you do not handle client card information directly. Instead, you send the user to a secure page hosted by Mastercard where user can enter their card information and you wait for the page to return to you with the response.

Image 3

Pros and cons of this model:

  • Pros:
    • You are totally free of securing user card information.
  • Cons:
    • User must be present.
    • Cannot be used in offline or mail/telephone orders.
    • You must check for pending transactions if the page has not returned to you (e.g., user has closed the browser or an internet issue.)

Merchant-Hosted Model / 2-party

Merchant-Hosted Model, also called 2-party, is where you handle client card information directly. You ask the user for card information or retrieve it from a database and send all the required information to VPC using a web request, where the VPC replies instantly with relevant information.

Image 4

Pros and cons of the 2-party model:

  • Pros:
    • No waits. You get the response instantly.
    • User may not be present.
    • Can be used with mail/telephone orders.
  • Cons:
    • You must handle the security of credit card page and data being stored in the database (for example.)

Endpoints

To start utilizing a model, you need to use its relevant endpoint which is available in the following table:

Model Endpoint
Server-Hosted vpcpay
Merchant-Hosted vpcdps

Payment Transactions

Now let us get to work. To issue a payment request to the server, you should include the following parameters:

Group Parameter Description
Common vpc_Version API version. Currently covered version is ‘1’.
vpc_Command The command name, which will be ‘pay’ for payment requests.
Authentication vpc_Merchant Your merchant ID.
vpc_AccessCode Your access code.
Order Details vpc_MerchTxnRef Your unique transaction reference.
vpc_OrderInfo Your order ID.
vpc_Amount Amount expressed in the smallest currency unit expressed as integer. For example, if the transaction amount is $49.95 then the amount value should be 4995.

Transaction Reference vs. Order Info

Now you might ask what is the difference between transaction reference and order info? And what makes transaction reference strictly recommended to be unique?

The answer is that ever asked yourself what will happen if the user in a server-hosted transaction closes the Mastercard page after a successful payment without returning to your site? The answer is without the unique transaction reference you will lose access to user’s payment transaction.

Using unique transaction references allows you to identify each payment request and to link them to user/order. And if you did not get a response from the payment request, you can use the unique reference to query about payment status later using the QueryDR command (will be covered later.)

You can also pass the order ID in the vpc_OrderInfo field keeping in mind that each order may have multiple payment requests, however, each payment request can only be linked to a single order.

Server-Hosted Payment Transactions

If you are going to use the server-hosted integration model, you will have to point your call to the correct API endpoint, which is vpcpay for server-hosted model, and provide two more parameters besides the parameters mentioned above. One of those two, as you might guess, is the return URL (i.e., callback URL.)

Parameter Description
vpc_ReturnURL The URL that Mastercard gateway will navigate to when the transaction completes. In this URL, you can define a handler to process the payment transaction results. You may define a Thank You page, a receipt page, or something like this. Keep in mind that not all transactions are successful. This URL must be:
  1. Absolute
  2. SSL-compliant.
vpc_Locale The ISO two-letter language code for the Mastercard server pages. Examples are: en (English), ar (Arabic), and es (Spanish.)

Now the question is: How do we send those parameters to the VPC API? Will we include them in body? Will we encode them as JSON? The answer is no! We simple include them as query string. As we are in server-hosted model, we will prepare our URL that has those parameters in the query string and then we will just navigate to this URL and wait for it to navigate back to our return URL (vpc_ReturnURL.)

Image 5

Worth mentioning that you can define your custom parameters as long as they do not start with ‘vpc_’.

Merchant-Hosted Payment Transactions

On the other hand, the merchant-hosted transactions use the endpoint vpcdps. It uses extra 3 parameters that you can easily guess:

Parameter Description
vpc_Card Custom card number
vpc_CardExp Card expiry date expressed in yyMM format. For example, Jan 2021 is expressed as 2101.
vpc_CardSecurityCode The card security code

Now let us put the pieces together.

Image 6

Response Parameters

If we are using the server-hosted model, we may receive the response as query parameters of our callback URL. On the other hand, if we are using the merchant-hosted model, we may receive the response as query string in the body of the web response. Those parameters include:

Parameter Description
vpc_MerchTxnRef Our unique transaction reference
vpc_OrderInfo Our order number
vpc_TxnResponseCode Transaction response code. A value of ‘0’ indicates a successful transaction
vpc_Message Indicates any error messages the transaction may have encountered
vpc_ReceiptNo Transaction unique identifier. Also called the Reference Retrieval Number (RRN)
vpc_AuthorizeId An identifying code issued by the bank to approve or deny the transaction
vpc_BatchNo A date supplied by the bank to indicate when this transaction will be settled
vpc_CardType Card type. For example, ‘MC’ for Mastercard cards

Request and Response Samples

Here is an example of a request URL:

https://migs.mastercard.com.au/vpcpay?vpc_AccessCode=77426638&vpc_Amount=10025&
vpc_Command=pay&vpc_Locale=en&vpc_MerchTxnRef=TX-1&vpc_Merchant=TESTEGPTEST&
vpc_OrderInfo=100&vpc_ReturnURL=https://localhost:44376/Home/PaymentCallback&vpc_Version=1

Here in this link, you can see that the endpoint is ‘vpcpay’ which indicates a server-hosted model (i.e., we will navigate the user to this link. We can also see that the amount is 10025 which means $100.25 (or whatever currency we are operating.) We can also see that we have specified our return URL as ‘https://localhost:44376/Home/PaymentCallback'. Which the user will be automatically navigated to when he completes the transaction.

When the user completes the transaction, he will be navigated to:

https://localhost:44376/Home/PaymentCallback&vpc_Amount=121300&vpc_AuthorizeId=586587&
vpc_BatchNo=20210129&vpc_CSCResultCode=M&vpc_Card=MC&vpc_Command=pay&
vpc_MerchTxnRef=TX-1&vpc_Merchant=TESTEGPTEST&vpc_Message=Approved&
vpc_OrderInfo=O-1&vpc_ReceiptNo=103006586587&vpc_TxnResponseCode=0&vpc_Version=1

No need for more explanation. The parameters are easy to understand and follow.

Integrity Checking

Ever wondered, what if a user simulates the payment process and just called the above URL of your site with any fake values?! Will you still count it as a valid transaction? How do you differentiate between the true and fake responses? The answer is the integrity checking.

The last third in the secure credentials that we did not cover yet is the secure hash secret. This code is used to prevent the cardholder from modifying a transaction request and response when passing it though cardholder’s browser. This is what we call integrity checking.

Integrity checking works by using the hash secret code as a key to hash all our parameters and to send the generated hash along with our call to the server which in turn validates the hash and proceeds if valid. On the contrary, the server hashes all response parameters using the same hash secret code and returns the response along with the generated hash to our application, which we can validate by regenerating the hash and comparing it to the returned value.

Three things should be noted in this process:

  1. VPC requires the hashed parameters to be ordered by ASCII ordinal values before hashing, e.g., the capital ‘E’ is before the small ‘a’.
  2. VPC requires the usage of either HMAC SHA-256 or MD5 hashing algorithm.
  3. The hash secret must be kept safe, it should not be exposed under any circumstances.

So, for this to work, we have two extra parameters that will be included in the request:

Parameter Description
vpc_SecureHash The generated hash
vpc_SecureHashType The hashing mechanism, which is ‘SHA256’ or ‘MD5’
Beware not to include your original secret hash.

Let us see this in action.

SHA-256 Hashing

For SHA-256 hashing, you can use the following procedure for requests:

Image 7

On the other hand, here is the response integrity checking mechanism for SHA-256.

Image 8

MD5 Hashing

For MD5 request hashes, use the following procedure:

Image 9

For response checking, use the following procedure:

Image 10

Transaction Queries

Previously, we have raised an issue about what will happen in server-hosted transactions if the user has closed the browser (for example) without returning to your site? The answer is in your unique merchant transaction number. You can use this number in the query API to query for transactions that has this number. That is why this number is strictly recommended to be unique.

The query command is based on the merchant-hosted model. And that means there will be no navigations, you will create the request and read its response instantly. It means also that it will use the vpcdps endpoint.

One critical thing to mention is that the transaction query command is part of the Advanced Merchant Administration (AMA) commands. Those advanced commands use an extra security credentials called the AMA username and password. Those credentials must be included as query parameters in the request.

For the transaction query request, we are going to use the following parameters:

Group Parameter Description
Common vpc_Version API version. Currently covered version is ‘1
vpc_Command The command name, which will be ‘queryDR
Authentication vpc_Merchant Your merchant ID
vpc_AccessCode Your access code
vpc_User AMA username
vpc_Password AMA password
Request Details vpc_MerchTxnRef Your unique transaction reference

For the response, we are going to have the following parameters:

Parameter Description
vpc_DRExists Returns ‘Y’ if the requested transaction reference has been found
vpc_FoundMultipleDRs Returns ‘Y’ if there’s multiple transactions with the requested merchant transaction reference
vpc_Amount If one transaction found, we are going to have its amount here.
vpc_BatchNo If one transaction found, we are going to have its batch number here.
vpc_TransactionNo If one transaction found, we are going to have its unique transaction number here.

Test Environment

Credentials

Here is a set of test credentials that can be used in the payment process. Normally, you will receive your test credentials from your acquiring bank. You can also search the internet and get few test credentials like those.

Item Value
Merchant ID TESTEGPTEST
Access Code 77426638
Secure Hash 7E5C2F4D270600C61F5386167ECB8DA6

Test Cards

Here are a set of test cards that you can use:

Item Card #1 Card #2
Type Mastercard Visa
Number 5123456789012346 4987654321098769
Expiry Date 05/21 05/21
Security Code 100 100

Code Glimpse

In this section, we will go through the code very quickly.

Let us start with query parameters. To get our code generating parameters dynamically and to differentiate between parameter fields and other fields, we created an attribute that will be used to decorate only parameter fields.

C#
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field,
                AllowMultiple = false, Inherited = true)]
public class QueryParamAttribute : Attribute
{
  /// <summary>
  /// Target parameter name.
  /// </summary>
  public string Name { get; set; }

  /// <summary>
  /// Is parameter required. Indicates whether to include an empty string
  /// if parameter value is null/empty.  Default is True.
  /// </summary>
  public bool IsRequired { get; set; }
}

Next, we started defining our class hierarchy and parameter properties:

C#
public abstract class VpcCommand
{
  /// <summary>
  /// Command name.
  /// </summary>
  [QueryParam(Name = "vpc_Command", IsRequired = true)]
  public abstract string Command { get; }

We used reflection to get the parameter query properties and their corresponding values:

C#
private static IEnumerable<MemberInfo> GetObjectQueryMembers(object targetObject)
{
  IEnumerable<MemberInfo> queryMembers;

  // Loads for instance properties
  queryMembers = targetObject.GetType().GetProperties();
  // Loads for instance fields
  queryMembers = queryMembers.Concat(targetObject.GetType().GetFields());

  // Checks QueryParamAttribute existence
  queryMembers = queryMembers.Where(a => a.GetCustomAttributes<QueryParamAttribute>().Any());
  return queryMembers;
}

We used a simple code to generate and concatenate query strings:

C#
public static string CreateQueryString(IEnumerable<QueryParameter> parameters)
{
  string queryStr = string.Empty;
  foreach (var param in parameters)
  {
    queryStr += string.Format("{0}={1}&", param.Name, param.Value);
  }

  queryStr = queryStr.TrimEnd('&');
  return queryStr;
}

And here is our secure hash generating code:

C#
public virtual string SHA256Hash(string hashSecret, IEnumerable<QueryParameter> queryParams)
{
  queryParams = queryParams.OrderBy(a => a.Name, StringComparer.Ordinal);
  string queryStr = QueryManager.CreateQueryString(queryParams);
  return Sha256(queryStr, hashSecret);
}

public virtual string MD5Hash(string hashSecret, IEnumerable<QueryParameter> queryParams)
{
  queryParams = queryParams.OrderBy(a => a.Name, StringComparer.Ordinal);

  string str = hashSecret + string.Join("", queryParams.Select(a => a.Value));

  return MD5(str);
}

And the code to execute a merchant-hosted command is fairly straightforward:

C#
public virtual string ExecuteCommandRaw(VpcCommand cmd)
{
  string reqUrl = ComputeCommand(cmd);

  WebRequest req = HttpWebRequest.Create(reqUrl);

  req.Method = "POST";

  using (var stm = req.GetResponse().GetResponseStream())
  using (var stmReader = new StreamReader(stm))
  {
    return stmReader.ReadToEnd();
  }

History

  • 3rd February, 2021: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Mohammad Elsheimy
Software Developer (Senior)
Egypt Egypt
Mohammad Elsheimy is a developer, trainer, and technical writer. He is a MCP, MCTS (WinForms), MCPD (Windows Apps), MCSA (SQL Server), MCSE (Data Analytics), and MCT expertized in .NET Framework technologies, data management and analytics. He is also a Project Management Professional (PMP) and a Quranic Readings Institute (Al-Azhar) graduate specialized in Quranic readings, Islamic legislation, and the Arabic language.

Comments and Discussions

 
-- There are no messages in this forum --