ECR SDKs - ecr-git-demo.payable.lk
PAYable ECR SDKs provide a bridge between PAYable terminals and any kind of POS platforms without any language barriers to complete the PAYment transaction requests.
Make sure the ECR payment service is running on the terminal as below in the notification bar.
The connection between the terminal and host system will be established using WebSocket which is running inside the ECR application.
The server is implemented based on these WebSocket protocol versions
Refer to the Mozilla WebSocket APIs to write your WebSocket client or use any libraries available based on the above protocol versions.
The below explanation can guide you to establish a connection between the host system and the ECR terminal using an internal (LAN - Local Area Network) network.
Initiate a WebSocket connection to the terminal's LAN IP address if both are in the same network, let's assume the example IP address of the terminal as 192.168.8.101
then the address would be starting with ws://
and the ECR port number is 45454.
- Token: 4DqxynHGtHNckmCrRzvVxkwuSfr8faRmPrLIX0hmkqw=
- POS host name: COMPANY-1 - This is the name of your current POS system.
Example:
ws://192.168.8.101:45454?token=4DqxynHGtHNckmCrRzvVxkwuSfr8faRmPrLIX0hmkqw=&pos=COMPANY-1
Once the connection is established, the host system will be notified from the implemented WebSocket client with a success message from the terminal as below.
{
"origin":"PP35271812000161",
"request":{
"origin":"COMPANY-1"
},
"status":"STATUS_TERMINAL_AUTHORIZED"
}
In the below situations handshake will be failed with the 404 error code:
- Token is invalid or not presented
- POS name is empty or not provided
- POS name is duplicate and already in use
Error:
Error during WebSocket handshake: Unexpected response code: 404
1.2.1 Card payment
Adjust the below JSON request as per the payment details, send as plain text to the connected terminal and wait for the response.
Example request:
{
"amount": 20.00,
"endpoint": "PAYMENT",
"method": "CARD",
"order_tracking": "example_sale_from_test", // any tracking reference data - optional
"receipt_email": "[email protected]", // customer email - optional
"receipt_sms": "0777777777", // customer phone number - optional
"id": 14526 // any numeric reference id - optional
}
When the payment gets succeeded or failed, the ECR terminal will send the response back to the requested host system with the request, so the response will be received to the host system if it's listening to the response message.
Example successful response:
{
"approval_code":"408809",
"card_name":"MOHAMMED/ASLAM ",
"card_no":"XXXX-XXXX-XXXX-5050",
"card_type":"MASTER",
"mid":"242332553252353",
"origin":"PP35271812000161",
"request":{
"amount":20.0,
"endpoint":"PAYMENT",
"id":1,
"method":"CARD",
"order_tracking":"example_sale_from_test",
"origin":"COMPANY-1",
"receipt_email":"[email protected]",
"receipt_sms":"0777777777"
},
"server_time":"2020-12-12 01:30:55 AM",
"status":"STATUS_SUCCESS",
"tid":"24343227",
"transaction_type":"EMV",
"txid":44910
}
Example failure response:
{
"error":"Received duplicate transaction request.",
"origin":"PP35271812000161",
"request":{
"amount":20.0,
"endpoint":"PAYMENT",
"id":1,
"method":"CARD",
"order_tracking":"example_sale_from_test",
"origin":"COMPANY-1",
"receipt_email":"[email protected]",
"receipt_sms":"0777777777"
},
"status":"STATUS_FAILED"
}
1.2.2 Wallet payment
Example request:
{
"amount": 20.00,
"endpoint": "PAYMENT",
"method": "WALLET",
"id":1, // any numeric reference id - optional
"mobile_no": "0777777777", // customer mobile number - optional
"bill_no": "unique_no", // unique reference no - optional
"print_receipt": "YES" // YES | NO - optional
}
Example successful response:
{
"rrn":"408809",
"tid":"24343227",
"mid":"242332553252353",
"origin":"PP35271812000161",
"request":{
"amount":20.0,
"bill_no":"unique_no",
"endpoint":"PAYMENT",
"id":1,
"method":"WALLET",
"mobile_no":"0777777777",
"origin":"COMPANY-1",
"print_receipt":"YES"
},
"status":"STATUS_SUCCESS"
}
Example failure response:
{
"error":"Duplicate Bill number",
"origin":"PP35271812000161",
"request":{
"amount":20.0,
"bill_no":"unique_no",
"endpoint":"PAYMENT",
"id":1,
"method":"WALLET",
"mobile_no":"0777777777",
"origin":"COMPANY-1",
"print_receipt":"YES"
},
"status":"STATUS_FAILED"
}
The discount is applied based on the card bin numbers that you set to the terminal. If the payee's card matched with the given bin ranges the amount will be applied as per the discount amount otherwise you can take the decision to reject the card or continue with the default payment amount.
Example request:
{
"endpoint":"PAYMENT",
"amount":100,
"id":1, // any numeric reference id - optional
"method":"CARD",
"discounts":[
{
"name":"COMMERCIAL-CREDIT-CARD",
"amount":55.05,
"bin_ranges":[
432571,
432572,
437840,
510484,
550489
]
}
]
}
As per the above request, if the payee's card bin number does not match with the above discount bin ranges, the default amount 100 will be proceeded, or if it matches then the 55.05 amount will be proceeded.
But if you want to stop the payment process if the payee's card number does not match with any given discount bin ranges you need to add the below property to the request.
"discounts_only":"YES"
The responses are sent back to you based on your requests, the below are example responses;
- When the card matches with the given discount ranges you will get the applied discount in
applied_discount
property:
{
"applied_discount":{
"amount":55.05,
"bin_ranges":[
432571,
432572,
437840,
510484,
550489
],
"name":"COMMERCIAL-CREDIT-CARD"
},
"approval_code":"408809",
"card_name":"SOMENAME/S",
"card_no":"4325-7200-XXXX-3006",
"card_type":"VISA",
"mid":"000000000000101",
"origin":"PP352720A1004626",
"request":{
"amount":100.0,
"discounts":[
{
"amount":55.05,
"bin_ranges":[
432571,
432572,
437840,
510484,
550489
],
"name":"COMMERCIAL-CREDIT-CARD"
}
],
"endpoint":"PAYMENT",
"id":1,
"method":"CARD",
"origin":"COMPANY-1"
},
"server_time":"2021-02-24 09:47:43 AM",
"status":"STATUS_SUCCESS",
"tid":"00000101",
"transaction_type":"EMV",
"txid":413455
}
- If you set this property to YES
"discounts_only":"YES"
and the card does not match with the discount ranges:
{
"error":"Discount is not available",
"origin":"PP352720A1004626",
"request":{
"amount":100.0,
"discounts":[
{
"amount":55.05,
"bin_ranges":[
432571,
432572,
437840,
510484,
550489
],
"name":"COMMERCIAL-CREDIT-CARD"
}
],
"discounts_only":"YES",
"endpoint":"PAYMENT",
"id":1,
"method":"CARD",
"origin":"COMPANY-1"
},
"status":"STATUS_FAILED"
}
Browse the terminal's IP address with 8080 port number in the same network to ensure the terminal status.
Example: http://192.168.8.101:8080
If the device is online with the local network, the URL will respond as below or else it won't respond anything since the terminal is offline.
This will show the connected POS hosts from the internal and external network sources using LAN and WAN.
STATUS_TERMINAL_AUTHORIZED
STATUS_TERMINAL_AUTHORIZED_ALREADY
STATUS_SUCCESS
STATUS_INVALID_AUTHCODE
STATUS_API_UNREACHABLE
STATUS_FAILED
STATUS_NOT_LOGIN
STATUS_INVALID_AMOUNT
STATUS_INVALID_DATA
STATUS_BUSY
1.5.1 If the request data does not contain required fields or not a valid JSON the below status will be thrown with the error message.
STATUS_INVALID_DATA
1.5.2 If the PAYable application is not available on the terminal or the version of the application does not meet the requirement.
STATUS_API_UNREACHABLE
The below explanation can guide you to establish a connection between the host system and the ECR terminal using an external (WAN - Wide Area Network) network/internet.
2.1.1 Initiate a WebSocket connection to our centralized ECR network with the token and POS name.
- Centralized ECR network: ws://ecr.payable.lk
- Token: 4DqxynHGtHNckmCrRzvVxkwuSfr8faRmPrLIX0hmkqw=
- POS host name: COMPANY-1 - This is the name of your current POS system.
Example:
ws://ecr.payable.lk?token=4DqxynHGtHNckmCrRzvVxkwuSfr8faRmPrLIX0hmkqw=&pos=COMPANY-1
Once the connection is established, the implemented WebSocket client will be notified as the server accepted the handshake and opened the socket connection by triggering the onOpen
method.
In the below situations handshake will be failed:
-
Token and POS/Host name are not provided
Error:
HTTP/1.1 400 Bad Request
Example:
Error during WebSocket handshake: Unexpected response code: 400
-
Token is invalid
Error:
HTTP/1.1 401 Unauthorized
Example:
Error during WebSocket handshake: Unexpected response code: 401
Some clients can identify the response code 401 as invalid authentication
HTTP Authentication failed; no valid credentials available
-
POS/Host name is duplicate and already in use
Error:
HTTP/1.1 429 Too Many Requests
Example:
Error during WebSocket handshake: Unexpected response code: 429
2.1.2 Send a auth request to authorize the terminal with the current POS/Host system if it's not already authorized.
- Turn on your terminal device and connect with the internet
- Make sure the terminal is connected with the ECR network
- Send the authorization request to the terminal's serial number as below
Example auth request:
{
"terminal": "PP35271812000161",
"auth_code": 44280
}
The terminal will validate your auth code and accept the authorization request with a successful response as below.
Status:
STATUS_TERMINAL_AUTHORIZED
Example successful auth response:
{
"origin":"PP35271812000161",
"request":{
"auth_code":44280,
"external":true,
"origin":"COMPANY-1",
"terminal":"PP35271812000161"
},
"status":"STATUS_TERMINAL_AUTHORIZED"
}
If you send an auth request to a terminal that is not connected and online with the ECR network, you will get the response as terminal unreachable with below status.
STATUS_TERMINAL_UNREACHABLE
If the auth code is invalid you will receive the response as the below status.
STATUS_INVALID_AUTHCODE
If the POS/Host system has already done a successful authorization process with the terminal, it will get the response status as below.
STATUS_TERMINAL_AUTHORIZED_ALREADY
The process is same as the LAN request/response that we already explained above in 1.2.
Additionally you need to add terminal in each request as below.
{
"terminal": "PP35271812000161",
...
}
Please check out the JavaScript example to learn more.
You will get the below status when you send a payment request to a terminal that is not connected to the ECR network and online.
STATUS_TERMINAL_UNREACHABLE
When you send a payment request to a terminal that is not authorized with your POS/Host system at least once, you will get the status as not authorized.
STATUS_TERMINAL_UNAUTHORIZED
JavaScript Demonstration: http://ecr-git-demo.payable.lk/html
ECR Android service is running in the terminal to expose the ECR facilities.
Auth code is the authorization code that helps the POS/Host systems to make the connection between terminal and POS/Host within the ECR network through WAN.
The auth code can be revoked from the below option in the ECR application of the terminal, which would help to prevent the new POS/Host system from connecting to the terminal.
POS/Host systems that are authorized already would be listed here in the ECR application of the terminal, it can be removed from the terminal using the remove button which also removes the absolute authorizations of those POS/Host systems.
-
Copy or include the ECR JAR library ecr-1.1.jar to the Java libs folder of your Java project.
-
Construct the
ECRTerminal
object with IP address, token, POS host name and implement the listener interface.
If you connect the terminal using the LAN network internally, the object should be constructed as below:
ECRTerminal ecrTerminal = new ECRTerminal(ip_address, token, pos_name, listener);
If you connect the terminal using the WAN network externally, the object should be constructed as below:
ECRTerminal ecrTerminal = new ECRTerminal(token, pos_name, listener);
Example:
ECRTerminal ecrTerminal = new ECRTerminal("192.168.8.101", "4DqxynHGtHNckmCrRzvVxkwuSfr8faRmPrLIX0hmkqw=", "JAVA-POS", new ECRTerminal.Listener(){
@Override
public void onOpen(String data) {
}
@Override
public void onClose(int code, String reason, boolean remote) {
}
@Override
public void onMessage(String message) {
}
@Override
public void onMessage(ByteBuffer message) {
}
@Override
public void onError(Exception ex) {
}
});
Initiate the terminal connection, call this method once and do error handling when the terminal disconnected.
ecrTerminal.connect();
After the connection is successfully established you can start to send the payment request to the terminal.
- Construct the payment request object and convert it to JSON
PAYableRequest request = new PAYableRequest(PAYableRequest.ENDPOINT_PAYMENT, 252, 256.00, PAYableRequest.METHOD_CARD);
String jsonRequest = request.toJson();
If you have connected the terminal using the WAN network externally, the payment request should be constructed as below:
The first parameter is the serial number of your terminal
PAYableRequest request = new PAYableRequest("PP35271812000161", PAYableRequest.ENDPOINT_PAYMENT, 252, 256.00, PAYableRequest.METHOD_CARD);
Explanation:
PAYableRequest request = new PAYableRequest(terminal, PAYableRequest.ENDPOINT_PAYMENT, id, amount, PAYableRequest.METHOD_CARD);
- Send to terminal
ecrTerminal.send(jsonRequest);
You can expect the reponse at
onMessage
method of the listener.
If the terminal rejects your request with STATUS_TERMINAL_UNAUTHORIZED
status, you need to send the auth request to the terminal as below:
PAYableRequest request = new PAYableRequest(terminal_serial, auth_code);
ecrTerminal.send(request.toJson());
Refer to the below demonstration to know more about connection and payment requests.
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
import com.google.gson.JsonSyntaxException;
import org.payable.ecr.ECRTerminal;
import org.payable.ecr.PAYableRequest;
import org.payable.ecr.PAYableResponse;
class Demo {
ECRTerminal ecrTerminal;
public void start() {
try {
ecrTerminal = new ECRTerminal("192.168.2.204", "4DqxynHGtHNckmCrRzvVxkwuSfr8faRmPrLIX0hmkqw=", "JAVA-POS", new ECRTerminal.Listener() {
@Override
public void onOpen(String data) {
// 1. Construct the sale request object
PAYableRequest request = new PAYableRequest(PAYableRequest.ENDPOINT_PAYMENT, 252, 256.00, PAYableRequest.METHOD_CARD);
// If you want to add a discount options to the request
// request.addDiscount(new PAYableDiscount("COM", 10, 432572, 435262, 432572));
// 2. Send to terminal
ecrTerminal.send(request.toJson());
// 3. Expect the response at 'onMessage' method
// If you want to stop the ongoing payment process in LAN/USB
// ecrTerminal.send(PAYableRequest.stop());
// If you want to stop the ongoing payment process in WAN
// ecrTerminal.send(PAYableRequest.stop("PP352720A1004626"));
}
@Override
public void onClose(int code, String reason, boolean remote) {
}
@Override
public void onMessage(String message) {
// Map JSON to Java object (optional) or handle from String data
try {
PAYableResponse response = PAYableResponse.from(message);
System.out.println("RESPONSE: " + response.status);
} catch (JsonSyntaxException ex) {
// Invalid JSON
}
}
@Override
public void onMessage(ByteBuffer message) {
// Optional implementation
}
@Override
public void onError(Exception ex) {
// Handle connection exceptions
}
});
// Just for the console print
ecrTerminal.debug = true;
// Initiate the terminal connection, call this method once and handle error when terminal disconnected
ecrTerminal.connect();
} catch (URISyntaxException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new Demo().start();
}
}
Establishing connection
let ws = new WebSocket('ws://192.168.8.101:45454?token=4DqxynHGtHNckmCrRzvVxkwuSfr8faRmPrLIX0hmkqw=&pos=COMPANY-1')
ws.onopen = () => console.log("Connection is opened")
ws.onclose = () => console.log("Connection is closed")
ws.onerror = (err) => console.log('Error occured: ' + err)
ws.onmessage = (message) => console.log('Response received: ' + message.data)
Sending payment request to the terminal
ws.send(`{"endpoint":"PAYMENT","amount":20.00,"id":1,"method":"CARD","order_tracking":"some_id","receipt_email":"[email protected]","receipt_sms":"0771111111"}`)
Refer the examples for HTML and JavaScript implementations payable.github.io/ecr-sdks/html
import websocket
ws = websocket.WebSocket()
ws.connect('ws://192.168.8.101:45454?token=4DqxynHGtHNckmCrRzvVxkwuSfr8faRmPrLIX0hmkqw=&pos=COMPANY-1')
ws.send('{"amount":20,"endpoint":"PAYMENT","method":"CARD","order_tracking":"example_sale_from_test","receipt_email":"[email protected]","receipt_sms":"0777777777","id":1}')
while(True):
result = ws.recv()
print(result)
Request PAYable to enable the USB ADB feature to your terminal
If you want to connect the terminal using USB cable, please follow the below steps.
-
Install Android Debug Bridge (adb) and set the environment path for ADB directory on your host POS system, this can be downloaded from Android platform-tools
-
If you are using PAYable Java ECR SDK, you can ignore the below step, or else you have to run this command on your Linux/Mac Terminal or Windows PowerShell.
adb forward tcp:45454 tcp:45454
- When you connect the terminal through USB, you have to provide the IP address as
127.0.0.1
ws://127.0.0.1:45454?token=4DqxynHGtHNckmCrRzvVxkwuSfr8faRmPrLIX0hmkqw=&pos=COMPANY-1
-
Install ADB as per the previous step
-
Set the IP address as
127.0.0.1
ECRTerminal ecrTerminal = new ECRTerminal("127.0.0.1", ...
- (Optional) If you have not installed ADB or any issues with your USB libraries, handle the below exceptions.
...
} catch (URISyntaxException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
Wi-Fi Direct (P2P) allows Android 4.0 (API level 14) and higher devices with the appropriate hardware to connect directly to each other via Wi-Fi without an intermediate access point.
P2P library provides instant integration (PnP) support for WIFI-Direct P2P for any Android projects plus it remembers the recently connected device and reconnects it automatically when it's available.
- No SSID Access Point is required
- No need to connect to WIFI Network
- Can be used while Mobile Data is turned on
- Auto reconnects when the terminal is available nearby
Refer the P2P Documentation to know more about PAYable P2P Wi-Fi Direct implementation.
Refer this repository to learn more.
PAYable ECR SDKs Integration