KARPACH

WEB DEVELOPER BLOG

How to integrate First Data Gateway e4 with .NET WCF?

Recently I worked on a project that needed integration with First Data Getaway e4 payment processing. Starting from v12 First Data introduced HMAC hash security. I found .NET REST sample, but there is nothing for WCF or Web Services. This new HMAC security feature makes usage of Web Service a little challenging. I hope this guide will help somebody.

Step 1. Add service reference:

WCF: Add Service Reference

WCF: Add Service Reference Step 2

Step 2. Create demo account

Step 3. Use the following code wrapper to charge a card:

public class Merchant
{
    private readonly string _gatewayId;
    private readonly string _password;
    private readonly string _keyId;
    private readonly string _hmac;
    private readonly bool _isDemo;

    private const string ProdUrl = "https://api.globalgatewaye4.firstdata.com/transaction/v12";
    private const string TestUrl = "https://api.demo.globalgatewaye4.firstdata.com/transaction/v12";


    public Merchant(string gatewayId, string password, string hmac, string keyId, bool isDemo = true)
    {
        _gatewayId = gatewayId;
        _password = password;
        _hmac = hmac;
        _keyId = keyId;
        _isDemo = isDemo;
    }

    public MerchantResponse Charge(int orderId, string cardHoldersName, string cardNumber, decimal amount, 
        int expirationMonth, int expirationYear, int ccv, string address, string city, string state, string zip)
    {            
        var client = new ServiceSoapClient(new BasicHttpBinding(BasicHttpSecurityMode.Transport), 
            new EndpointAddress(_isDemo ? TestUrl : ProdUrl));                                           
        client.ChannelFactory.Endpoint.Behaviors.Add(new HmacHeaderBehaivour(_hmac,_keyId));            

        TransactionResult result = client.SendAndCommit(new Transaction
                                                {                                                                        
                                                    ExactID = _gatewayId,
                                                    Password = _password,
                                                    Transaction_Type = "00",                                                                        
                                                    Card_Number = cardNumber,
                                                    CardHoldersName = cardHoldersName,                                                                                                                                                
                                                    DollarAmount = amount.ToString("F"),
                                                    Expiry_Date = string.Format("{0:D2}{1}",expirationMonth,expirationYear),
                                                    Customer_Ref = orderId.ToString(),
                                                    VerificationStr1 = string.Format("{0}|{1}|{2}|{3}|US",address,zip,city,state),
                                                    VerificationStr2 = ccv.ToString()
                                                });
        var response = new MerchantResponse
                        {
                            IsTransactionApproved = result.Transaction_Approved,
                            IsError = result.Transaction_Error
                        };
        if (!result.Transaction_Approved && !result.Transaction_Error)
        {
            response.Message = string.Format("Error {0}: {1}", result.Bank_Resp_Code, result.Bank_Message);
        }
        if (!result.Transaction_Approved && result.Transaction_Error)
        {
            response.Message = string.Format("Error {0}: {1}",result.EXact_Resp_Code,result.EXact_Message);
        }
        if (result.Transaction_Approved)
        {
            response.Message = result.Authorization_Num;
        }
        return response;
    }               

    class HmacHeaderBehaivour: IEndpointBehavior
    {
        private readonly string _hmac;
        private readonly string _keyId;

        public HmacHeaderBehaivour(string hmac, string keyId)
        {
            _hmac = hmac;
            _keyId = keyId;
        }

