API – Developers Docs API – Developers Docs
  • Addon Payments
  • POS integrated Payments
  • SpanishSwitch to Spanish
API – Developers Docs API – Developers Docs
API – Developers Docs
  • Addon Payments
  • POS integrated Payments
  • SpanishSwitch to Spanish
POS integrated Payments
  • Folder icon closed Folder open iconPayment integrated with Android POS
    • InStore Payment API Android
    • InStore Payment API Windows
    • InStore Payment REST API
  • Folder icon closed Folder open iconPayment integrated with Smartphone POS
    • Payment integration with Smartphone POS (iOS)
    • Payment integration with Smartphone POS (Android)
  • Folder icon closed Folder open iconPOS integrated Payments
    • Transactions
      • Tokenization
    • Reports
    • Device
  • Folder icon closed Folder open iconHost2Host Integration – POI-Switch Protocol
  • Folder icon closed Folder open iconPOS Data sheets

Payment integration with Smartphone POS (Android)

  • Version: 1.1.18
The estimated time to complete an integration with the Comercia 2.0 solution is 21 days. Our support team is fully available to assist you during this development process and ensure a successful implementation.

Introduction – About Smartphone Integrated POS

With the Smartphone Integrated POS integration (Android), you can process payments using the amount and registration information you send to the Smartphone POS app without having to add a payment library to your app. 

IMPORTANT: Only compatible with Android devices version 9.0 or higher, 64bit and with NFC reading (card reader).

Data is exchanged between the apps by creating a channel with Messenger Service.

The connection to the messaging service will not be established correctly if the merchant’s application is not included in the list of valid (permitted) applications (hashes).

This authorization mechanism works with SHA-256 hash signature used in the app. You can do this with the following command:
keytool -alias yourKeyAlias -keystore yourKeysore.jks -list -v

After you execute the command, the hash values will look like this:

Certificate thumbprint:
  • SHA1: C5:79:8C:79:C2:D1:CC:E6:F2:3F:34:29:10:28:7E:31:09:3E:2B:A4
  • SHA256: 6D:86:64:D3:84:3A:64:50:66:07:0E:7B:B8:71:DA:9E:2C:83:DE:EF:FD:D1:25:24:8D:D1:ED:B5:6D:0E:70:62

Important: This step is required to continue the rest of the integration.

After getting the SHA-256 value, you have to share it with the Comercia team at this email. This way, it will be added to the list of ones allowed. They will also give you a new APK with the hash value on the allowed list.

Communication diagram

Payment process flow

Preparing the AndroidManifest

You need permission for the MessengerService to create channels and exchange data between the sales app and the Smartphone POS payment app. Apps that don’t have this declaration and permissions can’t establish communications with the Smartphone POS app because they won’t be able to connect and exchange data. The permission name can be changed, although the exact value of the string“android:name” is correct.

The NFC permissions, location and internet have already been requested in the Smartphone POS app. 

  1. Add permissions: 
				
					<permission
    android:name="com.softpos.app2app.permission.MESSAGING_SERVICE"
    android:protectionLevel="normal" />
    
<uses-permission android:name="com.softpos.app2app.permission.MESSAGING_SERVICE" />
				
			

You must add services, otherwise an error will occur as we have not created the MessengerService.

				
					<application
...
<service
    android:name=".MessengerService"
    android:exported="true"
    android:permission="com.comercia.app2app.permission.MESSAGING_SERVICE" />

<queries>
    <intent>
        <action android:name="android.intent.action.MAIN" />
    </intent>
</queries>

<activity....
<intent-filter>
    <action android:name="android.intent.action.MAIN"/>
</intent-filter>
<activity>

</application>
				
			

* Change to suit your needs

Create the MessengerService class

Follow these steps: 

  1. The MessengerService class must be extended from Service:
				
					public class MessengerService extends Service
				
			

Variables: 

VariablesDescription
serverHandlerRequired to send and receive messages.
mMessengerRequired to link.
handShakeListenerTo check the handshake

2. Once the onBind method is implemented, onBind returns the binder for the messenger to the activity.

				
					@Nullable
@Override
public IBinder onBind(Intent intent) {
    return mMessenger.getBinder();
}
				
			

3. Add it to the MessengerService class:

				
					public MessengerService() {
super();
    HandlerThread handlerThread = new HandlerThread("MyHandlerThread");
    handlerThread.start();
    Looper looper = handlerThread.getLooper();

    serverHandler = new ServerHandler(looper);
    mMessenger = new Messenger(serverHandler);
}
				
			

