Security & Encryption
Client Authentication
The API uses OAuth2.0 as a security measure to authenticate requests.
Transport Encryption
The connection between the client applications and the API is secured with TLS/SSL.
It is recommended that the URL domain is compatible for both testing and production to ensure that during the testing stage, notification configuration meets FPX requirements.
Our APIs only support TLS 1.2
Message Signature Generation
You can also find our message signature SDK or sample apps in resources section.
Transaction will be signed using an asymmetric (private key) cryptopraphy mechanism. Messages are signed based on key fields rather than the whole message. The signature generated is then inputted into the message X-Signature
field in the message header. The key fields will be based on each of the different message formats as shown below.
PKI sign algorithm, signature method RSA-SHA 1 Public Key Signature Algorithm is used to compute a Signature value.
All message formats will require to include both the header and body fields to be built into the signature. The steps will be as below :
Step 1: Construct the source string
Based on the request message, respective fields value will be appended together following the order specified in below section.
Step 2: Sign the source string
Sign the constructed source string with participant’s private key.
Take the signed value and populate it into the
X-Signature
header field.
- Java
- PHP
public class FPXSignature {
public static String signDataUsingInternalKey(
String pvtKeyFileName,
String dataToSign,
String signatureAlg
)
throws IOException, NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, SignatureException {
PrivateKey privateKey = getPrivateKey2(pvtKeyFileName);
Signature signature = Signature.getInstance(signatureAlg, "BC");
signature.initSign(privateKey);
signature.update(dataToSign.getBytes());
byte[] signatureBytes = signature.sign();
return byteArrayToHexString(signatureBytes);
}
public static String byteArrayToHexString(byte b[]) {
StringBuffer sb = new StringBuffer(b.length * 2);
for (int i = 0; i < b.length; i++) {
sb.append(hexChar[(b[i] & 0xf0) >>> 4]);
sb.append(hexChar[b[i] & 0x0f]);
}
return sb.toString();
}
}
//gen signature
function genSignature($data,$binary_signature){
$priv_key = file_get_contents('C:\\pki-keys\\DevExchange\\EX00003846.key');
$pkeyid = openssl_get_privatekey($priv_key);
openssl_sign($data, $binary_signature, $pkeyid, OPENSSL_ALGO_SHA1);
$fpx_checkSum = strtoupper(bin2hex( $binary_signature ) );
}
//verification
function validateCertificate($path,$sign, $toSign)
{
global $ErrorCode;
$d_ate=date("Y");
//validating Last Three Certificates
$fpxcert=array($path."fpxuat_current.cer",$path."fpxuat.cer");
$certs=checkCertExpiry($fpxcert);
// echo count($certs) ;
$signdata = hextobin($sign);
if(count($certs)==1)
{
$pkeyid =openssl_pkey_get_public($certs[0]);
$ret = openssl_verify($toSign, $signdata, $pkeyid);
if($ret!=1)
{
$ErrorCode=" Your Data cannot be verified against the Signature. "." ErrorCode :[09]";
return "09";
}
}
elseif(count($certs)==2)
{
$pkeyid =openssl_pkey_get_public($certs[0]);
$ret = openssl_verify($toSign, $signdata, $pkeyid);
if($ret!=1)
{
$pkeyid =openssl_pkey_get_public($certs[1]);
$ret = openssl_verify($toSign, $signdata, $pkeyid);
if($ret!=1)
{
$ErrorCode=" Your Data cannot be verified against the Signature. "." ErrorCode :[09]";
return "09";
}
}
}
if($ret==1)
{
$ErrorCode=" Your signature has been verified successfully. "." ErrorCode :[00]";
return "00";
}
return $ErrorCode;
}
function verifySign_fpx($sign,$toSign)
{
error_reporting(0);
return validateCertificate('C:\\DevExchange\\',$sign, $toSign);
}
function checkCertExpiry($path)
{
global $ErrorCode;
$stack = array();
$t_ime= time();
$curr_date=date("Ymd",$t_ime);
for($x=0;$x<2;$x++)
{
error_reporting(0);
$key_id = file_get_contents($path[$x]);
if($key_id==null)
{
$cert_exists++;
continue;
}
$certinfo = openssl_x509_parse($key_id);
$s= $certinfo['validTo_time_t'];
$crtexpirydate=date("Ymd",$s-86400);
if($crtexpirydate > $curr_date)
{
if ($x > 0)
{
if(certRollOver($path[$x], $path[$x-1])=="true")
{ array_push($stack,$key_id);
return $stack;
}
}
array_push($stack,$key_id);
return $stack;
}
elseif($crtexpirydate == $curr_date)
{
if ($x > 0 && (file_exists($path[$x-1])!=1))
{
if(certRollOver($path[$x], $path[$x-1])=="true")
{ array_push($stack,$key_id);
return $stack;
}
}
else if(file_exists($path[$x+1])!=1)
{
array_push($stack,file_get_contents($path[$x]),$key_id);
return $stack;
}
array_push($stack,file_get_contents($path[$x+1]),$key_id);
return $stack;
}
}
if ($cert_exists == 2)
$ErrorCode="Invalid Certificates. " . " ErrorCode : [06]"; //No Certificate (or) All Certificate are Expired
else if ($stack.Count == 0 && $cert_exists == 1)
$ErrorCode="One Certificate Found and Expired " . "ErrorCode : [07]";
else if ($stack.Count == 0 && $cert_exists == 0)
$ErrorCode="Both Certificates Expired " . "ErrorCode : [08]";
return $stack;
}
Message Signature Fields
Bank Webview Services
DCL Inquiry
Request
Field | Type | Description |
---|---|---|
bankId | URI parameter | Bank code of the Participant |
CCL Inquiry
Request
Field | Type | Description |
---|---|---|
bankId | URI parameter | Bank code of the Participant |
DCL Authorize
Request
Field | Type | Description |
---|---|---|
bankId | URI parameter | Bank code of the Participant |
transactionId | URI parameter | Unique ID generated by FPX for each payment request received from Merchant |
action | URI parameter | Action code. Different actions could be initiated according to the transaction status |
CCL Authorize
Request
Field | Type | Description |
---|---|---|
bankId | URI parameter | Bank code of the Participant |
transactionId | URI parameter | Unique ID generated by FPX for each payment request received from Merchant |
action | URI parameter | Action code. Different actions could be initiated according to the transaction status |
Downtime Inquiry
Request
Field | Type | Description |
---|---|---|
bankId | URI parameter | Bank code of the Participant |
model | URI parameter | Business model |
Initiate Downtime
Request
Field | Type | Description |
---|---|---|
bankId | URI parameter | Bank code of the Participant |
model | URI parameter | Business model |
periodType | Body Parameter | Downtime period type |
startDate | Body Parameter | Downtime start date |
startTime | Body Parameter | Downtime start time |
endDate | Body Parameter | Downtime end date |
endTime | Body Parameter | Downtime end time |
Downtime Cancel
Request
Field | Type | Description |
---|---|---|
bankId | URI parameter | Bank code of the Participant |
schedulerId | URI parameter | Unique identification number assigned to the downtime request |
FPX Services
Differ from Bank Webview Services, this service requires all fields to be signed before sending to the FPX under fpx_checkSum
field.
Given below are the steps to sign a transaction request to FPX Services:
Step 1 – Construct the source string
a. The source string should be formed with all data element values.
b. The values should then be sorted by their data element name, in ascending order.
c. Each element value should be separated by a “|” (pipe) character in between them.
Below is format of source string, in ascending order:
fpx_msgToken|fpx_msgType|fpx_sellerExId|fpx_version
Below is sample of source string, constructed from the sample message
01|BE|EX00002200|7.0
Step 2 – Sign the source string
a. Sign the constructed source string with Merchant private key.
This steps applicable to all FPX Services APIs.