Skip to content

App to app

Android

This section describes the steps required to perform an “app to app” call on Android applications. The technical development process consists of 3 different steps:

Step 1: Create an intent to call mPOS
Step 2: Define the object class MessageToSend
Step 3: Get a response from mPOS
Step 1: Create an intent to call mPOS

Communication with the mPOS application is done by using Android intents. This means that the call to the mPOS by an Android app is made through an Intent which contains a bundle with the required information for the transaction.

The data sent to the mPOS can be found in the following code sample:

private Intent createPendingIntent(String reference, String value){
    Intent launchIntent = new Intent();

    //Package of Smartpos that will be called
launch.Intente.setClassName(“pt.sibs.android.mpos.sibsPagamentosQly”,”pt.sibs.android.mpos.activities.MainActivity”);

    TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
    stackBuilder.addNextIntent(launchIntent);

    // create a json with value and reference
    MessageToSend messageToSend = new MessageToSend();
    value? value.replaceAll(“[^\\d.]”, ””);
    messageToSend.setAmount(value);
    messageToSend.setReference(reference);
    Gson gson = new GsonBuilder().create();
    String message = gson.toJson(messageToSend,MessageToSend.class);

    // create json to a Base64
    byte[] bytes;
    bytes = message.getBytes(StandardCharsets.UTF_8);
    String base64msg = Base64.encodeToString(bytes, Base64.DEFAULT);

    // create a bundle and intent to call mpos and send data over
    Bundle data = new Bundle();
    data.putString(PACKAGE_ID, BuildConfig.APPLICATION_ID);
    data.putBoolean(REQUEST RESPONSE, sw.isChecked());
    data.putBoolean(BYPASS_INSERT_VALUE, bypassSw.isChecked());
    data.putBoolean(EDITABLE_REFERENCE, editReferenceSw.isChecked());
    data.putBoolean(CALL_IN_APP_FECHO, fechoSw.isChecked());
    data.putString(BASE64REFERENCE, base64msg);
    data.putInt(REQUEST_KEY, activityRequestCode);
    launchIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
    launch.Intent.putExtra(DATA_MPOS, data);

    return launchIntent;
}

The example illustrates a method that in the end returns an Intent with the necessary information. The Intent is created first, then the setClassName method is used to configure the mPOS Package and the Activity that will be invoked, in this case MainActivity. The name of the Activity to be used in the “app to app” call is: pt.sibs.android.mpos.activities.MainActivity.

After configuring the Intent, an object of a custom type called MessageToSend is created.

This object is used to hold values for the “reference”, “amount” and “gratuityAmount” fields, which are required for the mPOS transaction.

After creating the object and filling in the values of both fields, the object is converted to json, using the Gson lib , and then encode the json string into Base64.

After filling the object, we can create the Bundle to be passed along with the Intent. The Bundle must contain the following elements:

  • A String with the Application ID of the app which is calling the mPOS;
  • Boolean values indicating whether the app requires a response from the mPOS; allows to edit the amount and reference; whether it will execute a Closure instead of a Purchase;
  • A String with the Base64-encoded JSON data;
  • An Integer value used in the StartActivity that will use the Intent created by this method.

When the Bundle has been created, the FLAG_ACTIVITY_SINGLE_TOP flag is configured in the Intent. This flag is a configuration setting for the intent that specifies how the Activity should behave when it’s started. The keys used in the Bundle will be described further down in this guide. The development and production packages will be made available to developers once the integration journey initiates.

Info

The development and production packages will be made available to developers once the integration journey initiates.

Step 2: Define the object class MessageToSend

In this object, the following fields must be populated:

  • amount: this field contains the operation amount and is represented in cents.
    Example: for a €10 purchase, the amount must be populated with ‘1000’. This field type is String;
  • reference: this field informs the reference associated to the operation. It is of the String type, 25- character length (maximum). May contain alphanumeric values.
  • gratuityAmount: this field contains the amount of the gratuity related to the operation and is represented in cents. Example: for a purchase with a gratuity of €1, the value gratuityAmount must be populated with ‘100’. This field is of the String type.

Here is a code sample of the Class Message to send:

class MessageToSend {
    @SerializedName("reference")
    private String reference;
    @SerializedName("ammount")
    private String ammount;

    void setReference(String reference) {
        this.reference = reference;
    }
    void setAmmount(String amount) {
        this.ammount = amount;
    }