4. Add ServerHandler to MessengerService.class. ServerHandler is the controller responsible for handling all the messages for the Smartphone POS app.

				
					public class ServerHandler extends Handler {
    private Messenger replyTo;
    public ServerHandler(Looper looper) {
        super(looper);
    }
    public Messenger getReplyTo() {
        return replyTo;
    }
    public void setReplyTo(Messenger replyTo) {
        this.replyTo = replyTo;
    }
    
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        switch (msg.what) {
            case 0: //to reply to incoming handShake
                setReplyTo(msg.replyTo);
                sendHandShake()
                if (handShakeListener != null)
                    handShakeListener.onHandShaked();
                handShakeListener = null;
                break;
            case 1: //Send message to client app
                Message serviceMessage = Message.obtain();
                serviceMessage.setData(msg.getData());
                serviceMessage.what = 1;
                serviceMessage.replyTo = mMessenger;
                try {
                    getReplyTo().send(serviceMessage);
                } catch (RemoteException e) {
                    throw new RuntimeException("No messenger binded...", e);
                }
                break;
            case 2: //to see the incoming response
                setReplyTo(msg.replyTo);
                Bundle bundle = msg.getData();
                bundle.setClassLoader(getClass().getClassLoader());
                Log.e("response", msg.getData().getString("appResponse", "null"));
                break;
        }
    }
    
    //to send a handshake
    private void sendHandShake() {
        Message serviceMessage = new Message();
        Bundle serviceBundle = new Bundle();
        serviceBundle.putBoolean("appHandshake", true);
        serviceMessage.setData(serviceBundle);
        serviceMessage.what = 1;
        handleMessage(serviceMessage);
    }
    
    //Requests the last transaction information from SoftPos application
    public void getLastTxnApp(PaymentDataRequest paymentDataRequest) throws JSONException {
        Message serviceMessage = new Message();
        Bundle serviceBundle = new Bundle();
        JSONObject registerParameters = new JSONObject();
        registerParameters.put("terminalId", paymentDataRequest.getTerminalId());
        registerParameters.put("merchantId", paymentDataRequest.getMerchantId());
        registerParameters.put("activationCode", paymentDataRequest.getActivationCode());
        JSONObject lastTxnData = new JSONObject();
        lastTxnData.put("appLastTxn", "1");
        lastTxnData.put("registerParameters", registerParameters);
        serviceBundle.putString("appLastTxn", String.valueOf(lastTxnData));
        Log.e("lastTxn", String.valueOf(lastTxnData));
        serviceMessage.setData(serviceBundle);
        serviceMessage.what = 1;
        handleMessage(serviceMessage);
    }
    
    //Sends register information, amount and menu items to SoftPos application
    public void sendPayment(PaymentDataRequest paymentDataRequest) throws JSONException {
        Message serviceMessage = new Message();
        Bundle serviceBundle = new Bundle();
        JSONObject registerParameters = new JSONObject();
        registerParameters.put("terminalId", paymentDataRequest.getTerminalId());
        registerParameters.put("merchantId", paymentDataRequest.getMerchantId());
        registerParameters.put("activationCode", paymentDataRequest.getActivationCode());
        JSONObject configParameters = new JSONObject();
        configParameters.put("drawerMenu", paymentDataRequest.getDrawerMenu());
        configParameters.put("salesButton", paymentDataRequest.getSalesButton());
        configParameters.put("voidButton", paymentDataRequest.getVoidButton());
        configParameters.put("refundButton", paymentDataRequest.getRefundButton());
        configParameters.put("historyButton", paymentDataRequest.getHistoryButton());
        configParameters.put("settingsButton", paymentDataRequest.getSettingsButton());
        configParameters.put("tipScreen", paymentDataRequest.getTipScreen());
        configParameters.put("userPhoto", paymentDataRequest.getUserPhoto());
        
        JSONObject paymentData = new JSONObject();
        if (!paymentDataRequest.getTransactionType().equals("200")) { // if not sale
            paymentData.put("transactionId", paymentDataRequest.getTransactionId());
        }
        paymentData.put("amount", paymentDataRequest.getAmount());
        paymentData.put("transactionType", paymentDataRequest.getTransactionType());
        paymentData.put("configParameters", configParameters);
        paymentData.put("registerParameters", registerParameters); //registerParameters optional. If you send t
        
        //*** customMessage optional. ****
        paymentData.put("customMessage", paymentDataRequest.getCustomMessage());
        //*** customMessage optional. ****
        
        serviceBundle.putString("paymentData", String.valueOf(paymentData));
        Log.e("paymentData", String.valueOf(paymentData));
        serviceMessage.setData(serviceBundle);
        serviceMessage.what = 1;
        handleMessage(serviceMessage);
    }
    
    public void gotoList(PaymentDataRequest paymentDataRequest) throws JSONException {
        Message serviceMessage = new Message();
        Bundle serviceBundle = new Bundle();
        JSONObject registerParameters = new JSONObject();
        registerParameters.put("terminalId", paymentDataRequest.getTerminalId());
        registerParameters.put("merchantId", paymentDataRequest.getMerchantId());
        registerParameters.put("activationCode", paymentDataRequest.getActivationCode());
        JSONObject configParameters = new JSONObject();
        configParameters.put("drawerMenu", paymentDataRequest.getDrawerMenu());
        configParameters.put("salesButton", paymentDataRequest.getSalesButton());
        configParameters.put("voidButton", paymentDataRequest.getVoidButton());
        configParameters.put("refundButton", paymentDataRequest.getRefundButton());
        configParameters.put("historyButton", paymentDataRequest.getHistoryButton());
        configParameters.put("settingsButton", paymentDataRequest.getSettingsButton());
        configParameters.put("tipScreen", paymentDataRequest.getTipScreen());
        configParameters.put("userPhoto", paymentDataRequest.getUserPhoto());
        JSONObject goToListData = new JSONObject();
        goToListData.put("listType", paymentDataRequest.getListType());
        goToListData.put("configParameters", configParameters);
        goToListData.put("registerParameters", registerParameters);
        /*if(StateClass.isRegisterList())
        goToListData.put("registerParameters",registerParameters);*/
        serviceBundle.putString("gotoList", String.valueOf(goToListData));
        Log.e("gotoList", String.valueOf(goToListData));
        serviceMessage.setData(serviceBundle);
        serviceMessage.what = 1;
        handleMessage(serviceMessage);
    }
    
    public void gotoManuelSettlement(PaymentDataRequest paymentDataRequest) throws JSONException {
        Message serviceMessage = new Message();
        Bundle serviceBundle = new Bundle();
        JSONObject registerParameters = new JSONObject();
        registerParameters.put("terminalId", paymentDataRequest.getTerminalId());
        registerParameters.put("merchantId", paymentDataRequest.getMerchantId());
        registerParameters.put("activationCode", paymentDataRequest.getActivationCode());
        JSONObject configParameters = new JSONObject();
        configParameters.put("drawerMenu", paymentDataRequest.getDrawerMenu());
        configParameters.put("salesButton", paymentDataRequest.getSalesButton());
        configParameters.put("voidButton", paymentDataRequest.getVoidButton());
        configParameters.put("refundButton", paymentDataRequest.getRefundButton());
        configParameters.put("historyButton", paymentDataRequest.getHistoryButton());
        configParameters.put("settingsButton", paymentDataRequest.getSettingsButton());
        configParameters.put("settlementButton", paymentDataRequest.getSettlementButton());
        configParameters.put("tipScreen", paymentDataRequest.getTipScreen());
        configParameters.put("userPhoto", paymentDataRequest.getUserPhoto());
        JSONObject goToManuelSettlement = new JSONObject();
        goToManuelSettlement.put("configParameters", configParameters);
        goToManuelSettlement.put("registerParameters", registerParameters);
        if (StateClass.isRegisterGotoList())
            goToManuelSettlement.put("registerParameters", registerParameters);
        serviceBundle.putString("gotoManuelSettlement", String.valueOf(goToManuelSettlement));
        Log.e("gotoManuelSettlement", String.valueOf(goToManuelSettlement));
        serviceMessage.setData(serviceBundle);
        serviceMessage.what = 1;
        handleMessage(serviceMessage);
    }
    
    public void onlyRegister(PaymentDataRequest paymentDataRequest) throws JSONException {
        Message serviceMessage = new Message();
        Bundle serviceBundle = new Bundle();
        JSONObject registerParameters = new JSONObject();
        registerParameters.put("terminalId", paymentDataRequest.getTerminalId());
        registerParameters.put("merchantId", paymentDataRequest.getMerchantId());
        registerParameters.put("activationCode", paymentDataRequest.getActivationCode());
        JSONObject onlyRegister = new JSONObject();
        onlyRegister.put("registerParameters", registerParameters);
        serviceBundle.putString("appRegister", String.valueOf(onlyRegister));
        Log.e("onlyRegister", String.valueOf(onlyRegister));
        serviceMessage.setData(serviceBundle);
        serviceMessage.what = 1;
        handleMessage(serviceMessage);
    }
}
				
			

