First Data Global Gateway e4 – PHP API Code

30. December 2014 Blog 19

Recently I was working with someone who decided to use First Data as their payment processor. I like First Data and normally highly recommend them to people looking for credit card processing. However, in the past everyone I have worked with used a different payment gateway like Authorize.net so I have never worked with First Data’s Global Gateway. This client however was looking to save some money so they asked if it would be ok to use First Data as their gateway instead of Authorize.net. According to them First Data admitted that their API wasn’t the best and hasn’t been a main focus. I told them I was willing to take on the challenge. The documentation is pretty fragmented and there is basically no example code. The little code I did find was Python, which I have started using recently so that helped, but no PHP code to be found anywhere.

The hardest part about about First Data’s gateway is their HMAC hashing algorithm. They explain exactly how to construct it, however they aren’t clear on what the options are. Here is how you construct the hash:

Request Method + \n
+ Content-type + \n
+ Content Digest (SHA-1) + \n
+ Sending Time + \n
+ Request URL

(The sending time is expressed in ISO 8601 format, e.g: 2012-09-21T00:50:09Z)

For example, one part of the hash is the Content-type you are sending. You can choose between SOAP or JSON, so at first I used ‘JSON’ in the string, that didn’t work so I found something online that showed someone using “application/json; charset=utf-8” so I tried that. Once again no luck. Finally, I tried “application/json” and that worked. So anyway here is a simple class you can use to charge via the First Data Global Gateway.

class Payment {
    public $cc_name;
    public $cc_number;
    public $cc_cvv;
    public $cc_month;
    public $cc_year;
    public $email;
    public $transaction_id;

    public function charge($billing) {
        //TESTING ACCOUNT
        //get from account API settings these are not valid keys, key_id, gateway_id or password
        $key = 'xVY5oeqpcEhkXR_45ra55ycpe3k8Dxtt5o';
        $key_id = 123456;
        $gateway_id = 'AB1234-56';
        $endpoint = 'https://api.demo.globalgatewaye4.firstdata.com/transaction/v14';
        //$endpoint = 'https://api.globalgatewaye4.firstdata.com/transaction/v14';
        $password = 'j7oyy12345678150s2l4tpn54p971234';

        $myorder = array(
            'gateway_id' => $gateway_id,
            'password' => $password,
            'transaction_type' => '00',
            'amount' => $this->amount,
            'cardholder_name' => $this->cc_name,
            'cc_number' => $this->cc_number,
            'cc_expiry' => str_pad(($this->cc_month + 1),2,'0',STR_PAD_LEFT) . (date('y') + intval($this->cc_year)), //format 0414
            'cvd_code' => $this->cc_cvv,
            'client_ip' => $_SERVER['REMOTE_ADDR'],
            'client_email' => $this->email,
            'zip_code' => $billing->zip,
            'address' => array(
                'address1' => $billing->address,
                'address2' => $billing->address2,
                'city' => $billing->city,
                'state' => $billing->state,
                'zip' => $billing->zip
            ),
        );
        
        $data_string = json_encode($myorder);
        
        $ch = curl_init ();
        curl_setopt ($ch, CURLOPT_URL,$endpoint);
        curl_setopt ($ch, CURLOPT_CUSTOMREQUEST, "POST");
        curl_setopt ($ch, CURLOPT_POSTFIELDS, $data_string);
        curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0);
        curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt ($ch, CURLOPT_VERBOSE, 1);
        
        $content_digest = sha1($data_string);
        
        $current_time = gmdate('Y-m-dTH:i:s') . 'Z';
        $current_time = str_replace('GMT', 'T', $current_time);
        
        $code_string = "POST\napplication/json\n{$content_digest}\n{$current_time}\n/transaction/v14";
        $code = base64_encode(hash_hmac('sha1',$code_string,$key,true));
        
        $header_array = array(
            'Content-Type: application/json',
            'Content-Length: ' . strlen($data_string),
            'X-GGe4-Content-SHA1: '. $content_digest,
	    'X-GGe4-Date: ' . $current_time,
	    'Authorization: GGE4_API ' . $key_id . ':' . $code,
        );
        
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header_array);
        $result = curl_exec ($ch);
        curl_close($ch);
        
        $result = json_decode($result);
        if ($result->transaction_approved == '0') {
            return array('success'=>false,'error'=>$result->bank_message);
	} else {
            $this->transaction_id = $result->transaction_tag;
            return array('success'=>true);
	}
    }
}

Then it can be used like this.

$payment = new Payment();
$payment->cc_name = 'Test Tester';
$payment->cc_number = '4111111111111111';
$payment->cc_cvv = '123';
$payment->cc_month = 5;
$payment->cc_year = 2015;
$payment->email = 'test@test.com';
$result = $payment->charge($billing);

