Skip to main content

Configuration API

This page provides an overview of the Configuration API methods, which is essential for the personalisation and configuration of the PhonePOS terminal. It replaces the low-level Personalisation API and adds more features in an easily accessible way.

What does Personalisation mean?

We refer to the registration and provisioning of a terminal as personalisation. When you install the PhonePOS APK/AAB or your own app with the PhonePOS SDK integrated, the app state is considered unpersonalised. A successful personalisation results in a personalised terminal, enabling it to process transactions. To get the current state of PhonePOS please query the status first.

Setup

The ConfigurationApi provides several operations for configuring a terminal. These operations will guide you through the entire process. Before initiating terminal actions, it is important to first check the terminal's status.

To use the ConfigurationApi, you must initialise a PhonePosApi instance. Refer to the example code below for guidance.

Foreground Context

To ensure the stability of the personalisation API, the instance must be initialised from a foreground context of a class that is a child of ComponentActivity.
This ensures support for the registerForActivityResult(...) function which handles the personalisation response.

Please make sure the initialisation occurs within the onCreate(...) method.

warning

To avoid terminal connection leaks, please make sure to properly destroy phonePosApi instance by calling phonePosApi.onDestroy(Context) in onDestroy callback of the Activity (or any other place if applicable).

After destroying the phonePosApi instance it can not be reused. Please create a new one if needed.

public class PhonePosApiActivity extends AppCompatActivity {

private ActivityResultLauncher<Intent> personalizationLauncherV4;
private PhonePosApi phonePosApi;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

phonePosApi = PhonePosFactory.getPhonePosApi(getPhonePosApplicationId(), PhonePosApiActivity.this);
/*
Important: the personalizationLauncherV4 needs to be initialised in the onCreate function of the class
*/
personalizationLauncherV4 = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), phonePosApi.getConfigurationApi());
}

@Override
protected void onDestroy() {
super.onDestroy();
phonePosApi.onDestroy(this);
phonePosApi = null;
}

//,,,
private String getPhonePosApplicationId(){
/*
* For proper functionality of PhonePosApi, return the appropriate applicationId:
*
* - If using the PhonePOS APK/AAB:
* Return the applicationId of the PhonePOS app.
* Ensure the "query" parameter in your AndroidManifest is set correctly.
* Refer to the APK setup chapter for additional details.
*
* - If using the PhonePOS SDK:
* Return the applicationId of your own app.
*
* It is critical to return the correct value here, as the PhonePosApi will NOT work otherwise.
*/
return "your_phone_pos_application_id"; // Replace with your applicationId
}

}

Getting Terminal Status

Once you have obtained an instance of the personalisation, the next step is to check the terminal's status.
To do this, use the configurationApi.getStatus(...) method and handle the response via the PersonalisationStatusCallback.

The code snippet below demonstrates how to initiate this call and handle its response.

Already Setup?

If the terminal is already set up and returns STATUS_TERMINAL_OPERATIONAL, Please check out the internal error list coming with the response. PhonePOS may respond app update reminder. The reminder will still let you use the terminal, but getting one is the indication that PhonePOS will soon be outdated and needs to be updated before that.

public class PhonePosApiActivity extends AppCompatActivity {
//...

protected void getPhonePosStatus() {
phonePosApi.getConfigurationApi().getStatus(PhonePosApiActivity.this, (terminalState, terminalErrorMessage) -> {
switch (terminalState){
case STATUS_TERMINAL_OPERATIONAL:
/*
This state means that terminal is configured and fully operational. Transactions can be made!
*/
if(terminalErrorMessage.isUpdateReminder()){
// Display to the user that a new version of the terminal is available. Please ask them to update as this message usually indicates that soon current version will be outdated.
}

break;
case STATUS_APP_IS_OUTDATED:
/*
Current version of the Terminal is outdated. Unless the app is updated all transaction operations will be blocked.
*/
break;
case STATUS_PERSONALIZATION_NOT_DONE_YET:
/*
Terminal is installed but NOT configured. Please ask merchant to perform personalisation process.
Please take a look at ConfigurationApi.startPersonalisation(...).
*/
break;
case STATUS_PERSONALIZATION_IN_PROGRESS:
/*
Personalisation is in progress and should NOT be interrupted. Please wait for the process to be over.
*/
break;
case STATUS_TERMINAL_NOT_OPERATIONAL:
/*
In this scenario, terminal is blocked for various reasons. TerminalErrorMessage will give you more
details about why.
Within TerminalErrorMessage.InternalError there are several well known reason why the blockage happened.
Please see below:
*/
switch (terminalErrorMessage.getReason()){
case BATTERY_LOW:
/*
BATTERY_LOW indicates that phone battery is too low for Terminal to function as expected.
Please update the user to charge the phone before continuing.
*/
break;
case INIT_FAILED:
/*
This scenario occurs when there is connection problem with the PhonePOS Server,
Please make sure the connection is stable and afterward trigger ConfigurationApi.recoverTerminal(...) function.
If the problem still persists, please contact to PhonePOS support if such case arises.
*/
case TERMINAL_CONNECTION_FAILURE:
/*
This case indicates that the connection to the terminal could NOT have been established, or it got broken.
Please make sure that PhonePOS is installed and your application has visibility to one. Most
probable reasons for application visibility problem is incorrectly defining PHONE_POS_APPLICATION_NAME or missing
<queries> in manifest file.
*/

case UNKNOWN:
case NONE:
/*
This case should NOT occur with normal process, please contact PhonePOS support if it does.
Please also provide the value for terminalErrorMessage.getErrorCode() in these scenarios
*/
break;
}
break;
}
// Logging
log("TerminalState = " + terminalState.name() + ", statusCode = " + new GsonBuilder().create().toJson(terminalErrorMessage));
});
}
}