        public void Validate(ServiceEndpoint endpoint)
        {                
        }

        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {                
        }

        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {                
        }

        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
            clientRuntime.MessageInspectors.Add(new HmacHeaderInspector(_hmac,_keyId));                                
        }
    }      
         

    class HmacHeaderInspector: IClientMessageInspector
    {
        private readonly string _hmac;
        private readonly string _keyId;

        public HmacHeaderInspector(string hmac,string keyId)
        {
            _hmac = hmac;
            _keyId = keyId;
        }

        public object BeforeSendRequest(ref Message request, IClientChannel channel)
        {                                                                
            MessageBuffer buffer = request.CreateBufferedCopy(Int32.MaxValue);
            request = buffer.CreateMessage();
            Message msg = buffer.CreateMessage();                
            ASCIIEncoding encoder = new ASCIIEncoding();
                
            var sb = new StringBuilder();
            var xmlWriter = XmlWriter.Create(sb, new XmlWriterSettings
                                                    {
                                                    OmitXmlDeclaration  = true
                                                    });
            var writer = XmlDictionaryWriter.CreateDictionaryWriter(xmlWriter);
            msg.WriteStartEnvelope(writer);
            msg.WriteStartBody(writer);
            msg.WriteBodyContents(writer);                                
            xmlWriter.WriteEndElement();
            xmlWriter.WriteEndElement();
            writer.Flush();

            string body = sb.ToString().Replace(" />","/>");

            byte[] xmlByte = encoder.GetBytes(body);
            SHA1CryptoServiceProvider sha1Crypto = new SHA1CryptoServiceProvider();
            string hash = BitConverter.ToString(sha1Crypto.ComputeHash(xmlByte)).Replace("-", "");
            string hashedContent = hash.ToLower();

            //assign values to hashing and header variables
            string time = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ");
            string hashData = "POST\ntext/xml; charset=utf-8\n" + hashedContent + "\n" + time + "\n/transaction/v12";
            //hmac sha1 hash with key + hash_data
            HMAC hmacSha1 = new HMACSHA1(Encoding.UTF8.GetBytes(_hmac)); //key
            byte[] hmacData = hmacSha1.ComputeHash(Encoding.UTF8.GetBytes(hashData)); //data
            //base64 encode on hmac_data
            string base64Hash = Convert.ToBase64String(hmacData);

            HttpRequestMessageProperty httpRequestMessage;
            object httpRequestMessageObject;

            if (request.Properties.TryGetValue(HttpRequestMessageProperty.Name, out httpRequestMessageObject))
            {
                httpRequestMessage = httpRequestMessageObject as HttpRequestMessageProperty;
                httpRequestMessage.Headers["X-GGe4-Content-SHA1"] = hashedContent;
                httpRequestMessage.Headers["X-GGe4-Date"] = time;
                httpRequestMessage.Headers["Authorization"] = "GGE4_API " + _keyId + ":" + base64Hash;
            }
            else
            {
                httpRequestMessage = new HttpRequestMessageProperty();
                httpRequestMessage.Headers["X-GGe4-Content-SHA1"] = hashedContent;
                httpRequestMessage.Headers["X-GGe4-Date"] = time;                    
                httpRequestMessage.Headers["Authorization"] = "GGE4_API " + _keyId + ":" + base64Hash;
                request.Properties.Add(HttpRequestMessageProperty.Name, httpRequestMessage);
            }                
            return null;
        }

        public void AfterReceiveReply(ref Message reply, object correlationState)
        {                
        }
    }
}

public class MerchantResponse
{
    public bool IsTransactionApproved { get; set; }
    public bool IsError { get; set; }
    public string Message { get; set; }
}

As you can see “Charge” method is simple, but HMAC requirement makes it challenging. HMAC hash is calculated based on SOAP request body, which is not accessible through ServiceSoapClient. Also, we need to modify HTTP request header. Both things can be done using IClientMessageInspector or IClientMessageFormatter. In my implementation, I used IClientMessageInspector, since it is a little easier to integrate it with ServiceSoapClient. I didn’t find any easy way to get serialized SOAP body of the request, so using Fiddler I came up with the following magic code:

var sb = new StringBuilder();
var xmlWriter = XmlWriter.Create(sb, new XmlWriterSettings
                                        {
                                        OmitXmlDeclaration  = true
                                        });
var writer = XmlDictionaryWriter.CreateDictionaryWriter(xmlWriter);
msg.WriteStartEnvelope(writer);
msg.WriteStartBody(writer);
msg.WriteBodyContents(writer);                                
xmlWriter.WriteEndElement();
xmlWriter.WriteEndElement();
writer.Flush();

string body = sb.ToString().Replace(" />","/>");

The code above gives me serialized SOAP envelope without SOAP headers string. This string is used for HMAC calculation and at the end X-GGe4-Content-SHA1, X-GGe4-Date, Authorization are added to HTTP header.

Tips: You might get 401 errors. Use Fiddler to see an actual error. Make sure that you saved generated HMAC key (generate button doesn’t save it).

Posted on January 7, 2014 by

Comments

Posted on 2/6/2014 07:53:51 AM by Scott

I was beating my head against the wall on this one, no help from FirstData at all. You sir, are the man.
It took me a while to figure it out. I am glad that it helps somebody.

Posted on 4/9/2014 07:07:03 AM by Joe

This post was a life saver. Thanks so much for sharing!

Posted on 5/20/2014 04:51:41 AM by Hayk

How we can get orderId for making charge transaction?
It should be you internal orderId. Internally you should keep track of all orders and by orderId you can pull up specific order details.

Posted on 6/16/2014 01:41:39 PM by Bryan

If you’re interested in making a some money and helping to implement this into our current site, please email me. I’ve been working on this and smashing my head also. Even tried hiring a freelancer and he’s just been more frustrating. My client is really hoping to get this done within the next week. If you’re interested please let me know ASAP.

Posted on 8/13/2014 10:07:09 PM by Joey

Good work but you should also provide your using statements.

Posted on 12/2/2014 04:58:38 AM by Nandhini

I was searching for first Data Implementation, and found this post its really helpful. But I need to implement the first Data payment processing using java framework with Soap.

I tested version 14 first Data in Soap UI , its showing date header missing !!!!!!!!!!

Can You Help with this ?

I am sorry, I am not a java expert.

Posted on 12/2/2014 05:02:00 AM by Aishwarya

This post is really helpful. Thank You.

Posted on 1/21/2015 02:30:00 AM by alpesh

I got error under ServiceSoapClient then how can i solve it
What kind of error? Can you provide a stack trace?

Posted on 1/25/2015 09:00:01 PM by munish kumar