   void setGratuityAmount(String gratuityAmount) {
        this.gratuityAmount = gratuityAmount;
    }
}
Step 3: Get a response from mPOS

After the execution of the operation, a response can be received from the mPOS, if the flag corresponding to the key “REQUEST_RESPONSE” marks the value true.

The following example illustrates how to read the response if it comes via on ActivityResult or on NewIntent:

@Override
protected void onNewIntent(Intent intent) {
    String status = "";
    String errorCode = "";
    String date = "";
    String reference = "";
    String amount = "";
    String mbwayDataJson = "";
    MBWayCallInAppData mbwayCallInAppData = new MBWayCallInAppData();

    // get response from mpos
    if(intent != null && intent.getExtras() != null) {

        if(intent.getExtras().containsKey(CALLIN ERROR KEY))
        errorCode = intent.getExtras().getString(CALLIN_ERROR_KEY);

        if(intent.getExtras().containsKey(CALLIN STATUS KEY))
        status = intent.getExtras().getString(CALLIN_STATUS_KEY);

        if(intent.getExtras().containsKey(CALLIN DATE KEY))
        date = intent.getExtras().getString(CALLIN_DATE_KEY);

        if(intent.getExtras().containsKey(CALLIN AMOUNT KEY))
        amount = intent.getExtras().getString(CALLIN_AMOUNT_KEY);

        if(intent.getExtras().containsKey(CALLIN REF))
        reference = intent.getExtras().getString(CALLIN_REF);

        Toast.makeText(getApplicationContext(), "STATUS2: "+status+"\nError: "+errorCode+"\nAmount: "+ amount + "\nDate: "+date+"\nReference: "+reference, Toast.LENGTH LONG).show());
    }
    super.onNewIntent(intent);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    if(requestCode == activityRequestCode) {
        String status = "";
        String errorCode = "";
        String date = "";
        String reference = "";
        String amount = "";
        String mbwayDataJson = "";
        String gratuity = "";
        MBWayCallInAppData mbwayCallInAppData = new MBWayCallInAppData();


        if(data != null && data.getExtras() != null) {
            if (data.getExtras().containsKey(CALLIN ERROR KEY))
            errorCode = data.getExtras().getString(CALLIN ERROR KEY);

            if (data.getExtras().containsKey(CALLIN_STATUS_KEY))
            status = data.getExtras().getString(CALLIN STATUS KEY);

            if (data.getExtras().containsKey(CALLIN_DATE_KEY))
            date = data.getExtras().getString(CALLIN DATE KEY);

            if (data.getExtras().containsKey(CALLIN_AMOUNT_KEY))
            amount = data.getExtras().getString(CALLIN DATE KEY);

            if (data.getExtras().containsKey(CALLIN_REF))
            reference = data.getExtras().getString(CALLIN REF);
                if(data.getExtras().containsKey(CALLIN_GRATUITY_KEY))
            gratuity = data.getExtras().getString(CALLIN_GRATUITY KEY);

            Toast.makeText(getApplicationContext(), "STATUS2: "+status+"\nError: "+errorcode+"\nAmount: "+ amount + "\nGratuity: "+ gratuity +"\nDate: "+date+"\nReference: "+reference, Toast.LENGTH LONG.show());
        }
    }
}

In either case, an Intent is received containing a Bundle filled by the mPOS with the response data.

After validating that the Intent exists and contains the Bundle, the values of each Key will be obtained, if present.

The response returns 6 values, detailed on the following tables:

ValueDescriptionString Type
errorCodeCorresponds to the error code (if any) obtained by the mPOS while performing the operationCALLIN_ERROR_KEY
statusInforms the status of the operation performed by the mPOS, which can be:
DeviceError
Success
Declined
CommError
Usercancelled
UserTimeOut
Missing Credentials
CALLIN_STATUS_KEY
dateInforms the date when the operation was performed by the mPOSCALLIN_DATE_KEY
amountCorresponds to the value used in the operation performed in mPOS, can be used to compare with the value sent in the bundle which invoked the mPOS appCALLIN_AMOUNT_KEY
referenceCorresponds to the reference used in the operation performed in the mPOS, can be used to compare with the value sent in the Bundle which invoked the mPOS appCALLIN_REF
gratuityAmountcorresponds to the amount of the gratuity in an operation performed by the SoftPOS. It can be used to compare with the amount sent in the Bundle that invoked the mPOS appCALLIN_GRATUITY_KEY
MB WAY client data*Corresponds to a json with the MB WAY information used in the operation performed in the mPOS, an can be used when converting to an object MbWayCallInAppData. CALLIN_MBWAY_CLIENT_DATA
MB WAY client data*