STATUS_PERSONALIZATION_NOT_DONE_YET status indicates that the terminal is NOT configured yet. In this case a personalisation should be performed, otherwise transaction operations will NOT be possible.

Personalisation

Multiple methods are available to personalise a terminal, catering to different use cases.
Before selecting a personalisation method, note that some methods have specific prerequisites, such as an MDM (Mobile Device Management) environment.

Enabling/Disabling Personalisation Methods

The availability of a personalisation method for a given TID is determined by the onboarding process via ROS (Rubean Onboarding Service). Some methods are one-time only and require reactivation after use. The reactivation process may vary depending on the method, with different limits applying.

To re-enable a method, you might need to submit an over-boarding or reactivation request.

Automation of ROS Onboarding

In adherence to PCI guidelines, ROS onboardings must never be performed directly from the device.

Building PersonalisationDataProvider

To accommodate various scenarios and requirements, we support different types of personalisation. These methods are tailored to your specific needs, and you can select the appropriate personalisation type by using the DataProviderFactory. Refer to the DataProviderFactory and choose the type that aligns with your use case.

Personalisation Type availability

Not all personalisation types are supported by default. Each TID is assigned one or more types according to the onboarding performed with ROS. If you are unsure which types are available for you, please contact the PhonePOS support for clarification.

note

The DataProviderFactory class is part of the PhonePOS API library. Do NOT copy or attempt to duplicate the class.

public class DataProviderFactory {
public DataProviderFactory() {
}

/*
The methods that accept a list of otpServiceTypes always try to pick the top otp method.
If that is not available am automatic fallback to a lower method is performed.
*/

/*
Creates a PersonalisationDataProvider for scenario when terminalId and password are the main source of input.
"otpServiceTypes" specifies list of types of two-factor authentication you are willing to use.

NOTE: please make sure PhonePOS application provided for you supports chosen OtpServiceTypes
*/
public static PersonalisationDataProvider createProviderForTidAndPassword(String tid, String password, List<OtpServiceType> otpServiceTypes);

/*
Creates PersonalisationDataProvider for automated enrolment.
This method is only available in an MDM environment which additionally identifies the device.
*/
public static PersonalisationDataProvider createProviderForAutomatedEnrolment(String externalDeviceId, String token) {
return new PersoDataWithAutomatedEnrolment(externalDeviceId, token);
}

/*
Creates PersonalisationDataProvider which supports two-factor authentication.
The second factor (OTP) is automatically sent to the user and needs to be supplied in the following PhonePOS activity.
*/
public static PersonalisationDataProvider createProviderForTidAndOtp(String tid, List<OtpServiceType> otpServiceType) {
return new PersoDataWithTidAndOtp(tid, otpServiceType);
}

/*
Creates PersonalisationDataProvider for fuc and idCommerce scenario.
The second factor (OTP) is automatically sent to the user and needs to be supplied in the following PhonePOS activity.
*/
public static PersonalisationDataProvider createProviderForFucIdCommerceAndOtp(String fuc, String idCommerce, List<OtpServiceType> otpServiceType) {
return new PersoDataWithFucIdCommerceOtp(fuc, idCommerce, otpServiceType);
}

/*
Creates PersonalisationDataProvider for scenario when terminalId and password inputs are managed by PhonePOS UI.
*/
public static PersonalisationDataProvider createProviderForTidPasswordUiInput() {
return new PersoDataForDefaultUi();
}

public enum OtpServiceType {
SMS,
MAIL,
NONE;
}
}

Addition of configuration options

PhonePOS supports an array of options that can be passed with the PersonalisationDataProvider in the Personalisation. The PersonalisationOptions object can be added via .setOptions(...)to the PersonalisationDataProvider. You don't have to set all presented options but only the ones you need. Not set values are always set to the default option.

// Generate the provider with a personalisation method of your choosing
PersonalisationDataProvider provider = DataProviderFactory.createProviderFor...();

PersonalisationOptions options = new PersonalisationOptions();

