For our Documentation including JSON Request and Response Models, click here.
It is critical that the response is consumed in the intended order and format. Clients who deviate from this can experience unwanted behavior. Important: Handle exceptions with a TRY CATCH.
Try{ /v1.0.0/ConsentAnnual/ProcPayment } Catch (exception){ If exception Encountered (such as a server fault or timeout issue) then log and display exception message Return; } If (FunctionOK flag == False ){ This indicates an error which was handled on the EasyPay servers, consume the ErrCode and the ErrMsg Return; } If (TxApproved flag == False) { This indicates a declined authorization, display the TXID, RspMsg (friendly decline message), also the decline Code (TxnCode) } else { Transaction has been approved, display the TXID, and approval code (also in TXNCODE) }
For all other calls you will consume the response the same. If there is No TxApproved flag, then you can Omit the last evaluation.
All of the various API Calls and methods will return a Boolean flag named FunctionOK. If your API request completes without any exceptions, you should evaluate this flag first. If the flag does NOT show a true value this indicates an error was encountered somewhere along our processing train. It is important that the user see the returned (ErrCode) and (ErrMsg) in order to diagnose the problem.
A Decline is NOT an Error, these are expected and this just means that the card issuer for whatever reason does not want to approve the charge. If (FunctionOk = True) and (TxApproved = False) this is a decline. EasyPay returns a friendly decline message in the field named (RspMsg). The actual Decline code will be found in (TxnCode). The End user should see the friendly decline message at a bare minimum. A Complete list of decline codes and their meanings are found here: https://easypaysoftware.com/en/first-data-testing
EasyPay requires that you keep a separate Log which is specifically designed to store EasyPay Activity
Here is the recommended method when charging a card on file:
One of the most common problems we encounter is that Integrators who charge card on file neglect to protect against duplicate Charges. Imagine a button on a web page which might initiate a Charge. If this button is allowed to call our API more than Once, then the CardHolder will get charged multiple times and the merchant will call us to complain.
It is your responsibility to make sure the Button is disabled as soon as it is pressed so that the double tap does not occur.
Also, you can look at the ConsentID and the Amount and write code which will not allow this combination to get processed within the same short period of time.
If you are not passing Cardholder Data through our API then you only need to place a Session Key in the Header to connect to your account . This Session key can be generated using the Authenticate Command OR In some Cases we may simply assign you a Session Key. These Keys have expiration dates which Range from 24 hours to 2 years, and this will depend on our agreed Implementation.
If you plan to pass Cardholder data through the API you will need the following items:
For Simple Authentication we require a SESSIONKEY value in the header as follows:
SessKey: 9B9175EF556E4DDA93303132323141303035383339
Note Header Name is SessKey and Value is 9B9175EF556E4DDA93303132323141303035383339
You need to use a separate key for each device connecting to our API. This key may be generated using our Authenticate Command or we may assign a Key for you. Check with EasyPay Tech to determine this.
When HMAC is enforced, we would require the header value to have additional length as follows:
SessKey:
9B9175EF556E4DDA93303132323141303035383339_1702565789_123_1BD0C45A1DCBC7F9D0730FDD6222A45E10FCC7D9E84557499B812B138D0B7149
The format is as follows: SessionKey_Epoch_DeviceID_Hash
In order to develop the header for HMAC you will need to append values for Epoch (seconds since 1970 UTC ) as well as a user or device ID ( your choice here ) and finally the computed HMAC Hash. This Hash is created using a secret value which we will provide.
Sample
Signature = Key_Epoch_UserID_Hash
And your header becomes the following "Sesskey: " + Signature
Your Actual Header will look like this:
SessKey:
9B9175EF556E4DDA93303132323141303035383339_1702565789_123_1BD0C45A1DCBC7F9D0730FDD6222A45E10FCC7D9E84557499B812B138D0B7149
The following code will develop your signature value including your Key.
var key = "9B9175EF556E4DDA93303132323141303035383339"; var secret = "7D55DBB3D691C9E0FDF341E4AB38C3C9"; var user = 123; var hash = ""; var epoch = (int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; using (var hmac = new HMACSHA256(Encoding.ASCII.GetBytes(secret))) { string Hashable = string.Format("{0}_{1}_{2}", key, epoch, user); var bytes = hmac.ComputeHash(Encoding.ASCII.GetBytes(Hashable)); hash = BitConverter.ToString(bytes).Replace("-", ""); } var signature = string.Format("{0}_{1}_{2}_{3}", key, epoch, user, hash);
String key = "9B9175EF556E4DDA93303132323141303035383339"; String secret = "7D55DBB3D691C9E0FDF341E4AB38C3C9"; String user = "123"; String epoch = Long.toString(new Date().getTime() / 1000L); Try{ Mac sha256_HMAC = Mac.getInstance("HmacSHA256"); SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), "HmacSHA256"); sha256_HMAC.init(secret_key); String Hashable = key + "_" + epoch + "_" + user; hash = Hex.encodeHexString(sha256_HMAC.doFinal(Hashable.getBytes())); } catch (NoSuchAlgorithmException | InvalidKeyException e) { // handle signing exceptions } String signature = String.join("_", key, epoch, user, hash);
In the Pre-Request Script Tab: var key = ‘9B9175EF556E4DDA93303132323141303035383339’; var secret = '7D55DBB3D691C9E0FDF341E4AB38C3C9'; var user = '123'; var epoch = Math.floor(Date.now() / 1000); // hash time, key, user with secret var hash = CryptoJS.HmacSHA256(`${key}_${epoch}_${user}`, secret); const signature = `${key}_${epoch}_${user}_${hash}`; //console.log(signature); pm.collectionVariables.set("token", signature.toUpperCase()); In the headers tab, create a new header with the name SessKey and set the value to {{token}}
When API traffic originates from unknown networks or mobile devices, we also mandate that any credit card numbers be encrypted prior to building your JSON request. This type of data represents a relatively small number of bytes and is a good candidate for RSA encryption. We will provide an RSA 2048 Certificate and you will use the public Key to encrypt the card holder data. Only the actual Credit card Number need be encrypted. The expiration Date and CVV do not need to be encrypted.
using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; string MyCardNumber = "4111111111111111"; X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine); X509Certificate2 mycert = new X509Certificate2(); store.Open(OpenFlags.ReadOnly); bool CertFound = false; foreach (X509Certificate2 cert in store.Certificates) { //Search for cert within store either by thumbprint or subject if (cert.Subject.Contains("mobile.easypay5.com")) { mycert = cert; CertFound = true; break; } } if (!CertFound) { MessageBox.Show("Unable to find the Certificate"); return; } byte[] plainbytes = Encoding.UTF8.GetBytes(MyCardNumber); RSACryptoServiceProvider rsa = mycert.PublicKey.Key as RSACryptoServiceProvider; byte[] EncryptedBytes = rsa.Encrypt(plainbytes, true); // convert to base 64 string before sending to EasyPay EncryptedString = Convert.ToBase64String(EncryptedBytes); Whenever sending a credit card number to our API it would look like the following. "ccCardInfo": { "AccountNumber": EncryptedString, "ExpMonth": 10, "ExpYear": 2022, "CSV": "122" },
const crypto = require("crypto"); const fs = require("fs"); var MyCardNumber = "4761530001111118"; try { const publicKey = Buffer.from( fs.readFileSync("mobile.easypay5.com.pem", { encoding: "utf-8" }) ); const encryptedData = crypto.publicEncrypt( { key: publicKey, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, oaepHash: 'sha1', }, // We convert the data string to a buffer using `Buffer.from` Buffer.from(MyCardNumber) ); console.log("Length: " + encryptedData.byteLength); // this should equal 512 console.log("Data: " + encryptedData.toString("base64")); } catch (error) { console.error("Error encrypting card data:", error); }
package EPEncrypt; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.security.InvalidKeyException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.Base64; import java.util.Enumeration; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; public class EPEncryptCard { public static void main(String[] args) { CertificateDetails certDetails = getCertificateDetails( "C:\\Users\\BobSmith\\Downloads\\mobile_easypay5_com.cer", ""); String MyCardNumber = "4111111111111111"; byte[] plainbytes = MyCardNumber.getBytes(StandardCharsets.UTF_8); try { Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding"); cipher.init(Cipher.ENCRYPT_MODE, certDetails.getX509Certificate().getPublicKey()); byte[] EncryptedBytes = cipher.doFinal(plainbytes); String eBytes = new String(Base64.getEncoder().encodeToString(EncryptedBytes)); System.out.println(eBytes); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } } // void main end public static CertificateDetails getCertificateDetails(String jksPath, String jksPassword) { CertificateDetails certDetails = null; try { // boolean isAliasWithPrivateKey = false; KeyStore keyStore = KeyStore.getInstance("Windows-MY"); // Provide location of Java Keystore and password for access keyStore.load(new FileInputStream(jksPath), jksPassword.toCharArray()); // iterate over all aliases Enumeration < String > es = keyStore.aliases(); // System.out.println(keyStore.aliases().toString()); String alias = ""; while (es.hasMoreElements()) { alias = (String) es.nextElement(); if (alias.contains("mobile.easypay5.com")) { break; } } Certificate[] chain = keyStore.getCertificateChain(alias); certDetails = new CertificateDetails(); certDetails.setX509Certificate((X509Certificate) chain[0]); } catch (KeyStoreException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (CertificateException e) { e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return certDetails; } //method getCertificateDetails end } // class EPEncryptCard end package EPEncrypt; import java.security.PrivateKey; import java.security.cert.X509Certificate; public class CertificateDetails { private PrivateKey privateKey; private X509Certificate x509Certificate; public PrivateKey getPrivateKey() { return privateKey; } public void setPrivateKey(PrivateKey privateKey) { this.privateKey = privateKey; } public X509Certificate getX509Certificate() { return x509Certificate; } public void setX509Certificate(X509Certificate x509Certificate) { this.x509Certificate = x509Certificate; } } // class CertificateDetails end
Here are some pre encrypted Test Cards which can be used until such time that you have added RSA encryption to your project.
VISA 4761530001111118
QWOY6TAb5qjPFQdGrxTFThJ7EPbc295nw4JN2L/GLGjqMV1dFJQGBNL9SblCuJId15CjCjrFAVilc1zNM6l5jNnDRR9s2/+co0QLvQLTapTTgveP/5dn6PMfhxwKnSb/a0Qd9+qLb5FeHMgmMbhBMJo3PHlf/JNwDX/PWZ9I2LAEHPPf+5cgteLgoOVNw5U/mf1i5mtovNYI6Nsfsp3JGe2HOQTFCjcBx2OlzRQooYawZVByE1BV+FDvkWirU3v4DO1BxrhDODgK/TMrneg8ne75ig8LlCJhpcuO5oXp9ES6JsdQ/Q9mIqqJBA2Zo86qFLr1yCGh7taQIJ9V6j91VPybJJ9MLv5xJlUv5puxrvSfnECaR0nwLBBHrF/sHq+SmAiGGwC1qQB7dLO5PJWWd7Qy0uhxWarQSVaPKJRW7uNFKXxFdGWNBcINVR/mkNECJ4E+AdbhbbGj3Vx4ExGB2aIFpfp9izXx75T4JGvK/uBv1XABLgqzXInA1WLU50arOLnQH58FBaZiZRATukP60KPLqWSC2NPuHDQw/3eFQ/KvViLR3BSh2WLTvS7qVcZ7f43iNiHt8CMLuaaEWL8GfvU1FU2rB/DsOp9ab+N5DmTs9voRLEfKARCgUggAaC57eDzT8rY/vA7/+2iTGZqv9OuMSlopoGmZF5eiH0ysXUI=
MASTERCARD 5137221111116668
DaS9Fnf5k2KoQgs27Sgt+C+4ej/qMNgXtvwMf3ZuGhGqQVpQ9t6MMgEqcxZaW4LVakJ6rynq7YSucjOpRiwsQcDdo8pPPo11zQtzl8hCjyotWOwjqkE8fn9h/e9WcxIgaDmdmH+Kzg0avpXU/XynaYQdfrNbkKSmcNd8G4gLX51ETrkXwV5mrue5vb4V/F7uX+V7ZIZRhWpc1feC2lB4I8SvIUA/C0GeQtCp8//cXu1m//1fcwYSdNclkOvqunk9Fv/NV8vKAYEmnMfM6a35mq/sDgAXIMvLumXo94DC+Id32cN3NYfGmPCdBiCKRS0G5SD5yDBDZEMb4v4s4TkkTGT6PCnxd6U4LPfb55MGfMF49oOBgDpmxhcYlsKYDdIwjcGUefY0Wgv3QWPkeZ+59fiIPMaGEiu+UnxyeF1Ly5lhxp+6C2hRe7DR9fdAruFTIDNlrx0zrhjuzsjoi28EEEPcV1OKawPUd85c3amWkDiM0/508z54ayk16Mzn6ppaQdWY65mSnkNqz8t1TcK0HGElkYSCZdCwLQf6LDaTRZgCxYCt+KAJ2kb4ejgTybqFlPjub8xK0H+IeNqNjeUzz5I1iN4TGgAvQTXH292/Y/lO+bRTo8CBYGmi/002+WskWDBduUKl21TjNpIUpr0dhcUbp92IZicXu7MxRxRQ9iI=
DISCOVER 6011208701117775
IVbMmCpr+oj7hlHPhtMqM61eZdvXPvL/z0MJggwwrZF/oQcbaEXIoywVmOP2+OYaOfBVjd3gbhJ8RdZxsnmh1yMJebZDcJJ6e8blABh2DHEg8lHQaxNb8/H2Jhj9xVu17EaoGZUsZqvwtfrilPXkfQM0QMqZ2A6sE8Ac5piEVgwMTUIewd666uHSpzjJkft6hKaAQZfX6sQn3+CqgeB+a6GzZYsHfc5f07V6iAUQfgrSnHFQ82CIVOpk5bBmRZYp1ue3qjLmsb0/HNlPHgCArUBn1QdIWOMm8rcQMvHIO5Ao4ezldHPIq8+VVS4c7YB+igfUwuoLQx2AJbJjLiQgutw4yWTHHdh7v+QrNqys8cLp+0AbUxj5sidSQSn9Z4wA++yBIPSBOU1xmYGQTTEyepid620vGxwOOGQQgIW4Zif3cOxt+H0KxbfN6IHUSXt2c6G9Xss1gKq+JxEfxMTqSk+6WJrvpzPIu+Jw1lIWQqlFM9PCa6Cxpv0Pmkg1iqvTfoxceBCs+rdOrylv5a72Zp/zEhmDNpkaI15lUzJQX9cUtTFg5pfyOJwBKhKNz2kUAff8Q7G9+8HLl9dJFqSTvpbmYLT+3XGNGeAZuFhzLKXV0fcKiy8YNhVn6lE6SdXkbVcQCrk4641veX3yF3bVTNC2vRAtd8wFkdWqqMvbLT8=
AMEX 371030089111338
j345qduLc7NEWKF5BQU4IjHAVMASg0sOk8QhJb5cP0wewy8Sg2Tl5Bb/Hsc9onrRQI4A4zjsnxyyMQ8puFYE3svY+3BPmZGLudD8cn8KLFhbzcYsrsb01whpN+dHg5wIdEwAFc5vGHApa6XWEFUSIyAHUcQc+peX3mPr/VP79cGvEgJ1W+xrzIkYfSICx1mEyLr0goTgRWMtCC254C4Lp7fM8TYXrxDe7iLNU/MWMpTPgIn2kOKfTIcBHjzz1pR2CXyAg4tLWnwBUKnMKx4WNuhfBlbVsQpmTGRC9gEOl+lWE6lowPCw3oeJZNffF3z3MBBd/xKMOIZrjXENLLwTbK6peEkTJ9weZoAOZLfzseFJGxQTL5fVQQ2jrhHtCYfq+sHNDBe9NxIa46vx1qOw6lQ8IBDWZGe6jttLIlhdadHEYnkFim5XwM570PlSgZNNEdnAzKaP9ycbo6DGdProZQh8w98pcm49SzOXInLOUfCxR4b2h7d29rxrgn3g0N55o+EnwRajuqN63lDeKDW6LLU1Gt0QfvteOTVIU3NR8KgE3ssDkHaQIDeYN739d0P7f5/5phL86rrlGTNESk3HwGpCvp7L6CU0pco8pQDloMfKo2hPh5vTPSPSwEp8rpyJCT2ejiLIia6/NdflODJY8H3t9DxjRVIm8eX8kzr/dWM=
You may download our commercial certificate for public key encryption in the format of your choice.
Note: use RSA encryption padding OaepSHA1
Your encrypted card number will always have 512 bytes.