5. Add this method to get the most recent transaction:

				
					public static void getLastTxn(PaymentDataRequest paymentDataRequest) throws RemoteException, JSONException {
    serverHandler.getLastTxnApp(paymentDataRequest);
}
				
			

6. Add this method to send a message:

				
					public static void sendPayment(PaymentDataRequest paymentDataRequest) throws RemoteException, JSONException {
    serverHandler.sendPayment(paymentDataRequest);
}
				
			

7. Add this method to get the list of voids, refunds and history: 

				
					public static void gotoList(PaymentDataRequest paymentDataRequest) throws RemoteException, JSONException {
    serverHandler.gotoList(paymentDataRequest);
}
				
			

8. Add this method for the log:

				
					public static void onlyRegister(PaymentDataRequest paymentDataRequest) throws RemoteException, JSONException {
    serverHandler.onlyRegister(paymentDataRequest);
}
				
			

9. Add HandshakeListener to MessengerService.class:

				
					interface HandShakeListener {
    void onHandShaked();
}
				
			

10. To establish the handshake: 

				
					public static void setHandshake(HandShakeListener handShakeListener_){
    handShakeListener = handShakeListener_;
}
				
			

11. Add this method for manual close:

				
					public static void gotoManuelSettlement(PaymentDataRequest paymentDataRequest) throws RemoteException, JSONException {
    serverHandler.gotoManuelSettlement(paymentDataRequest);
}
				
			