// Sets the desired screen orientation for the personalization process and terminal display.
// Options are: PORTRAIT (default), LANDSCAPE
options.setScreenOrientation(PersonalisationOptions.ScreenOrientation.PORTRAIT);

// Sets attestation provider to Play Integrity. Please note that picking ZIMPERIUM_ZDEFEND will generate additional license fees.
// Options are GOOGLE_PLAY_INTEGRITY (default), ZIMPERIUM_ZDEFEND
options.setAttestationProvider(PersonalisationOptions.AttestationProvider.GOOGLE_PLAY_INTEGRITY);

// Sets the nfc reader platform sound to enabled (default) or disabled.
// With this option enabled you will hear two sounds:
// One when the card is presented (by the system itself) and one when the card is fully read (from the terminal)
// With this option disabled you will only hear one sound:
// When the card is fully read (from the terminal)
options.setNfcReaderPlatformSoundsEnabled(true);

// Defines the styling of the PhonePOS personalisation.
// You can reset the style to default by supplying a null value
// Please refer to the chapter "Updating the theme" lower on this page for more details.
PhontePosTheme theme = new PhonePosTheme();
theme.day; // customize theme here
options.setAppTheme(theme);

// Enables or disables (default) the deep link api.
// Please refer to https://docs.phonepos.online/docs/phonepos-apk-sdk/integration/apis/deep-link-api/ for more information about this API
options.setDeepLinkApiEnabled(false);

// New feature, available from PhonePOS 3.16.X and up
// Enables or disables (default) the support for secondary display devices.
// This feature addresses devices that offer two displays.
// The one facing the customer should, with this option enabled, show the terminal screen.
options.setSecondaryDisplayEnabled(false);

// New feature, available from PhonePOS 3.16.X and up
// Defines the position of an additional image that signals the position of the nfc reader.
// Options are: NO_IMAGE (default), POSITION_LEFT, POSITION_RIGHT
// Please enable this feature only on devices that are configured in landscape mode and offer a sufficiently large screen.
// Otherwise, you might get misaligned images in the terminal.
options.setNfcImagePosition(PersonalisationOptions.NfcImagePosition.NO_IMAGE);

// New feature, available from PhonePOS >= 4.14.X and High-Level PhonePOS API >= 2.17.4
// Defines a preferred terminal/personalisation and transaction language.
// TransactionLanguage.NONE defaults the language to the following:
// for personalisation -> system language
// for transaction -> language in backend terminalId configuration
options.setLanguage(TransactionLanguage.ES);

Starting the Personalisation process

At this stage you should already have checked the status of the terminal and it should have shown you that the terminal is NOT personalised yet. The process can be started for the merchant by calling: startPersonalisation(...) function:

note

PhonePOS transaction screens supports both LANDSCAPE and PORTRAIT orientation. In case you want to specify the orientation you can use PersonalisationDataProvider.setOptions(...) function. Please see the example below.