The json has the following structure:

{
    "fiscalIdentificationNumber": "123456789 ",
    "email": “email_de_teste@sibs.com”
}
NameShapeDescription
fiscalidentificationNumberstringTIN
emailstringClient’s email

Below you can find a table with the Used Keys and correspondent definition.

Used keysKey definition
DATA_MPOSCorresponds to the name of the Bundle used to call the mPOS app
PACKAGE_IDContains the application ID of the app which is calling the mPOS
BASE64REFERENCECorresponds to the value in base 64 of the json created from the object MessageToSend with the amount and reference values populated
REQUEST_RESPONSECorresponds to the flag which indicated whether the app that is invoking the mPOS requires a response
BYPASS_INSERT_VALUECorresponds to the flag which indicated whether the app that is invoking the mPOS allows the change of the amount
EDITABLE_REFERENCECorresponds to the flag which indicated whether the app that is invoking the mPOS allow the change of the reference
REQUEST_KEYCorresponds to the Int value used in the StartActivity that used the created intent
CALLIN_ERROR_KEYUsed in case of response corresponding to the error (if any) obtained by the mPOS while performing the operation
CALLIN_STATUS_KEYUsed in case of response and it informs the status of the operation performed by the mPOS (success, declined, etc.)
CALLIN_AMOUNT_KEYUsed in case of response and corresponds to the amount of the operation performed in the mPOS
CALLIN_GRATUITY_KEYUsed in case of response and corresponds to the amount of the gratuity in an operation performed in the mPOS. The value is of the String type.
CALLIN_DATE_KEYUsed in case of response and it informs the date when the operation was performed in the mPOS
CALLIN_REFUsed in case of response and it contains the reference used in the operation performed in the mPOS
CALL_IN_APP_FECHOCorresponds to the flag indicating whether the app will perform a closure (“fecho”, in Portuguese) instead of a purchase
API_TOKENUsed to export the authentication token of the payment app. This token is generated through the backoffice or payment app and contains the information of the User who generated it.
The token generation is done through the tab “Manage API Key”.
The token must be transmitted in JWT format (base64 with dot dividers, such as header.body.trailer) and is provided in the format expected by the payment application.
API_TOKEN_IDKey used to transport the authentication token ID. It is used to identify the token used by the partner application. The value is of the String type.
String token= "eyJhbGciOiJFQ0RILUVTIiwiZW5jIjoiQTEyOENCQy1IUzI1NiIsImVwayI6eyJrdHkiOiJFQyIsImNydiI6IlAtMjU2IiwieCI6IkdacEs5U0taUGxVTkpWR1JGMSswenlacVpXUGNNcUJSNmh1ODJTZVAxNGdcdTAwM2QiLCJ5IjoiQUszUjY3alpGYmQ1QTR6T013SnNLQVJ4WTY5MGo0bEJIQXdoWlZraHJrUEUiLCJleHQiOmZhbHNlfSwia2lkIjoidGVzdGVmaW5hbCJ9..122+VO2IJii+3oQhdQRgJw==.VGrKQuXL+VtCspmXVF1YXiREJvsSvivWUld+XPJjhbJWd4Fur5vVk7LQn7NK8W/+tC8P7f5mPkYTXAy374FJSA==.OFzZ03QZf/2btlJQwoAnhQ==";
String token_id ="token_test";
data.putString(API_TOKEN, token);
data.putString(API_TOKEN_ID, token_id);

Notification

The API Token is important when activating the service of Single Sign On. For this purpose, you will have to access the SIBS Payment Application Backoffice through a Web Browser.

The API key menu allows the configuration of Single Sign On (SSO) authentication intended to allow the User a secure login to the partner application (such as business app or invoicing apps) without the need to login to the payment application. 

On accessing this menu page, the User will be shown the list of API Keys that are currently active as per the following figure: 

To create a new API Key, the user should use the “Add API Key” button, available at the top of the page. Clicking on this button opens a window where the user must enter the following data to create the token: 

  • Key Name (optional) 
  • Password (mandatory) 