Create the SoftposAppLoader class

Follow these steps:

  1. Add variables and constructors:
VariablesDescription
appNameSoftpos app name.
packageNameName of the Softpos app package.
				
					private static Context context;
static String appName = "DESTINATION APP NAME example: Smartphone TPV";
static String packageName = "DESTINATION PACKAGNAME example: com.comercia.app";
SoftposAppLoader(Context context){
    this.context = context;
}
				
			

2. Check they are installed: 

				
					private static boolean isAppInstalled() {
    PackageManager pm = context.getPackageManager();
    List<PackageInfo> packageInfos = pm.getInstalledPackages(0);
    for (PackageInfo packageInfo : packageInfos) {
        
        if (packageInfo.packageName.equalsIgnoreCase(context.getPackageName())) {
            return true;
        }
    }
    return false;
}
				
			

3. Check they are enabled: 

				
					private static boolean isAppEnabled() {
    boolean appStatus = false;
    try {
        PackageManager pm = context.getPackageManager();
        List<PackageInfo> packageInfos = pm.getInstalledPackages(0);
        for (PackageInfo packageInfo : packageInfos) {
            if (packageInfo.applicationInfo.enabled) {
                appStatus = true;
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return appStatus;
}
				
			

4. To call the latest transaction: 

				
					public static void getLastTxn(final PaymentDataRequest paymentDataRequest) {
    if (isAppInstalled())
        if (isAppEnabled()) {
            Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(packageName)
                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
            launchIntent.putExtra("app2appPackageName", BuildConfig.APPLICATION_ID)
                .putExtra("app2appMessengerServiceClassPath", MessengerService.class.getCanonicalName());
            context.startActivity(launchIntent);
            MessengerService.handShakeListener = null;
            MessengerService.setHandshake(new MessengerService.HandShakeListener() {
                @Override
                public void onHandShaked() {
                    new Handler().post(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                MessengerService.getLastTxn(paymentDataRequest);
                            } catch (RemoteException e) {
                                e.printStackTrace();
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }
                        }
                    });
                }
            });
        }
        else Toast.makeText(context, appName + " app is not enabled.", Toast.LENGTH_SHORT).show();
    else Toast.makeText(context, appName + " app is not installed.", Toast.LENGTH_SHORT).show();
}
				
			

5. To open the Smartphone POS payment application: 

				
					public static void getPayment(final PaymentDataRequest paymentDataRequest) {
    if (isAppInstalled())
        if (isAppEnabled()) {
            Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(packageName)
                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
            launchIntent.putExtra("app2appPackageName", BuildConfig.APPLICATION_ID)
                .putExtra("app2appMessengerServiceClassPath", MessengerService.class.getCanonicalName());
            context.startActivity(launchIntent);
            MessengerService.handShakeListener = null;
            MessengerService.setHandshake(new MessengerService.HandShakeListener() {
                @Override
                public void onHandShaked() {
                    new Handler().post(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                MessengerService.sendPayment(paymentDataRequest);
                            } catch (RemoteException | JSONException e) {
                                e.printStackTrace();
                            }
                        }
                    });
                }
            });
        }
        else Toast.makeText(context, appName + " app is not enabled.", Toast.LENGTH_SHORT).show();
    else Toast.makeText(context, appName + " app is not installed.", Toast.LENGTH_SHORT).show();
}
				
			

6. The Softpos app opens and shows the list screen: 

				
					public static void goToList(final PaymentDataRequest paymentDataRequest) {
    if (isAppInstalled())
        if (isAppEnabled()) {
            Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(packageName)
                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
            launchIntent.putExtra("app2appPackageName", BuildConfig.APPLICATION_ID)
                .putExtra("app2appMessengerServiceClassPath", MessengerService.class.getCanonicalName());
            context.startActivity(launchIntent);
            MessengerService.handShakeListener = null;
            MessengerService.setHandshake(new MessengerService.HandShakeListener() {
                @Override
                public void onHandShaked() {
                    new Handler().post(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                MessengerService.gotoList(paymentDataRequest);
                            } catch (RemoteException | JSONException e) {
                                e.printStackTrace();
                            }
                        }
                    });
                }
            });
        }
        else Toast.makeText(context, appName + " app is not enabled.", Toast.LENGTH_SHORT).show();
    else Toast.makeText(context, appName + " app is not installed.", Toast.LENGTH_SHORT).show();
}
				
			