public class PhonePosApiActivity extends AppCompatActivity {

// ...

public void startPersonalisation(Intent intent) {
PersonalisationDataProvider provider = provideTerminalData(intent);
phonePosApi.getConfigurationApi().startPersonalisation(
provider, PhonePosApiActivity.this, new PersonalisationCallback() {
@Override
public void onPersonalisationSuccess() {
/*
The callback indicates that personalisation process went successfully. This means that
transactions are possible, and you can trigger Transactions with the TransactionAPI
*/

log("personalisation finished successfully");
}

@Override
public void onPersonalisationFailed(@NotNull PersonalisationResult personalisationResult, @NotNull PersonalisationFailureReason personalisationFailureReason) {
switch (personalisationResult) {
case PERSONALIZATION_FAILED:
switch (personalisationFailureReason){
case PHONEPOS_IS_OUTDATED:
log("Failed because phonepos application is outdated. Please updated the application and retry the process.");
break;
case EMAIL_SENDING_FAILED:
log("Failed because confirmation was requested by e-mail but could NOT be delivered.");
break;
case SMS_SENDING_FAILED:
log("Failed because confirmation was requested by sms but could NOT be delivered.");
break;
case EMAIL_VERIFICATION_TIMEOUT_SERVER:
log("Failed because the confirmation timeout reached on the server.");
break;
case TID_ALREADY_PERSONALIZED:
log("Failed because the terminal with requested id is already personalised. Please off-board the terminal in use before retrying.");
break;
case CLIENT_DOES_NOT_EXIST:
log("Failed because the no entry found for the terminal credentials provided, please provide correct credentials.");
break;
case BATTERY_TOO_LOW:
log("Failed because phone battery is too low for continuing the personalisation process. Please recharge and retry");
break;
case INVALID_CREDENTIAL_FORMAT:
log("Failed because credentials were provided in an incorrect format, Please make sure the PhonePOS solution is supporting current format used.");
break;
case TERMINAL_CONNECTION_FAILURE:
log("Failed because the connection with terminal couldn't be established, Please make sure working PhonePOS application is installed on your device and you have correct visibility declared in manifest.");
break;
case CANCELLED_BY_USER:
log("Failed because User requested the cancellation of the process.");
break;
case PROCESS_WAS_TERMINATED:
log("Failed because the process was terminated. Most probable reason is that it was forcefully killed either by the system or the user");
break;
case PHONEPOS_ALREADY_PERSONALISED:
log("Failed because PhonePOS already has an active terminal. In case you wish to change the user, please do RESET first.");
break;
case PHONEPOS_PERSONALISATION_IN_PROGRESS:
log("Failed because PhonePOS personalisation is already in progress. Please let the process finish as parallel personalisation is NOT allowed. " +
"If you wish to restart the process, please use RESET first. Alternatively, if you wish to re-attach to the process, please use reattachToPersonalisationProcess(...) function.");
break;
case INVALID_OTP:
log("Failed because the OTP provided was invalid. Please make sure you are using a valid OTP.");;
break;
case INVALID_CREDENTIALS:
log("failed because invalid credentials were provided for personalisation.");
break;
case EMV_UPLOAD_DENIED_FOR_SECURITY_REASONS:
log("Terminal was not able to upload EMV data due to security reasons. Please contact PhonePOS support for assistance.");
break;
case EMV_UPLOAD_FAILED:
log("Terminal was not able to upload EMV, the reason is unknown. Please do a terminal recovery, or contact PhonePOS support for assistance.");
break;
case NETWORK_UNSTABLE:
log("Network was unstable during the personalisation process. Please try again later.");
break;
case NETWORK_UNAVAILABLE:
log("Network was unavailable during the personalisation process. Please try again later.");
break;
case INVALID_JSON:
log("Failed because incorrect format was provided to phonePOS, please make sure you are sending valid data");
break;
case OTP_TYPE_NOT_AVAILABLE:
log("OTP type is not available for the terminal. Please make sure the terminal supports the OTP type you are trying to use.");
case INVALID_OTP_TYPE:
log("Invalid OTP type was provided. Please make sure you are using a valid OTP type.");
break;
case INTERNAL_TERMINAL_CONNECTION_TIMEOUT:
log("Failed because the connection with terminal timed out. Please make sure the internet connection is stable and working properly. If the error persists, please contact PhonePOS support for assistance.");
break;
case BAD_HTTP_CODE:
log("Failed because the server returned an unexpected HTTP code. Please check the server logs for more details or contact PhonePOS support for assistance.");
break;
case SERVER_TOO_BUSY:
log("Failed because the server was too busy to process the request. Please try again later.");
break;
case UNKNOWN:
/*
The reason of failure is not clear. Usually this means that PhonePOS API needs to be updated.
Please check and provide statusCode for further investigations and contact PhonePOS team for assistance.
*/
log("Failed but the reason couldn't be specified. The statusCode for the failure is = " + personalisationFailureReason.getStatusCode());
break;
}
break;


case ANOTHER_PERSONALIZATION_IN_PROGRESS:
/*
The Personalisation process was already initiated and is in progress. New personalisation process can NOT be started while the old one is still in progress.
*/
break;
case RECOVERY_NEEDED:
/*
In this scenario, Personalisation process was finished but the payments are not possible.
This occurs in cases of connection failures in the last stage of PhonePOS and
CAN be recovered by sending terminalRecover(...) call in the ConfigurationApi.
*/

break;

case TERMINAL_OPERATIONAL:
/*
Result code indicating that the terminal was successfully personalised.
This will not be returned in case of failed personalisation and can be ignored
*/
break;
}
log("personalisation failed with status = " + personalisationResult.name() + ", and with status code = " + personalisationFailureReason.getStatusCode());
}

@Override
public void startActivityForResult(@NonNull Intent intent) {
personalizationLauncherV4.launch(intent);
}
}
);
}

private PersonalisationDataProvider provideTerminalData(){
PersonalisationDataProvider provider = getDataProvider();
/*
In case you want to specify an orientation in which the transaction screen needs to appear,
you can set options to the provider class.
*/
provider.setOptions(getSdkOptions());
return provider;
}

private PersonalisationOptions getSdkOptions(){
PersonalisationOptions sdkOptions = new PersonalisationOptions();
sdkOptions.setScreenOrientation(PersonalisationOptions.ScreenOrientation.LANDSCAPE); // sets PhonePOS orientation to LANDSCAPE
//sdkOptions.setScreenOrientation(PersonalisationOptions.ScreenOrientation.PORTRAIT);
return sdkOptions;
}

private PersonalisationDataProvider getDataProvider(){
// Please choose and return applicable function from DataProviderFactory.
}

}


Reattach To Personalisation Process

note

This api is only available in PhonePOS api version 2.18.8 and higher.

