First Data Global Gateway e4 – PHP API Code
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.
What would the complete JSON output look like which can be used on Firefox Poster?
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″}}
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’.
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,
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?
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.
Thanks for this code. It really helps me a lot.
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!
I don’t know how to use this code can you please a full code with a form?
Firstdata is switching over to sha256, could you update your code for the new encryption?
You should just have to change this line:
$code = base64_encode(hash_hmac(‘sha1’,$code_string,$key,true));
Simply change sha1 to sha256.
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.
How can i get key,key_id,gateway_id,password
Please reply me ASAP
…
How can i do pre-auth and then capture..????
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);
?>
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);
}
I am getting internal server error after running this code
Thanks Man you saved my life.
Awesome.
Thanks,
Iam