7. The Smartphone POS app opens and shows the log screen: 

				
					public static void getOnlyRegister(final PaymentDataRequest paymentDataRequest) {
    if (isAppInstalled())
        if (isAppEnabled()) {
            Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(packageName)
                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
            launchIntent.putExtra("app2appPackageName", BuildConfig.APPLICATION_ID)
                .putExtra("app2appMessengerServiceClassPath", MessengerService.class.getCanonicalName());
            context.startActivity(launchIntent);
            MessengerService.handShakeListener = null;
            MessengerService.setHandshake(new MessengerService.HandShakeListener() {
                @Override
                public void onHandShaked() {
                    new Handler().post(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                MessengerService.onlyRegister(paymentDataRequest);
                            } catch (RemoteException | JSONException e) {
                                e.printStackTrace();
                            }
                        }
                    });
                }
            });
        }
        else Toast.makeText(context, appName + " app is not enabled.", Toast.LENGTH_SHORT).show();
    else Toast.makeText(context, appName + " app is not installed.", Toast.LENGTH_SHORT).show();
}
				
			

8. The Smartphone POS app opens and the manual close is done: 

				
					public static void gotoManuelSettlement(final PaymentDataRequest paymentDataRequest) {
    if (isAppInstalled())
        if (isAppEnabled()) {
            Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(packageName)
                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
            launchIntent.putExtra("app2appPackageName", "com.example.opendemoapp")
                .putExtra("app2appMessengerServiceClassPath", MessengerService.class.getCanonicalName());
            context.startActivity(launchIntent);
            MessengerService.handShakeListener = null;
            MessengerService.setHandshake(new MessengerService.HandShakeListener() {
                @Override
                public void onHandShaked() {
                    new Handler().post(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                MessengerService.gotoManuelSettlement(paymentDataRequest);
                            } catch (RemoteException | JSONException e) {
                                e.printStackTrace();
                            }
                        }
                    });
                }
            });
        }
        else Toast.makeText(context, appName + " app is not enabled.", Toast.LENGTH_SHORT).show();
    else Toast.makeText(context, appName + " app is not installed.", Toast.LENGTH_SHORT).show();
}
				
			

Using the PaymentDataRequest

Follow these steps:

  1. You can initiate the payment action with the following code for a sale transaction. The following code is just an example, you have to adjust it to your needs. You have to register the transactionId and amount refunded from the sale. It will be required for voids and refunds. 

				
					PaymentDataRequest paymentDataRequest = new PaymentDataRequest();
paymentDataRequest.setMerchantId("YOUR MERCHANT ID TO REGISTER");
paymentDataRequest.setTerminalId("YOUR TERMINAL ID TO REGISTER ");
paymentDataRequest.setActivationCode("ACTIVATION CODE");
paymentDataRequest.setAmount("1400"); //-> YOUR AMOUNT VALUE
paymentDataRequest.setTransactionType("200"); //-> TRANSATION TYPE (FOR SALE -> "200" )
paymentDataRequest.setOrderId("12345"); //-> YOUR ORDER ID OF TRANSACTION
paymentDataRequest.setDrawerMenu("1"); //-> FOR DRAWER MENU OPEN/CLOSE
paymentDataRequest.setSalesButton("1"); //-> FOR SALE MENU VISIBLE = 1 /UNVISIBLE =0
paymentDataRequest.setVoidButton("1"); //-> FOR BUTTON VOID VISIBLE = 1 /UNVISIBLE =0
paymentDataRequest.setRefundButton("1"); //-> FOR REFUND BUTTON VISIBLE = 1 /UNVISIBLE =0
paymentDataRequest.setHistoryButton("1"); //-> FOR HISTORY BUTTON VISIBLE = 1 /UNVISIBLE =0
paymentDataRequest.setSettingsButton("0"); //-> FOR SETTING BUTTON VISIBLE = 1 /UNVISIBLE =0
paymentDataRequest.setTipScreen("0"); //-> FOR TIP MENU VISIBLE = 1 /UNVISIBLE =0
paymentDataRequest.setUserPhoto("1"); //-> FOR USER PHOTO VISIBLE = 1 /UNVISIBLE =0


/////// OPTIONAL PART ////////////
Map<String, String> customMessage = new HashMap<>();
customMessage.put("courierId", "YOUR COURIER ID");
customMessage.put("subMID","YOUR EXTERNAL MERCHANT ID"); //-> FOR SUB MERCHANT-ID TO DELIVER PAYMENT AMOUNT
customMessage.put("subTID","YOUR EXTERNAL TERMINAL ID"); //-> FOR SUB TERMINAL-ID TO DELIVER PAYMENT AMOUNT
paymentDataRequest.setCustomMessage(new JSONObject(customMessage).toString());
/////// OPTIONAL PART ////////////
SoftposAppLoader softposAppLoader = new SoftposAppLoader(getApplicationContext());
softposAppLoader.getPayment(paymentDataRequest);
				
			
1.a: Transaction types:
setTransactionTypeDescription
200Sales
300Refunds
400Voids
700MoneyAdd
1.b: ConfigParameters: Send 1 or 0 to customize the application. For example:
paymentDataRequest.setRefundButton("1"); 