In case you lost the connection to the PhonePOS personalisation process and you receive PERSONALISATION_IN_PROGRESS as the result of getStatus(...) function, You need to re-attach to the personalisation process, or cancel the current personalisation and re-start the new one. To cancel the current personalisation process, use the reset(...) function. To re-attach to the personalisation process, you can use the reattachToPersonalisationProcess(...) function (which will send a CONTINUE_PERSONALISATION command). This function will return the PersonalisationResult of the active personalisation process. The setup for the reattaching should be the same as for the personalisation process, except PersonalisationDataProvider does not need to be specified. Please take into note that "personalizationLauncherV4.launch(intent);" this line is still crucial for the reattaching process. Handling of the callbacks is also the same as for the personalisation process. Except several results. In this case you will not receive the ANOTHER_PERSONALIZATION_IN_PROGRESS result. In case you request reattaching when no personalisation process is in progress, you will receive Failure with the reason INVALID_CREDENTIALS.

public class PhonePosApiActivity extends AppCompatActivity {

// ...

public void reattachToPersonalisationProcess() {
phonePosApi.getConfigurationApi().reattachToPersonalisationProcess(PhonePosApiActivity.this, new PersonalisationCallback() {
@Override
public void onPersonalisationSuccess() {
log("personalisation finished successfully");
}

@Override
public void onPersonalisationFailed(@NotNull PersonalisationResult personalisationResult, @NotNull PersonalisationFailureReason personalisationFailureReason) {
// Please refer to the example above in startPersonalisation section for the explanation of the failure codes.
log("personalisation failed with status = " + personalisationResult.name() + ", and with status code = " + personalisationFailureReason.getStatusCode());
}

@Override
public void startActivityForResult(@NonNull Intent intent) {
personalizationLauncherV4.launch(intent);
}
}
);
}

}


Reset the terminal

If you want to stop the transaction process on a terminal, the RESET function can be used. Before you process further please wait for the callback in onResetFinished.

warning

This function is supported for PhonePOS versions from 3.14.02.18 and newer. Prior to that PhonePOS did NOT support callbacks for reset operations. As a fallback solution for PhonePOS version 3.13.X and below, you will get a callback after a timeout with a negative reset result (as no callback is sent). It is highly recommended to use PhonePOS version 3.14.02.18 and above if you use the reset functionality. In case you are using older versions, please call the "getStatus" method manually to clarify whether the reset was successful or not.


public class PhonePosApiActivity extends AppCompatActivity {
//...
private PhonePosApi phonePosApi;
//...

private void resetTerminal(){
phonePosApi.getConfigurationApi().reset(
PhonePosApiActivity.this,
new PersonalisationResetCallback() {
@Override
public void onResetFinished(boolean wasResetSuccess) {
// If reset was NOT successful please use "getStatus(...)" function before repeating the operation.
// This value can be false in rare cases, when the Android system itself does NOT behave as expected
// and the system is stuck.
// This function will under normal operation always return true.
}
}
);

}
}

Getting SDK Info

SDK Info will provide you with information about the phonepos version and the currently personalised terminalId. In case PhonePOS app is NOT installed or could NOT be connected to personalisationInfo.terminalWasConnectedSuccessfully will be false. In which scenario personalisationInfo.sdkGeneralInfo will be null and personalisationInfo.terminalId will be empty. In case the PhonePOS app could be connected but NOT personalised the terminal id will be empty but personalisationInfo.sdkGeneralInfo.version still will be received.

public class PhonePosApiActivity extends AppCompatActivity {

//...
private PhonePosApi phonePosApi;

//...

private void getSdkInfo(){
phonePosApi.getConfigurationApi().getSdkInfo(MainActivity.this, new SdkInfoCallback() {
@Override
public void onRetrievedSdkInfo(PersonalisationInfo personalisationInfo) {
boolean successfullyConnectedToPhonePos = personalisationInfo.terminalWasConnectedSuccessfully;
if(successfullyConnectedToPhonePos){
String terminalId = personalisationInfo.terminalId;
String phonePosVersion = personalisationInfo.sdkGeneralInfo.version;
}else{
// no data could be received as PhonePOS connection failed. Please check if PhonePOS is installed and you have sufficient <queries> for the application.
}
}
});
}
}

Terminal Recovery

New feature

Available from PhonePOS version 3.14.01.17 and up.

In case PhonePOS is already personalised but the payment process is corrupted, you can use TerminalRecovery operation.