Since the “Key name” is an optional field, it does not need to be filled in. In these cases, a name will be automatically generated by the backend. This “key name” field is to help you identify the token in use.  

After entering the required data, a success message will be displayed for token creation and a file with the token and the token ID will be automatically downloaded. This file has a JSON with the following structure:

{
	"authToken": "eyJhbGciOiJFQ0RILUVTIiwiZW5jIjoiQTEyOENCQy1IUzI1NiIsImVwayI6eyJrdHkiOiJFQyIsImNydiI6IlAtMjU2IiwieCI6IkFJSFpXL3VGbXF6NlByTFp3eXNXRUgrSWh1ZUJDUWlFckFkd1lFY2NXZlRxIiwieSI6IlI2WGk3NEIxVkQ2aGR2TU0wOFkwc3MzdVVNR1ozZmJ2VWZHblpwMFRrbmdcdTAwM2QiLCJleHQiOmZhbHNlfSwia2lkIjoiN2VhMWUzY2ItZmJkMy00MGE2LTk0ODEtZjE5N2FmMDY1YzRmIn0=..yHo1ot7byeyDUn3YpDIbqQ==.7AexWSp5a129AE5NRytWzDQhxH5p7c9OG3c8CrsyCzx5ZGDDmnAHMqFLMKHdPdMJ.4P4YtpZkgglHEqGICH9QJw==",
	"tokenId": "7ea1e3cb-fbd3-40a6-9481-f197af065c4f"
}

There is a validation at the “Key Name” level. If the User tries to create a token with the name of an existing key, the following error message will be displayed: “A token with the specified if already exists, each token must have a unique name.” 

Notification

Please note that re-generating a token will not invalidate tokens that have been previously generated.

The key can be renewed on the “Re-generate” butting, that is, this button creates a new key for a given API Token. The next steps will be to simply enter the account password, which will trigger the automatic download of the file with the re-generated token. Since it is a token obtained with an ephemeral key, it will be different from the originally generated token.

The Delete button shall be used to revoke an existing token. This functionality will cause the selected token to be deleted, rendering it invalid. For security reasons a warning message is displayed before the User starts the token deletion process.

If the action is confirmed, the token deletion process will start, and the user sill only need to enter the password to complete the process. 

Once completed, the token will be deleted, hence becoming invalid for use in any application. The deleted token shall be removed from the list of active keys and cannot be re-generated. 

Notification

If the user logged in to the application does not have access to the token used, they will be redirected to logout. The user will then need to log in again manually through the application, using the credentials for which the token was generated.

Warning

If the user changes the password, it will be necessary to replace all the tokens generated with it. Session tokens will become inoperative, in case of a change in the User’s account.

Once the token is created, it can be used to authenticate the partner application, through the app to app call. As long as the token is valid, the User won’t be logged out of the payment apps and all the requests will be authenticated with the token.

iOS

This section describes the steps required to perform a “app to app” call on iOS applications. The technical development itself requires 3 steps:

Step 1: Configure the application
Step 2: Create the data model to transfer to mPOS
Step 3: Get a response from mPOS
Step 1: Configure the application

To receive responses from the mPOS, the client application must configure a URL Type in the project’s Info.plist. The name (scheme) must be defined in the URL Schemes field – this is the name by which the mPOS app will make the “app to app” call to obtain the answer with the result of the operation performed in the mPOS.

In the following example, the “app-to-app” scheme must be replaced by the client application scheme:

Step 2: Create the data model to transfer to mPOS

The call to the mPOS by an iOS app is made through a data model (in json format in base64) based on the following parameters:

{
    "reference" : “ABCDEFG”,
    "amount" : “3284”,
    "lockAmountValue" : 1,
    "performAutomaticClose" : 1,
    "urlScheme": @“callinapp://"
}

Below, we provide you with a table with the details of the date model briefly described:

FieldDescription
referenceInforms the reference associated to the operation. It is of the String type, 25-character length (maximum). May contain alphanumeric values.
amountContains the operation amount and is represented in cents. Example: for a €10 purchase, the value ‘amount’ must be populated with ‘1000’. This field is of the String type.
lockAmountValueBoolean field. If populated with ‘true’, then it is not possible to edit the amount sent to the mPOS and, as such, the mPOS starts directly on the payment method selection screen.
performAutomaticClose:Boolean field. If populated with ‘true’, then the mPOS app will open on the Closure screen and automatically start the closure operation without user intervention. If both this field and the field lockAmountValue are populated with ‘true’, then this operation will have priority over the purchase operation, which is ignored.
urlSchemeThis field indicates which scheme (of the client application) the mPOS app should call to send the result of the executed operation.