2. You can use it for any activity as follows to Void or Refund a payment.

You can void/refund with the transactionID you get during the sale. Plus, to initiate the void or refund, there are two methods:

  • Send a list request and open the void list screen and click on the button.
  • Send the payment request directly as VOID.

If you send a list request, you can’t get a payment void response, but that is the only difference. Then, you process the refund as follows.

This is a sample code to void a transaction: 

				
					PaymentDataRequest paymentDataRequest = new PaymentDataRequest();
paymentDataRequest.setMerchantId("MERCHANT ID TO REGISTER");
paymentDataRequest.setTerminalId("TERMINAL ID TO REGISTER");
paymentDataRequest.setActivationCode("ACTIVATION CODE");
paymentDataRequest.setAmount("1300");
paymentDataRequest.setTransactionType("400"); // or setTransactionType("300") for refund
paymentData.setTransactionId("123456");
paymentDataRequest.setDrawerMenu("1");
paymentDataRequest.setSalesButton("1");
paymentDataRequest.setVoidButton("1");
paymentDataRequest.setRefundButton("1");
paymentDataRequest.setHistoryButton("1");
paymentDataRequest.setSettingsButton("0");
paymentDataRequest.setTipScreen("0");
paymentDataRequest.setUserPhoto("1");

SoftposAppLoader softposAppLoader = new SoftposAppLoader(getApplicationContext());
softposAppLoader.getPayment(paymentDataRequest);
				
			

3. You can use it as follows to see the final transaction. This is a sample code: 

				
					PaymentDataRequest paymentDataRequest = new PaymentDataRequest();
paymentDataRequest.setMerchantId("YOUR MERCHANT ID TO REGISTER");
paymentDataRequest.setTerminalId("YOUR TERMINAL ID TO REGISTER");
paymentDataRequest.setActivationCode("ACTIVATION CODE");

SoftposAppLoader softposAppLoader = new SoftposAppLoader(getApplicationContext());
softposAppLoader.getLastTxn(paymentDataRequest);
				
			

4. You can use it as follows to see the final transaction. 

setTransactionTypeDescription
3000List of refunds
4000List of voids
5000List of logs
				
					PaymentDataRequest paymentDataRequest = new PaymentDataRequest();
paymentDataRequest.setMerchantId("MERCHANT ID TO REGISTER");
paymentDataRequest.setTerminalId("TERMINAL ID TO REGISTER");
paymentDataRequest.setActivationCode("ACTIVATION CODE");
paymentDataRequest.setListType("3000");
paymentDataRequest.setDrawerMenu("1");
paymentDataRequest.setSalesButton("1");
paymentDataRequest.setVoidButton("1");
paymentDataRequest.setRefundButton("1");
paymentDataRequest.setHistoryButton("1");
paymentDataRequest.setSettingsButton("0");
paymentDataRequest.setTipScreen("0");
paymentDataRequest.setUserPhoto("1");

SoftposAppLoader softposAppLoader = new SoftposAppLoader(getApplicationContext());
softposAppLoader.gotoList(paymentDataRequest);
				
			

5. You can use it as follows for records: 

				
					PaymentDataRequest paymentDataRequest = new PaymentDataRequest();
paymentDataRequest.setMerchantId(((EditText)findViewById(R.id.merchantId)).getText().toString());
paymentDataRequest.setTerminalId(((EditText)findViewById(R.id.terminalId)).getText().toString());
paymentDataRequest.setActivationCode(((EditText)findViewById(R.id.activationCode)).getText().toString());

SoftposAppLoader softposAppLoader = new SoftposAppLoader(getApplicationContext());
softposAppLoader.getOnlyRegister(paymentDataRequest);
				
			

Sample incoming and outgoing messages

In this section, you have several messages for different situations.

Record of payment transactions

1.a: Message sent from your merchant payment app: 

				
					appData - > 
{
    "amount": "1400",
    "transactionType": "200",
    "configParameters": {
        "drawerMenu": "1",
        "salesButton": "1",
        "voidButton": "1",
        "refundButton": "1",
        "historyButton": "1",
        "settingsButton": "1",
        "tipScreen": "0",
        "userPhoto": "1"
    },
    "registerParameters": {
        "terminalId": "16010129",
        "merchantId": "000000009041042",
        "activationCode": "testCode"
    },
    "customMessage": "{\"courierId\":\"17823678\",\
    "subMID\":\"MID123456\",\
    "subTID\":\"TID123456\",\
    "installmentCount\":\"3\"}"
}
				
			

The CustomMessage parameter is sent directly to the host.