public class PhonePosApiActivity extends AppCompatActivity {

///...
private PhonePosApi phonePosApi;

///...

public void recoverTerminal() {
phonePosApi.getConfigurationApi().recoverTerminal(new TerminalRecoveryCallback() {
@Override
public void onStatusReady(TerminalState terminalState, TerminalErrorMessage terminalErrorMessage) {
switch (terminalState) {
case STATUS_TERMINAL_OPERATIONAL:
/*
This state means that terminal is configured and fully operational. Payments can be made!
*/
break;
case STATUS_APP_IS_OUTDATED:
/*
Current version of the Terminal is outdated. Unless the app is updated all payments operations will be blocked.
*/
break;
case STATUS_PERSONALIZATION_NOT_DONE_YET:
/*
Terminal is installed but NOT configured. Please ask merchant to perform personalisation process.
Please take a look at ConfigurationApi.startPersonalisation(...).
*/
break;
case STATUS_PERSONALIZATION_IN_PROGRESS:
/*
Personalisation is in progress and should NOT be interrupted. Please wait for the process to be over.
*/
break;
case STATUS_TERMINAL_NOT_OPERATIONAL:
/*
In this scenario, terminal is blocked for various reasons. TerminalErrorMessage will give you more
details about why.
Within TerminalErrorMessage.InternalError there are several well known reason why the blockage happened.
Please see below:
*/
switch (terminalErrorMessage.getReason()) {
case BATTERY_LOW:
/*
BATTERY_LOW indicates that phone battery is too low for Terminal to function as expected.
Please update the user to charge the phone before continuing.
*/
break;
case INIT_FAILED:
/*
This scenario occurs when there is connection problem with the PhonePOS Server,
Please make sure the connection is stable and if the problem still persists, please contact to PhonePOS support.
*/
case TERMINAL_CONNECTION_FAILURE:
/*
This case indicates that the connection to the terminal could NOT have been established, or it got broken.
Please make sure that PhonePOS is installed and your application has visibility to one. Most
probable reasons for application visibility problem is incorrectly defining PHONE_POS_APPLICATION_NAME or missing
<queries> in manifest file.
*/

case UNKNOWN:
case NONE:
/*
This case should NOT occur with normal process, please contact PhonePOS support if it does.
Please also provide the value for terminalErrorMessage.getErrorCode() in these scenarios
*/
break;
}
break;
}
}
}, this);
}
}

Update configuration options after personalisation

The prefered way of settings configuration options is during the personalisation.
Below is a list of which parameters can be updated at what point in time. This may be subject to change.

OptionPersonalisationAfter Personalisation
attestationProvider
screenOrientation
nfcReaderPlatformSoundsEnabled
nfcImagePosition
secondaryDisplayEnabled
appTheme
terminalTheme
deepLinkApiEnabled
language

Update orientation

You can use the phonePosApi.getConfigurationApi().updateOptions(...) function to update the orientation. The response is returned in the function OptionUpdateCallback.onFinished(boolean isSuccess) where isSuccess indicates whether the orientation for the phonePos app has been successfully updated.

Reboot required

The terminal needs to be rebooted to pick up this option change. We recommend to restart the device to avoid any confusion on the user side.

public class PhonePosApiActivity extends AppCompatActivity {

///...
private PhonePosApi phonePosApi;

///...

/*
PhonePOS supports ScreenOrientation update and works in both LANDSCAPE and PORTRAIT modes.
updateOrientation will help you to change orientation if needed.
*/
@Override
protected void updateOrientation(SdkOrientation newOrientation) {
PersonalisationOptions.ScreenOrientation screenOrientation = PersonalisationOptions.ScreenOrientation.PORTRAIT;
if (newOrientation == SdkOrientation.LANDSCAPE) {
screenOrientation = PersonalisationOptions.ScreenOrientation.LANDSCAPE;
}

PersonalisationOptions options = new PersonalisationOptions();
options.setScreenOrientation(screenOrientation);
phonePosApi.getConfigurationApi().updateOptions(options, isSuccess -> log("phonepos app orientation update finished with success = " + isSuccess));
}
}

Updating the theme

New feature

Available from PhonePOS version 3.12.01.11 and up

PhonePOS can be themed by sending a JSON stylesheet. Themes can be configured anytime in the process and are permanently stored within PhonePOS until the next theme update.

Communication

To define a new theme you have to instantiate the PhonePosTheme class and define the theming options. Submit the PhonePosTheme object to the updateTheme(...) function will apply the theme. If you wish to leave certain elements, such as the navigation bar color, unchanged, simply omit the corresponding entries. Keep in mind that boolean values default to false. Currently only the day theme is supported. Available options are:

public class PhonePosTheme {
@SerializedName("day")
private Stylesheet day;

@Data
@Builder(setterPrefix = "with")
private static class Stylesheet {
// custom logo shown on activation screen (PNG/JPG in base64 encoding)
@SerializedName("activationLogoEnabled")
public boolean activationLogoEnabled;

@SerializedName("logoBase64")
public String logoBase64;

@SerializedName("colorAccentAnimation")
public String colorAccentAnimation;

@SerializedName("colorButton")
public String colorButton;

@SerializedName("colorButtonText")
public String colorButtonText;

@SerializedName("colorStatusBar")
public String colorStatusBar;

@SerializedName("colorNavigationBar")
public String colorNavigationBar;

@SerializedName("colorActionBar")
public String colorActionBar;
}
}
Reset behaviour

Please note that the theming settings are not affected by the reset function. If you want to reset the theme to the default, please call the same updateTheme method again with an instantiated style object but no values.