The following code sample represents a “app to app” call made to mPOS by an iOS app:

(void) openAppWithScheme:(NSString*)scheme {
    NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
    numberFormatter.numberStyle = NSNumberFormatterDecimalStyle;

    int amount = [numberFormatter numberFromString:@“32,84”].floatValue * 100;

    NSDictionary *paramsDic = @{@"reference" : @"ABCDEFG",
        @"amount" : [NSString stringWithFormat:@"%i", amount],
        @"lockAmountValue" : [NSNumber numberWithBool:YES],
        @"performAutomaticClose" : [NSNumber numberWithBool:YES],
        @"urlScheme": @"callinapp://"
    };

    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:paramsDic options:0error:nil];
    NSString *jsonParms = [jsonData base64EncodedStringWithOptions:0];

    NSString *url = [NSString stringWithFormat:@"%@://%@", scheme, jsonParms];

    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:url] 
options:@{ UIApplicationOpenURLOptionUniversalLinksOnly: @NO} completionHandler:^(BOOL success) {
        NSLog(@"URL: %@", url);
        NSLog(@"Success: %@", success ? @"YES": @"NO");
        }
    ];
}
Step 3: Get a response from mPOS

The mPOS application, upon receiving a “app to app” call processes the requested operation returning the response to the client application with the result (success or error) of the operation. This response is returned to the client application using the following data model defined in JSON in base 64

{
    @"callInError" : “”,
    @"callInStatus" : “APPR”,
    @"callInAmount" : “3284”,
    @"callInDate": “2020-05-04T11:42:38.001+01:00”,
    @"callInRef": “ABCDEFG”
    @"callInMBWayCustomerData": “{"fiscalIdentificationNumber": "123456789 ",  "email": “email_de_teste@sibs.com”}”
}

Here is a brief description with the meaning of the different fields:

FieldDescription
CallInError Value corresponds to the error code (if any) obtained by the mPOS while performing the operation. The value is of the String type.
CallInStatus Informs the status of the operation performed by the mPOS, which can be:
– DeviceError
– Success
– Declined
– CommError
– Usercancelled
– UserTimeOut
CallInAmountCorresponds to the value used in the operation performed in the mPOS, and can be used to compare with the value sent in the call to the mPOS app. The value is of the String type.
CallInDateValue informs the date when the operation was performed by the mPOS. The value is of the String type.
CallInRefCorresponds to the reference used in the operation performed in the mPOS, and can be used to compare with the value sent in the call to the mPOS app. The value is of the String type.
CallInMBWayCustomerData*Corresponds to a json with the MB WAY information used in the operation performed in the mPOS – TIN and email – that can be sent as a response to a payment with QR code
– Name
– Shape
– Description
– fiscalidentificationNumber
– String
– TIN
– email
– String
– Client’s email
CallInMBWayCustomerData *

The json has the following structure:

{
  "fiscalIdentificationNumber": "123456789 ",
  "email": “email_de_teste@sibs.com”
}

Below we provide you an example of how to process an mPOS response in the AppDelegate file of the iOS project:

- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:    (NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
    [self parsePaymentResponse:url];
    return YES;
}

-(void)parsePaymentResponse:(NSURL*_Nullable)url {
    if(!url)
    return;

    NSString *base64Encoded = [url.absoluteString stringByReplacingOccurrencesOfString:@"callinapp://" withString:@""];
    if(!base64Encoded)
    return;

    NSData *nsdataFromBase64String = [[NSData alloc] initWithBase64EncodedString:base64Encoded options:0];
    if(!nsdataFromBase64String)
    return;

    NSError *error;
    NSDictionary *dicParams = [NSJSONSerialization JSONObjectWithData:nsdataFromBase64String options:0 error:&error];
    if(!dicParams || error)
    return;

    NSLog(@"%@", dicParams);
    NSString *result = [NSString stringWithFormat:@"%@", dicParams];
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Resposta" message:result preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];
[self.window.rootViewController presentViewController:alert animated:YES completion:nil];

}