If subMID and subTID are provided, the backend system of the Smartphone POS app replaces the current MID (Merchant ID) and the TID (Terminal ID) just before sending the transaction info to the client’s external host. The transaction is completed with the replaced merchant information (subTID, subMID) on the client host side, but the transaction is stored in the database with the original MID/TID. Here is an example:

  1. There is a terminal registered on the backend system of the Smartphone POS app with MID: 1 and TID: 1.
  2. A transaction is initiated giving subMID: 2 and subTID: 2 in the field customMessage.
  3. The customMessage is sent to the Smartphone POS app backend.
  4. The backend system verifies the customMessage field and extracts the subMID/subTID information and replaces them in the transaction info for the original ones just before sending the transaction on the acquirer’s gateway.
  5. When the response is received, the backend once again replaces the merchant information with the original: MID:1 TID:1.
  6. The transaction is stored in the database with MID:1 TID:1.
  7. A response is sent to the Smartphone POS app with MID: 1 and TID: 1. 

This mechanism allows the client to process a transaction using different merchant ID (MID) and terminal ID (TID) to transfer funds to another merchant’s account. But remember the transaction will be listed in the log with the original MID/TID.

Other points to consider:

  • If subMID and subTID aren’t sent, the transaction will progress as usual. 
  • If information is provided on the installmentCount in the custom message, the backend will take the custom message and send it directly to the host in the suitable ISO field (or other type of integration).
  • If it is not provided in the custom message, the backend will apply the default flow. For example, if you don’t provide the installmentCount, the backend can send it as 1 by default.

1.b: Log of messages returned for the payment:

The “transactionStatus” field can be:

  • success: The payment transaction was completed successfully.
  • decline: The payment transaction failed or expired. 
				
					response:
{"transactionType":"200",
"appVersion":"1.2.10",
"amount":"5000",
"maskedPan":"**** **** **** 0516",
"transactionStatus":"success",
"customMessage":"{\"isoStan\":\"001017\"}",
"refusalCode":"00",
"transactionDate":"29-11-2022 15:47:24",
"transactionId":"233394301141"}
				
			

Get the latest transaction records

				
					appLastTxn->
    {
        "appLastTxn":"1",
        "registerParameters": {
            "terminalId": "00192118",
            "merchantId": "000000009041042",
            "activationCode": "testCode"
        }
    }
				
			
				
					response:

{"appLastTxn":
"{\"transaction_id\":\"302684069304\",
\"transaction_date\":\"230126\",
\"amount\":\"700\",
\"approvalCode\":\"00\",
\"card_number\":\"0516\",
\"orderId\":\"167471801514\",
\"authorizationId\":\"00\",\
"approvedStatus\":\"1\",
\"transactionType\":\"200\",
\"stan\":\"00\",\
"txnMti\":\"00\",
\"transaction_time\":\"102726\",
\"batchNumber\":\"00\"}"}
				
			

To get the transaction log

This is the message to send from your merchant app: 

				
					{
    "listType": "3000",
    "configParameters": {
        "drawerMenu": "1",
        "salesButton": "0",
        "voidButton": "1",
        "refundButton": "1",
        "historyButton": "1",
        "settingsButton":"1",
        "tipScreen": "0",
        "userPhoto": "1"
    }
}
				
			

Other messages you may receive from the Smartphone POS app

4.a: Sample response messages: 

				
					{
    "response":
    {
        "a2aCode":"1003",
        "a2aMessage":"Register error : Server Error please contact with your administrator"
        "errorCode":"104",
        "errorMainCode":"9",
        "errorSubCode":"32"errorCode
    }
}
				
			
				
					{
    "response":
    {
        "a2aCode":"1010",
        "a2aMessage":"SoftposApp Stoped"
    }
}
				
			

Parameters and their descriptions: 

ParametersDescription
a2aCodeThe response code has been created in the SoftPos app.
a2aMessagea2aMessage is the message corresponding to the a2aCode. The backend message can be added after it.
errorCodeerrorCode returned from the backend. If an error code is received from the backend, the errorCode will not be null.
errorMainCodeerrorMainCode returned from the backend. All the error codes and explanations are available in the SoftPos SDK document.
errorSubCodeerrorSubCode returned from the backend.

4.b: Other messages and codes:

ParametersResponse messageDescription
1011The application was closed because
application was opened
standalone
The app was closed because it was opened standalone.
1010SoftposApp StoppedThe Softpos app stopped.
1007Amount cannot be alphanumeric characters, null, 0Amount cannot be alphanumeric characters, null, 0. Related to the amount sent.
1013Manual Settlement SuccessfulThe manual settlement was successful. This is returned when a manual settlement process is completed.
1009Registration SuccessfulRegistration successful.
1014Registration NeededRegistration needed. This error is returned if the required registration isn’t done.
1012Connection Error This error is returned when there is a problem with the connection.
1003Register error:There was an error during registration. The backend message can be added after it. For example: Registration error: Server error, please contact your administrator.
1006JsonParse error:If the merchant’s app message doesn’t fit the JSON structure, it will return this code and message.
1008transaction size = 0If there isn’t a transaction and you want to see the latest transaction (appLastTxn), you will get this message.
1004unregister ERROR, please try againIf you send registerParameter, the SoftPos app will void and then register. Message during unregistration.
1005Initialization error:If you receive an error during initialization, it will return this code and message. The backend message can be added after it.