Request changes

If the design options are not sufficient for your use case, you can contact our support team and we will analyse further proceedings.

public class PhonePosApiActivity extends AppCompatActivity {

///...
private PhonePosApi phonePosApi;

///...

@Override
protected void updateTheme(PhonePosTheme appTheme) {
phonePosApi.getConfigurationApi().updateTheme(appTheme, result -> log("theme updated successfully = " + new GsonBuilder().create().toJson(result)));
}
}

Showing Status and Settings

New feature

Available from PhonePOS version 4.01.11.0156 and up

The showStatusAndSettings(Context) function in the Configuration API launches the main PhonePOS activity. It can be used to:

  • Display the current terminal status and version to users (if the terminal is already personalized)
  • Provide access to the settings screen for debugging purposes

Its return value indicates if the action was successful.

public class PhonePosApiActivity extends AppCompatActivity {

///...
private PhonePosApi phonePosApi;

///...

public void showStatusAndSettings() {
if(!phonePosApi.getConfigurationApi().showStatusAndSettings(this)) {
// failure, is a supported PhonePOS version installed?
}
}
}

Session Management

New optional feature

Available from PhonePOS SDK version 4.01.15.0200 and up & High-Level PhonePOS API version 2.19.0 and up

Sessions are an optional, JWT-based feature used to restrict terminal functionality to predefined timeframes. Integrators are required to issue and manage tokens by themselves. If you would like to use this feature, please contact our Integrator Support Team for further guidance.

Overview

The following diagram illustrates the high-level logic for PhonePOS sessions:

Notes:

  • Set the enforceSession flag to true when executing create, update, or amend in ROS to activate this feature for your terminal.
  • A valid session must be established before starting the terminal personalization
  • To establish/extend a session, setSessionToken can be called no matter the current session's validity
  • If a session expires on a working terminal, its status transitions from TERMINAL_OPERATIONAL to TERMINAL_NOT_OPERATIONAL with reason code SESSION_EXPIRED

Creating a Session Token

The creation of the session token needs to happen on your backend system. Please get in touch with our Integration Support Team for further details.

Setting a Session Token

Update the terminal session by passing a valid token to the setSessionToken method.

phonePosApi.getConfigurationApi().setSessionToken(token, new SetSessionTokenCallback() {
@Override
public void onSetSessionTokenSuccess(SessionInfo info) {
info.isEnforced(); // True if sessions are required
info.isValid(); // True if the current session is active
info.getRemainingMs(); // Remaining validity in milliseconds
info.getExpiresAtElapsedRealtimeMs(); // Precise SystemClock.elapsedRealtime() expiry time
info.getExpiresAtUtc(); // Current device's wall-clock-based expiry time (UTC)

// Since SessionInfo internally uses the android monotonic clock, you can track the
// respective session state with this object for the lifetime of your app
}

@Override
public void onSetSessionTokenFailure(SessionError error) {
switch (error.getError()) {
case INVALID_TOKEN:
// Invalid token structure / content
break;
case TOKEN_ALREADY_EXPIRED:
// Token expiration time has already passed
break;
case SESSION_NOT_FOUND:
// Token claim points to non-session-enabled or non-existent terminal
break;
case NETWORK_UNSTABLE:
case NETWORK_UNAVAILABLE:
// Connection issues; suggest retry or check network
break;
case TERMINAL_CONNECTION_FAILURE:
// PhonePOS SDK unreachable (check plugin installation or OS restrictions)
break;
default:
// Use error.getInternalErrorCode() for support inquiries
}
}
}, context);
warning

Please be aware that if you execute a ROS create or update request, the sessions for your terminal will be stopped in the backend. You then need to execute setSessionToken on the client again to recreate the session in the backend. This is a security feature to prevent old session tokens from influencing new terminal entries. A ROS amend request does not stop the session in the backend.

Retrieving Session Information

Use getSdkInfo to check the current session status and remaining validity.

phonePosApi.getConfigurationApi().getSdkInfo(context, sdkInfo -> {
final SessionInfo sessionInfo = sdkInfo.sessionInfo;
// See handling of sessionInfo in onSetSessionTokenSuccess callback of setSessionToken
});

Logging

The PhonePOS ecosystem contains two log sources: PhonePOS SDK/APK and PhonePOS API. For debugging purposes, it is highly recommended to implement the following two features of handling PhonePOS logs below:

SDK Log Submission

SDK logs are not not directly accessible. However, for troubleshooting purposes, they can be submitted to our support. While it is possible to submit SDK logs through UI within the settings page (see here), the SDK log submission can also be requested from the API. Please take a look at submitPhonePosLogs() in the code example below.

Enabling PhonePOS API logs