The $billing value sent in is a simple classes with properties for address, address2, city, state, and zip. This has worked great for me so far. If you have any questions write a comment and ask and I will help out if possible.


19 thoughts on “First Data Global Gateway e4 – PHP API Code”

  • 1
    Ken on February 25, 2015 Reply

    What would the complete JSON output look like which can be used on Firefox Poster?

    • 2
      pitchinnate on March 24, 2015 Reply

      An example JSON would look like this:

      {“gateway_id”:”AB1234-56″,”password”:”xxxxxxxxxxxxxxxxxxxx”,”transaction_type”:”00″,”amount”:1.23,”cardholder_name”:”Test Testing”,”cc_number”:”4111111111111111″,”cc_expiry”:”0415″,”cvd_code”:”123″,”client_ip”:”111.111.111.111″,”client_email”:”test@testing.com”,”zip_code”:”12345″,”address”:{“address1″:”123 test st”,”address2″:””,”city”:”testville”,”state”:”oh”,”zip”:”12345″}}

      • 3
        ken on March 24, 2015 Reply

        I followed your code and generated the headers then used Firefox poster but keep getting error as: Body Digest doesn’t match header ‘X-GGE4-CONTENT-SHA1’.

        • 4
          pitchinnate on March 25, 2015 Reply

          Make sure the time on the computer/server you are generating the code on is correct as they only allow for a small tolerance on that. Also make sure you are sending all three of these headers:

          ‘X-GGe4-Content-SHA1: ‘. $content_digest,
          ‘X-GGe4-Date: ‘ . $current_time,
          ‘Authorization: GGE4_API ‘ . $key_id . ‘:’ . $code,

          • 5
            ken on March 25, 2015

            I also used the terminal HMAC calculator and set the headers of Firefox/Poster accordingly and this time I got error: “Invalid signature received….”. I called first data support and they said it could be due to missing space or additional space here or there on the headers. What is the exact look of the headers of your example. How do they look like when you place them on Firefox/Poster?

          • 6
            pitchinnate on March 30, 2015

            I don’t know what Firefox/Poster is. I do all my work server side with PHP and Curl. So I’m not sure what the issue could be sorry.

  • 7
    Suchi on March 31, 2015 Reply

    Thanks for this code. It really helps me a lot.

    • 8
      special project team on July 8, 2015 Reply

      Im always getting invalid signature.

      Array
      (
      [server_response] => Invalid signature received ‘P2aleH############’.
      [request_header] => POST /transaction/v14 HTTP/1.1
      Host: api.demo.globalgatewaye4.firstdata.com
      Content-Type: application/json
      Accept: application/json
      Content-Length: 251
      X-GGe4-Content-SHA1: 31c9c2a27c4151f6ad5632d46a5afdada0badee4
      X-GGe4-Date: 2015-07-08T07:45:41Z
      Authorization: GGE4_API 261536:P2aleHwzqdaqqRY5EeIEExsBo6s=

      [signature] => P2aleHwzqdaqqRY5EeIEExsBo6s=
      )

      Please help!

  • 9
    Aditya on May 7, 2015 Reply

    I don’t know how to use this code can you please a full code with a form?

  • 10
    Nostrus on June 2, 2015 Reply

    Firstdata is switching over to sha256, could you update your code for the new encryption?

    • 11
      pitchinnate on June 30, 2015 Reply

      You should just have to change this line:
      $code = base64_encode(hash_hmac(‘sha1’,$code_string,$key,true));
      Simply change sha1 to sha256.

  • 12
    George A on July 21, 2015 Reply

    Thanks for posting the code. I am testing it an I get a NULL result after decoding the json. Do you have an idea what could be the issue?

    Thanks for your time.

  • 13
    pankaj on July 29, 2015 Reply

    How can i get key,key_id,gateway_id,password

  • 14
    pankaj on July 29, 2015 Reply

    Please reply me ASAP

  • 15
    pankaj on July 31, 2015 Reply

    How can i do pre-auth and then capture..????

  • 16
    Pankaj on August 19, 2015 Reply

    We are use this code. And i am getting Invalid signature received.
    $gateway_id,
    ‘password’ => $password,
    ‘transaction_type’ => ’00’,
    ‘amount’ => $this->amount,
    ‘cardholder_name’ => $this->cc_name,
    ‘cc_number’ => $this->cc_number,
    ‘cc_expiry’ => str_pad(($this->cc_month + 1),2,’0′,STR_PAD_LEFT) . (date(‘y’) + intval($this->cc_year)), //format 0414
    ‘cvd_code’ => $this->cc_cvv,
    ‘client_ip’ => $_SERVER[‘REMOTE_ADDR’],
    ‘client_email’ => $this->email,
    ‘zip_code’ => ‘123456’,
    ‘address’ => array(
    ‘address1’ => ‘Test Address’,
    ‘address2’ => ‘Test Address123’,
    ‘city’ => ‘Test City’,
    ‘state’ => ‘Test State’,
    ‘zip’ => ‘123456’
    ),
    );

    $data_string = json_encode($myorder);

    $ch = curl_init ();
    curl_setopt ($ch, CURLOPT_URL,$endpoint);
    curl_setopt ($ch, CURLOPT_CUSTOMREQUEST, “POST”);
    curl_setopt ($ch, CURLOPT_POSTFIELDS, $data_string);
    curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0);
    curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt ($ch, CURLOPT_VERBOSE, 1);

    $content_digest = sha1($data_string);

    $current_time = gmdate(‘Y-m-dTH:i:s’) . ‘Z’;
    $current_time = str_replace(‘GMT’, ‘T’, $current_time);

    $code_string = “POST\napplication/json\n{$content_digest}\n{$current_time}\n/transaction/v12”;
    $code = base64_encode(hash_hmac(‘sha1’,$code_string,$key,true));

    $header_array = array(
    ‘Content-Type: application/json’,
    ‘Content-Length: ‘ . strlen($data_string),
    ‘X-GGe4-Content-SHA1: ‘. $content_digest,
    ‘X-GGe4-Date: ‘ . $current_time,
    ‘Authorization: GGE4_API ‘ . $key_id . ‘:’ . $code,
    );

    curl_setopt($ch, CURLOPT_HTTPHEADER, $header_array);
    $result = curl_exec ($ch);
    curl_close($ch);

    print_r($result);die;

    $result = json_decode($result);

    if ($result->transaction_approved == ‘0’) {
    return array(‘success’=>false,’error’=>$result->bank_message);
    } else {
    $this->transaction_id = $result->transaction_tag;
    return array(‘success’=>true);
    }
    }
    }

    $payment = new Payment();
    $payment->cc_name = ‘Test Tester’;
    $payment->cc_number = ‘4111111111111111’;
    $payment->cc_cvv = ‘123’;
    $payment->cc_month = 5;
    $payment->cc_year = 2017;
    $payment->email = ‘test@test.com’;
    $payment->amount = ‘10.00’;
    $result = $payment->charge();
    print_r($result);

    ?>

  • 17
    shimion on August 30, 2015 Reply

    I am slo getting error “Invalid signature received”….

    Please help:

    “AH6730-03”, “password” => ‘v010l6676c3140p965ljtrdoos0356p3’, “transaction_type” => “00”, “amount” => “11”, “cardholder_name” => “asd”, “cc_number” => “4111111111111111”, “cc_expiry” => “0319”, “cc_cvv ” => “123”);
    $json_request = json_encode($nvp);

    // HMAC Hash
    // @see https://firstdata.zendesk.com/entries/22069302-api-security-hmac-hash.
    $content_type = ‘application/json; charset=UTF-8’;
    $hmackey = ‘nVLR9ykiqBovnGc5h0bRqIqDYiTTzkgB’;
    $key_id = ‘214427’;
    $hashtime = gmdate(“c”);
    $content_digest = sha1($json_request);
    $api_uri = ‘/transaction/v19’;
    $hashstr = “POSTn” . $content_type . “n” . $content_digest . “n” . $hashtime . “n” . $api_uri;
    $authstr = base64_encode(hash_hmac(“sha256”, $hashstr, $hmackey, TRUE));

    $curl_headers = array(‘Content-Type: ‘ . $content_type, ‘Accept: application/json’);
    $curl_headers[] = ‘Authorization: GGE4_API ‘ . $key_id . ‘:’ . $authstr;
    $curl_headers[] = ‘X-GGe4-Date: ‘ . $hashtime;
    $curl_headers[] = ‘X-GGe4-Content-SHA1: ‘ . $content_digest;

    // Setup the cURL request.
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_VERBOSE, 0);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $json_request);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
    curl_setopt($ch, CURLOPT_NOPROGRESS, 1);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $curl_headers);
    $result = curl_exec($ch);

    // Getting jSON result string
    $data_string = json_decode($result);
    print($data_string);

    if ($data_string) {
    if ($data_string->bank_resp_code == ‘100’) {
    print(‘Approved!’);
    } else {
    print($data_string->bank_message);
    }
    } else {
    print($result);
    }

  • 18
    jdb on October 13, 2015 Reply

    I am getting internal server error after running this code

  • 19
    Iam on February 17, 2016 Reply

    Thanks Man you saved my life.

    Awesome.

    Thanks,
    Iam

Leave a Reply to Aditya Cancel reply

Your email address will not be published. Required fields are marked *