i got error in Console Application ‘The HTTP request is unauthorized with client authentication scheme ‘Anonymous’. The authentication header received from the server was ‘’.’
You can debug HTTP requests with Fiddler. Also make sure that you use correct user name and password.

Posted on 2/9/2015 11:52:19 AM by Kondraganti

Viktor, Thanks for posting the code. Working perfectly for me for Version 14 with .Net

Posted on 2/12/2015 02:53:14 AM by Pramod M

Believe me you have saved me a ton of time and effort, thanks Viktar. Appreciate the content you’ve shared.

Can you also post a sample usage of that Merchant class and the Charge method. I am getting the error

“The HTTP request is unauthorized with client authentication scheme ‘Anonymous’.”

I guess its because of the value that I am passing into hmac and keyId paramters of the constuctor. Can you elaborate of this and it will be great if you post a sample code to use it the right way.

Once thanks for the post.

Posted on 2/12/2015 03:46:22 AM by Pramod M

Hi Viktar,

Please ignore my previous question. The error was because I was trying v14 whereas the demo settings does not allow me to use that it defaults to v12. SO I regenerated the hmac key and it seems to work fine. Your code works like charm. Thanks again.

Posted on 2/27/2015 12:21:16 AM by parshant

Can you please tell me how can i get the wsdl file. Any help will be appreciated. its urgent

Posted on 3/6/2015 05:48:30 PM by Jonathan Black

Thanks for some very good info. I’m working on an implementation and unfortunately am getting “Invalid signature received” when I look at the response in Fiddler. Any ideas? It looks like the “base64Hash” value is different from what is generated in Content Digest on First Data’s site. Is that supposed to match? TIA for any help!

Posted on 4/1/2015 11:09:08 PM by Hemant Yadav

I have integrated your code and followed all the instruction but i am getting

The remote server returned an error: (401) Unauthorized.

[MessageSecurityException: The HTTP request is unauthorized with client authentication scheme ‘Anonymous’. The authentication header received from the server was ‘’.]

If i used same user name and password with v11 everything working fine. But now i need to integrate Telecheck that is the reason i need to integrate v13 or v14 because that is supported in that version only.

Please help me how can i resolve this?

Posted on 6/9/2015 07:42:40 AM by John

Can anyone provide a sample of the values used to call the

initial Merchant method? I don’t know what to put for the

gatewayId,

hmac

keyId

values?

Posted on 8/5/2015 05:22:32 AM by abdul

How and where to call this method BeforeSendRequest() in code ?
It is automatically after you call client.SendAndCommit, but before actual http call. It behaves this way since it added to Endpoint Behaviors.

Posted on 12/2/2015 12:09:27 PM by Paddy

It worked like a charm. Initially I got error saying – ‘The HTTP request is unauthorized with client authentication scheme ‘Anonymous’. The authentication header received from the server was ‘’.’ But when I gave correct GatewayID and Password it worked. Thank you.

Posted on 12/11/2015 10:31:16 AM by Paddy

HI , The code worked in .net 4.0. But I have to implement my code in CLR which is in 2.0. I am not able to implement the same code in .net 2.0 Can you please guide me little on this? Thanks for your help.
You will need to use System.Net WebRequest.

Posted on 3/12/2016 06:01:58 AM by asmaa

how can implement search on first data on .Net

Posted on 4/6/2016 04:18:02 AM by harvinder Chand

hello sir,

Have you used recurring in transaction?

Posted on 5/22/2016 05:11:41 AM by Boichev

It works. However if i try to use Level 3 options, for example to add line items (product code, description, amount etc), the example works till version v11. Version 12 and newer - it not work. Using Fiddler, the error message returned form the server is - the hash not match to the body content. Any ideas?

Posted on 6/11/2016 11:26:50 AM by vj

Thanks it works. I am using with V19 where they added an object for Address instead of concatenated string. Eventhough their document states address properties are optional, If I don’t populate any of those fields (Ex City) I am getting The HTTP request is unauthorized with client authentication scheme ‘Anonymous’. Any idea is this something on our side or do i need to contact them? Appreciate if you can provide your thoughts to resolve this error.

Posted on 5/22/2017 07:28:30 AM by mani bhusan singha

sir pls send me userid and password demo for test
You can create test account yourself. My test account has confidential information.

Posted on 2/8/2018 07:51:19 AM by Dave

Thank you for this code. I was able to get it to work. For those getting the The HTTP request is unauthorized with client authentication scheme ‘Anonymous’. The authentication header received from the server was ‘’., make sure the API version for the service reference and endpoint is the same API version set in the API settings on the First Data website.

Posted on 4/4/2018 08:19:33 AM by Sunil Nakum

I am getting this error while trying to passing the name “äbc äbc”.

“The HTTP request is unauthorized with client authentication scheme ‘Anonymous’. The authentication header received from the server was ‘.”

Thanks in Advance.

See comment above.

Posted on 9/28/2018 05:20:28 AM by Ebiz

how to add customer with credit card details in First Data Gateway e4 ?Please explain this in Asp.net c#.

can you please email me this code