As the PhonePOS API is part of the integrator's infrastructure, we (as Rubean) are not saving or controlling the logging. Nevertheless, there is an independent API which enables you, the integrator, to receive any logs that accumulate in the PhonePOS API. Those logs can then be transferred to your local logging infrastructure. To enable API logs, setup a PhonePosApiLogger instance and all the logs from PhonePOS API will be delivered in its callback. Please take a look at addLoggerToPhonePosApi() in the code example below.

public class PhonePosApiActivity extends AppCompatActivity {

///...
private PhonePosApi phonePosApi;

///...

private void submitPhonePosLogs() {
phonePosApi.getConfigurationApi().submitTerminalLogs(this,
new SubmitTerminalLogsCallback() {
@Override
public void onSubmissionSuccess() {
// PhonePOS team now can review the submission.
}

@Override
public void onSubmissionFailure() {
// submitting logs failed, Please ask the merchants to retry with a delay.
}

@Override
public void onSubmissionRateLimitReached(long remainingMs) {
// submitting logs failed, Please ask the merchants to retry with a delay.
}
}
);
}

private void addLoggerToPhonePosApi(){
PhonePosApiLogging.addLogger(new PhonePosApiLogger() {
@Override
public void onNewOutput(String tag, String value) {
Log.d(tag, value);
}
});
}

}

Device Compatibility

DeviceCompatibility check performs checks most common issues that users face which causes personalisation to fail and can be avoided.
Api produces DeviceCompatibilityReport which contains information of how compatible is the device state with PhonePOS. Each of the fields of the report is CompatibilityStatus object, indicating if the check is passed, failed or unable to verify.

CompatibilityStatus.SUCCESS - The check passed and is acceptable by PhonePOS.

CompatibilityStatus.FAILURE - The check failed and will not be accepted. In case of the development build types, some check failures can be ignored.

CompatibilityStatus.UNKNOWN - The check could NOT be performed and the result of PhonePOS behaviour can NOT be predicted. This does NOT mean PhonePOS will be inoperable.

Please take a look at the implementation below for more details.

warning

Compatibility api does NOT guarantee that PhonePOS process can will be successful but produces a list for most of the common problems that can be addressed by the user via changing the phone settings and/or updating outdated android versions.

public class PhonePosApiActivity extends AppCompatActivity {

///...
private PhonePosApi phonePosApi;

///...

private void onGetUsabilityClicked() {
phonePosApi.getConfigurationApi().getDeviceCompatibilityReport(this, new DeviceCompatibilityCallback() {
@Override
public void onReportReady(DeviceCompatibilityReport deviceCompatibilityReport) {
/*
deviceCompatibilityReport.showTipsOptions:
Result: Shows if the user has tips enabled.
Fix: Please ask the user to turn it off in the developer options

deviceCompatibilityReport.pointerLocation
Result: Shows if the user has pointer location enabled.
Fix: Please ask the user to turn it off in the developer options

deviceCompatibilityReport.keyAttestationResult
Result: Shows if the android key attestation failed to pass the security check.
Fix: Failing this check means that the phone security is either outdated or has some malware.


deviceCompatibilityReport.isNfcSupportedByDevice
Result: Checks if NFS is supported by a device.
Fix: PhonePOS solution uses NFC for payments. Without NFC transactions will NOT be operational.

deviceCompatibilityReport.isNfcEnabled
Result: Shows if the NFC usage is enabled on a device.
Fix: Please ask the user to enable the feature to be able to make transactions.

deviceCompatibilityReport.adbShouldBeDisabled
Result: Shows if the user has usb or remote debugging enabled.
Fix: Please ask the user to turn it off as PhonePOS does NOT allow process to continue in case of active debugging.

deviceCompatibilityReport.isAndroidVersionSupported
Result: Shows if the android version is Compatible with minimum supported version of PhonePOS.
Fix: PhonePOS will not be functional unless updated to minimum supported version.

deviceCompatibilityReport.isBatteryLevelOkay
Result: Shows if the battery charge level is sufficient for PhonePOS processes.
Fix: Please ask the user to charge the phone before continuing.

deviceCompatibilityReport.isGooglePlayServicesPresent
Result: Shows if the phone supports google play services.
Fix: PhonePOS supports stable solution also for phones without Google Play Service, but this feature should be enabled for the customers. Please contact PhonePOS support team.
*/
}
});
}
}
UserExistence Api (Deprecated)

Checking if client exists in system

warning

This api is deprecated for removal!
Please do NOT use it if not otherwise communicated.

Before starting the personalisation you can check if the user is eligible for the functionality. This can be done by using ConfigurationApi.checkIfUserExists api.

public class MainActivity extends AppCompatActivity {
// ...

private void checkUserExistence(){
PersonalisationDataProvider provider = provideTerminalData();
phonePosApi.getConfigurationApi().checkIfUserExists(
provider,
MainActivity.this,
new UserExistenceCallback() {
@Override
public void onUserExists(boolean userExists) {
// handle the response
}
}
);
}

private PersonalisationDataProvider provideTerminalData(){
/*
Please choose applicable function from DataProviderFactory above.
*/
}
}