Manual settlement

Request:

				
					{
    "configParameters": {
        "drawerMenu": "1",
        "salesButton": "0",
        "voidButton": "1",
        "refundButton": "1",
        "historyButton": "1",
        "settingsButton": "1",
        "settlementButton": "0",
        "tipScreen": "0",
        "userPhoto": "1"
    },
    "registerParameters": {
        "terminalId": "00000001",
        "merchantId": "000000000000011",
        "activationCode": "1"
    }
}
				
			
				
					{
    "settlementResult": true,
    "settlementResultMessage": "ACQUIRER_SETTLEMENT_SUCCESS",
    "settlementSaleCount": null,
    "settlementSaleAmount": null,
    "settlementVoidCount": null,
    "settlementVoidAmount": null,
    "batchNumber": "1713"
}
				
			
				
					{
    "errorCode": "E104",
    "internalErrorCode": 0,
    "internalErrorSubCode": 0
}
				
			

Disable registration at each payment

If the following parameters are sent in the requests, registration will be attempted automatically. To disable registration at each payment do not send these fields. Send them only in the required circumstances.

  • configParameters
  • registerParameters

Even if empty, if these fields are present the POS Smartphone will attempt to register, replacing any information already registered.

The Smartphone POS registration should only be sent in the following circumstances:

  • First payment: In cases where the app is not previously registered.
  • Error 104: Indicates that the APP is not registered. This error may occur due to a recent installation, data deletion or reinstallation of the APP.

Example of Smartphone POS integration

On the main page of this section, you can find examples.

Comparte este documento

Payment integration with Smartphone POS (Android)

Copiar el enlace

Clipboard Icon
Tabla de Contenidos

Products

  • Addon Payments
  • POS integrated Payments
  • Universal Pay

Sales

Tell us about your business so we can offer you the best solution.

Contact an expert
Contact an expert
Contact an expert
Contact an expert
Contact an expert

Technical Support

Already a client and need help? Contact us, we’re here for you.

Help

Partners

We work with the best partners for in-store and ecommerce solutions. Want to join us?

Join us

© Comercia Global Payments

Privacy policy
Exercising rights
Client information
Whistleblowing channel
Legal disclaimer
Cookies policy
Ask AI
Write your question. For example: How do I create a payment link?
SmartWiki may skip data. Verify the information or contact support.

SmartWiki, Powered by AI

API - Developers Docs
Manage cookie consent

To offer the best experiences, we use technologies such as cookies to store and/or access device information. Consent to these technologies will allow us to process data such as browsing behavior or unique IDs on this site. Failure to consent, or withdrawal of consent, may adversely affect certain features and functions.

Functional Always active
Storage or technical access is strictly necessary for the legitimate purpose of allowing the use of a specific service explicitly requested by the subscriber or user, or for the sole purpose of carrying out the transmission of a communication over an electronic communications network.
Preferences
Technical storage or access is necessary for the legitimate purpose of storing preferences not requested by the subscriber or user.
Statistics
El almacenamiento o acceso técnico que es utilizado exclusivamente con fines estadísticos. Storage or technical access that is used exclusively for anonymous statistical purposes. Without a requirement, voluntary compliance by your Internet service provider, or additional records from a third party, information stored or retrieved solely for this purpose cannot be used to identify you.
Marketing
Storage or technical access is necessary to create user profiles to send advertising, or to track the user on a website or several websites for similar marketing purposes.
Manage options Manage services Manage {vendor_count} vendors Read more about these purposes
See preferences
{title} {title} {title}

Consulta la documentación de las distintas secciones de integraciones:

Comienza a integrar

undraw_add_to_cart_re_wrdo 1 (1) (1)

Plugins para CMS

Complementa la integración

SDKs

Métodos de pago

Herramientas

Addon Payments

Consulta la documentación de Addon Payments. Aquí tienes las distintas secciones:

Integraciones

Consultas frecuentes

Portal Backoffice

Cyberpac

We are currently working on the English version of the Cyberpac documentation. You can view the Spanish version using the buttons below:

Canales BackOffice Portal

Plugins integration

Custom integrations

POS integrated Payments

Create a solution that will help you automate processes. You can even add payment processes on physical terminals.

Payment Integrated with Android POS

Payment Integrated with Smartphone POS

POS Data sheets

Addon Payments

Comercia Global Payments has several integration options so you can choose the most efficient one for you.

Integrations

Frequently Asked Questions

BackOffice Portal

Consult the documentation of the different integrations sections:​

Start integration

undraw_add_to_cart_re_wrdo 1 (1) (1)

CMS Plugins

Complement your integration

SDKs

Payment Methods

Tools